数据类型由编译器创建,为了更好的管理内存。
常量和变量
常量
常量,就是不会变化的数据。
- 定义方法
- 方法一:普通定义
"hello"、-10、10、3.14444
- 方法二:定义宏
// #define 宏名 宏值 // 没有分号结束标记 #define PI 3.14
- 方法三:const 关键字定义
// 被 const 关键字修饰的变量,表示只读变量 const int a = 10;
- 方法一:普通定义
- 示例:求圆的周长和面积
#include #define PI 3.1415 int main(void) { //int r = 3; // 半径 const int r = 3; // 只读变量 float l = 2 * PI * r; // 周长 float s = PI * r * r; // 面积 printf("圆的周长为:%.2f\n", l); printf("圆的面积为:%.2f\n", s); return 0; }
变量
变量,就是会变化的数据。
- 定义语法 (一般方法)
// 变量三要素:类型名、变量名、变量值 // 类型名 变量名 = 变量值 int r = 3; // 变量值是一个常量 float s = PI * r * r; // 变量值是一个表达式
- 变量的定义
int a = 1;
- 变量定义会开辟内存空间,变量声明不会
-
变量想要使用必须有定义
当编译器编译程序时,在变量使用之前,必须要看到变量定义。如果没有看到变量定义,编译器会自动寻找一个变量声明提升为定义。
如果该变量声明前有 extern 关键字,无法提升。 -
定义变量时,不要重名
-
变量的声明
没有变量值的变量定义,叫做声明。
int a; extern int b; // 添加了关键字 extern
- 变量的定义
- 变量的存储
- 变量名、地址、变量值
- 示意图
- 变量名的本质
- 变量名的本质,是一段连续内存空间的别名
- 程序通过变量来申请和命名内存空间
- 通过变量名访问内存空间
- 不是向变量名读写数据,而是向变量所代表的内存空间中读写数据
- 变量的修改方式
- 直接修改
-
间接修改 (利用指针)
#define _CRT_SECURE_NO_WARNINGS #include #include #include void test01() { int a = 10; a = 20; // 直接修改 printf("%d\n", a); int* p = &a; *p = 30; // 间接修改 printf("%d\n", a); } int main(void) { test01(); system("pause"); return 0; }
标识符
标识符是变量和常量的统称。
- 命名规则
- 通常常量使用大写,变量使用小写,大小写严格区分
- 只能使用字母、数字、下划线 () 来命名标识符,且不能以数字开头,例如:a-z/A-Z/0-9/
- 禁止使用关键字或系统函数作为标识符名称
- 示例:变量声明
#include #define MAX 10 main() { int a; const int b = 10; a = MAX; //a = 123; //b = 3; // 常量的值不能修改 printf("%d %d\n", a, b); return 0; }
基本类型
整型
- 有符号整型 (signed)
signed,有符号,但是超级不常用,通常省略。
- short
- %hd,2字节
- int
- %d,4字节
- long
- %ld,通常4字节
最早期的类型,字节数区分平台。
- windows 32/64 位 -> 都是 4 字节
- Linux
- 32位 -> 4字节
- 64位 -> 8字节
- %ld,通常4字节
- long long
- %lld,8字节
- short
- 无符号整型 (unsigned)
unsigned,只表示数据量,没有方向 (正负),字节数和对应的 signed 类型相同。
- unsigned short
- %hu,2字节
- unsigned int
- %u,4字节
- unsigned long
- %lu,4字节
- unsigned long long
- %llu,8字节
- unsigned short
- 注意事项
- 小的数据类型赋值给大的数据类型不会出错,编译器会自动转化;大的数据类型赋值给小的数据类型,可能丢失高位
- 示例:打印整型变量
#define _CRT_SECURE_NO_WARNING #include #include int main(void) { int a = 3; short b = 4; long c = 5; long long d = 6; unsigned int aa = 33; //33u unsigned short bb = 44; //44u unsigned long cc = 55; //55lu unsigned long long dd = 66; //66llu printf("%d\n", a); printf("%hd\n", b); printf("%ld\n", c); printf("%lld\n", d); printf("%u\n", aa); printf("%hu\n", bb); printf("%lu\n", cc); printf("%llu\n", dd); system("pause"); return 0; }
字符型 char
char 存储一个字符,本质是 ASCII 码,格式匹配符是 %c。
- ASCII 码
- A – 65
-
a – 97
- 示例:大小写转换,差 32
#define _CRT_SECURE_NO_WARNING #include #include int main(void) { char ch = 'M'; printf("ch = %c\n", ch + 32); // A - 65, a - 97,大小写之间差 32 system("pause"); return 0; }
- 示例:大小写转换,差 32
- 0 – 48
- 字符 0
- \n – 10
- 换行符
- \0 – 0
- 数值 0
- 转义字符 ()
- 将普通字符转为特殊意,反之亦然
实型 (浮点型)
- float
- 单精度浮点型,保留 6 位小数
- %f,4字节
- double
- 双精度浮点型 (默认)
- %lf,8字节
- 示例:实型 (浮点型) 格式化输出
#define _CRT_SECURE_NO_WARNING #include #include int main(void) { float a = 3.14f; // double b = 3.14; // // 直接输出 printf("a = %f\n", a); // 自动保留6位小数 printf("b = %lf\n", b); // 控制小数位 printf("----------------------\n"); printf("a = %5.2f\n", a); // 总共5位,不够用空格补,保留2位小数 printf("b = %08.2lf\n", b); // 共8位,不够用0补齐,保留2位小数 // 科学计数法输出 a = 3.2e3f; // 表示 3.2 * 10^3 -- e 可以写成 E b = 3.2e-3f; // 表示 3.2 * 10^(-3) printf("----------------------\n"); printf("a = %f\n", a); printf("b = %lf\n", b); system("pause"); return 0; }
类型转换
- atof/atoi 函数
- 函数描述
- 把参数 str 所指向的字符串转换为一个浮点数/整数
- 函数原型
#include double atof(const char *str) int atoi(const char *str) long int atol(const char *str)
- 函数描述
- strtod/strtol 函数
- 函数描述
- 把参数 str 所指向的字符串转换为一个浮点数/长整型
- 函数原型
#include double strtod(const char *str, char **endptr) long int strtol(const char *nptr, char **endptr, int base);
- 参数
- nptr
- 要转换的字符串,必须得能够转换成对应的整型才行
- endptr
- 通常指定为 NULL,只有测试时才会使用,如果转换错误,会传出错误的字符串地址
- base
- 指定进制,可以是 8、10、16
- nptr
- 参数
- 示例
char *p = "123abc"; char *pt = NULL; strtol(p, &pt, 10); // 表示将 123abc 转换为10进制的整型 // pt 打印结果为 abc
- 函数描述
sizeof 操作符
格式匹配符是 %zd。
作用
- 用来求变量或类型的大小,单位为字节
- sizeof 的本质不是函数,而是操作符,所以不包含任何头文件
语法
sizeof(变量)
sizeof(类型)
sizeof 变量 // 可以不加小括号 ()
- 示例 1
#define _CRT_SECURE_NO_WARNING #include #include int main(void) { int a = 3; short b = 4; long c = 5; long long d = 6; size_t e = sizeof(d); printf("int %zd\n", sizeof(int)); printf("short %zd\n", sizeof(short)); printf("long %zd\n", sizeof(long)); printf("long long %zd\n", sizeof(long long)); printf("int %zd\n", sizeof(a)); printf("short %zd\n", sizeof(b)); printf("long %zd\n", sizeof(c)); printf("long long %zd\n", sizeof(d)); printf("long long %zu\n", e); system("pause"); return 0; }
- 示例 2
“`c
define _CRT_SECURE_NO_WARNINGS
include
// 1.sizeof 基本用法
void test01()
{
int a = 10;
printf(“len = %u, %u, %u\n”, sizeof(a), sizeof(int), sizeof a); // 4, 4, 4
}// 2.sizeof 返回值类型
void test02()
{
unsigned int a = 10;
printf(“10 – 11 = %u\n”, a – 11); // 4294967295
printf(“10 – 11 = %d\n”, a – 11); // -1
if (a – 11 111000
-
二进制转十进制
- 2^10 以下要记下来
- 2^10 以下要记下来
八进制
八进制数字,以0开头,每位小于8。
- 八进制转二进制
- 按 421 码将每个八进制位展开
- 示例:056 和 05326 转二进制
- 八进制转十进制
- 示例:056 -> 46
- 示例:056 -> 46
- 二进制转八进制
- 421 码,3 个一组,从右往前,高位不足补 0
- 示例:1 010 111 010 110 -> 012726
十六进制
十六进制数字,以 0x 开头,每位取 0-9/A-F/a-f。
- 语法
- 十六进制和十进制数字对照
- 十六进制和十进制数字对照
- 十六进制转十进制
- 示例:0x1A -> 26,0x13F -> 319
- 示例:0x1A -> 26,0x13F -> 319
- 十六进制转二进制
- 示例:0x1A 和 0x13F 转为二进制
- 示例:0x1A 和 0x13F 转为二进制
- 二进制转十六进制
- 8421 码
- 示例:0001 0011 1111 转为十六进制
赋值
- 格式匹配符
- 十进制显示:%d
- 八进制显示:%o
- 十六进制显示:%x
- 注意事项
- 不能直接赋值二进制
- 示例:进制转换
#define _CRT_SECURE_NO_WARNING #include #include int main(void) { int a = 0x2c; // 不能直接赋值二进制数 printf("a 的16进制数为:%x\n", a); printf("a 的10进制数为:%d\n", a); printf("a 的8进制数为:%o\n", a); system("pause"); return 0; }
计算机内存数值存储方式 (原码、反码和补码)
存储知识
- 1 bit
- 就是一个二进制位
- 1 个字节 1B = 8 bit
- 1KB = 1024B
- 1MB = 1024KB
- 1GB = 1024MB
- 1TB = 1024GB
原码 (已淘汰)
不便于加减运算。
- 43 -> 00 101011
- 正数以0开头,不足8位的补0
- -43 -> 10 101011
- 负数以1开头,不足8位补0
反码 (已淘汰)
- 43 -> 00 101011
- 正数与原码相同:00 101011
- -43 -> 10 101011
- 负数是符号位不变,其他位原码取反:11 010100
补码 (现今计算机采用的存储形式)
- 人为规定
- 000 0000 -> 0
- 1000 0000 -> -128
- 43 -> 00 101011
- 正数与原码相同:00 101011
- -43 -> 10 101011
- 负数是符号位不变,其他位原码取反 + 1:11 010101
- 43 – 27 = 43 + (-27)
- 43 的补码
- 00 101011
- -27
- 原码
- 100 11011
- 反码
- 111 00100
- 补码
- 111 00101
- 原码
- 43 – 27 = 00 101011 + 111 00101 = 10000 10000
- 超出8位的丢弃 -> 000 10000 -> 16
- 43 的补码
原码、反码和补码总结
- 对于正数
- 原码、反码、补码相同
- 对于负数
- 补码 = 反码 + 1
- 补码的符号位不动,其他位求反,最后整个数加1,得到原码
数值范围
- char 类型
- 1 字节,8 个 bit,相当于数值位有 7 个
- 有符号 char
- -2^(8-1) ~ 2^(8-1)-1
- 最后 -1 是因为有一个 0 值
- -128 ~ 127
- -2^(8-1) ~ 2^(8-1)-1
- 无符号 char
- 0 ~ 2^8-1
- 0 ~ 255
- 0 ~ 2^8-1
- int 类型
- 有符号
- -2^(48-1) ~ 2^(48-1)-1
- -2147483648 ~ 2147483647
- -2^(48-1) ~ 2^(48-1)-1
- 无符号
- 0 ~ 2^(4*8)-1
- 0 ~ 4294967295
- 0 ~ 2^(4*8)-1
- 有符号
- long 类型
- 同 int
- long long 类型
- 有符号
- -2^(88-1) ~ 2^(88-1)-1
- 无符号
- 0 ~ 2^(8*8)-1
- 有符号
类型限定符
extern
美 /ˈekstɜːrn/
- 表示声明,没有内存空间,不能提升
const
- 限定变量为只读变量
volatile
- 防止编译器优化代码
register
- 定义一个寄存器变量 (寄存器变量没有地址,变量地址在内存中),提高效率
- register 是建议型的指令,而不是命令型的指令,如果 CPU 有空闲寄存器,那么 register 就生效,如果没有空闲寄存器,就无效
字符串的格式化输入和输出
字符串常量
- 字符串一定有一个结束标记 ‘\0’
- 字符串使用双引号引起来
- 字符串常量和字符常量的不同
- ‘a’ 不等价 “a”:一个是字符,一个是字符串
格式匹配符
- %%
- 用来转义 %,\ 转义无效
- %Ns
- 显示 N 个字符的字符串,不足 N 用空格向左填充
%015.2f //左侧填充0
- 显示 N 个字符的字符串,不足 N 用空格向左填充
- %-Ns
- 显示 N 个字符的字符串,不足 N 用空格向右填充
%-015.2f // 向右填充0
- 显示 N 个字符的字符串,不足 N 用空格向右填充
格式化输出
- printf 函数
- 从字符串第一个字符开始打印,直到 ‘\0’ 结束
- putchar 函数
输出单个字符到屏幕 (也可以直接使用 ASCII 码)。
常用putchar('\n');
来打印换行。- 函数描述
- 输出单个字符
- 不能输出字符串 (‘abc’ 既不是有效字符,也不是有效字符串)
- 示例
putchar(97); putchar('\n');
- 函数描述
格式化输入
- scanf()
- 函数描述
- 从键盘接收用户输入。
- 接收字符串
- 变量名要取地址传递给 scanf,数组名本身包含地址,不用取地址
- 申请了 10 个字节,超出的部分不受保护,但是不出错
- 注意事项
- scanf 具有安全隐患,如果存储空间不足,数据能存储到内存中,但是不受保护
- scanf 函数在接收字符串时,碰到空格和换行终止,所以不能使用 scanf 接收带有空格的字符串
- 示例
// 接收整数 %d int a, b, c; scanf("%d %d %d", &a, &b, &c); // &:取出变量的地址 // 接收字符 %c int a, b, c; scanf("%c %c %c", &a, &b, &c); // 接收字符串 %s char str[10]; scanf("%s", str);
- 函数描述
- getchar()
- 函数描述
- 从键盘获取用户输入的一个字符,返回该字符的 ASCII 码。
- 示例
#define _CRT_SECURE_NO_WARNINGS #include // 接收字符 void test01() { char c1 = getchar(); printf("%c\n", c1); } int main() { test01(); return 0; }
- 函数描述
运行时报错:scanf 不安全
- 解决方法
- 在源文件第一行添加:#define _CRT_SECURE_NO_WARNINGS
- 设置VS:VS 项目-属性-C/C++-预处理器-预处理器定义-编辑,添加 _CRT_SECURE_NO_WARNINGS