常量与变量
关键字
C语言的关键字共有32个
数据类型关键字(12)
- char
- short
- int
- long
- float
- double
- unsigned
- signed
- struct
- union
- enum
- void
控制语句关键字(12)
- if
- else
- switch
- case
- default
- for
- do
- while
- break
- continue
- go
- return
存储类关键字(5)
- auto
- extern
- register
- static
- const
其他关键字(3)
- sizeof
- typedef
- volatile
数据类型
数据类型的作用:编译器预算对象(变量)分配的内存空间
数据类型分为三种:
- 基本类型
- 整型
- int
- short
- long
- 字符型
- char
- 浮点型
- float
- double
- 整型
- 构造类型
- 数组类型
- 结构类型(struct)
- 联合类型(union)
- 枚举类型(enum)
- 指针类型
- char *
- int *
- int **
常量
- 常量是在程序运行过程中,其值不被改变的量
- 常量一般出现在表达式或者赋值语句中
- 常量在代码中使用const 来修饰
- 也可以 使用define 来声明一个宏
# include <stdio.h>
# include <stdlib.h>
#define MAX = 100
int main(){
const int a = 10;
//MAX =99; error 不可以修改
// a = 12; error 不可以修改
return 0;
}
变量
变量在使用前必须要定义,定义变量前必须有相应的数据类型 变量的声明和定义是有区别的
- 声明一个变量不要建立存储空间 使用extern 修饰 如 extern int a;
- 定义一个变量是需要建立存储空间,int b
# include <stdio.h>
# include <stdlib.h>
int main(){
extern int a = 10; // error
return 0;
}
一般来说,定义中包含着声明,对于int b 来说 它既是声明,同时也是定义
而对于extern int b 来说,它只是声明并没有定义
整型
整型的输出
| 打印格式 | 含义 |
|---|---|
| %d | 输出一个有符号的10进制的int类型 |
| %o | 输出8进制的int类型 |
| %x | 输出16进制的int类型,字母以小写输出 |
| %X | 输出16进制的int类型,字母以大写输出 |
| %u | 输出一个10进制的无符号数 |
正数示例
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = 10;
printf("有符号十进制 %d\n", a);
printf("8进制 %o\n", a);
printf("16进制小写 %x\n", a);
printf("16进制大写 %X\n", a);
printf("无符号十进制 %u\n", a);
return 0;
}
输出内容
有符号十进制 10
8进制 12
16进制小写 a
16进制大写 A
无符号十进制 10
负数示例
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = -10;
printf("有符号十进制 %d\n", a);
printf("8进制 %o\n", a);
printf("16进制小写 %x\n", a);
printf("16进制大写 %X\n", a);
printf("无符号十进制 %u\n", a);
return 0;
}
输出内容
有符号十进制 -10
8进制 37777777766
16进制小写 fffffff6
16进制大写 FFFFFFF6
无符号十进制 4294967286
仅仅是在整数前面添加了一个符号,输出的值差别很大,这是因为在计算机中存储的是补码,后面补码部分会分析这个示例
整型变量的赋值
整型变量的定义 都是 int a ,在赋值的时候可以以不同进制的形式来赋值
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = 123; // 十进制
int b = 0123; // 8进制
int c = 0x123; // 16进制
printf("有符号十进制 a = %d\n", a);
printf("有符号十进制 b = %d\n", b);
printf("有符号十进制 c = %d\n", c);
printf("8进制 a = %o\n", a);
printf("8进制 b = %o\n", b);
printf("8进制 c = %o\n", c);
printf("16进制小写 a = %x\n", a);
printf("16进制小写 b = %x\n", b);
printf("16进制小写 c = %x\n", c);
printf("16进制大写 a = %X\n", a);
printf("16进制大写 b = %X\n", b);
printf("16进制大写 c = %X\n", c);
return 0;
}
输出内容
有符号十进制 a = 123
有符号十进制 b = 83
有符号十进制 c = 291
8进制 a = 173
8进制 b = 123
8进制 c = 443
16进制小写 a = 7b
16进制小写 b = 53
16进制小写 c = 123
16进制大写 a = 7B
16进制大写 b = 53
16进制大写 c = 123
整型变量的输入
变量的输入通过库函数scanf来完成,这个函数第一个参数是输入的格式,第二参数是变量的地址
# include <stdio.h>
# include <stdlib.h>
int main(){
int a;
printf("请输入变量a的值:");
scanf("%d",&a);
printf("a = %d\n",a);
return 0;
}
打印结果:
a = 1
注意:scanf("%d",&a) 这个%d后面不能添加换行符号\n,否则就会报错
还可以通过其他格式的输入
# include <stdio.h>
# include <stdlib.h>
int main(){
int a;
printf("请输入变量a的值:");
scanf("%o",&a); /// 以8进制的方式输入
printf("a = %d\n",a); /// 以16进制的方式输出
return 0;
}
输出结果
请输入变量a的值:12
a = 10
其他整数类型
| 数据类型 | 占用空间 |
|---|---|
| short(短整型) | 2字节 |
| int(整型) | 4字节 |
| long(长整型) | window为4字节,linux 4字节(32位),8字节(64位) |
| long long(长长整型) | 8字节 |
- 整型在内存中所占的字节数与所选择的操作系统有关,虽然C语言标准中没有明确规定整型数据的长度,但是long类型的长度不能小于int类型,short类型的长度不能大于int类型
- 当一个小的数据类型赋值给一个大的数据类型的时候,不会出错,因为编译器会自动转化,但是当一个大的数据类型赋值给一个小的数据类型的时候,就有可能会丢失高位
整型常量的表示
| 整型常量 | 代表类型 |
|---|---|
| 10 | int 类型 |
| 10l,10L | long 类型 |
| 10ll,10LL | long long 类型 |
| 10u,10U | unsigned int类型 |
| 10ul,10UL | unsigned long类型 |
| 10ull,10ULL | unsigned long long 类型 |
补充打印格式
| 打印格式 | 含义 |
|---|---|
| %hd | 输出short类型 |
| %ld | 输出long类型 |
| %lld | 输出longlong类型 |
| %hu | 输出无符号short类型 |
| %lu | 输出无符号long类型 |
| %llu | 输出无符号longlong类型 |
数值存储方式
原码
- 原码是一个数的二进制码
- 最高位作为符号位,0 表示正 1 表示为负
- 其他数值部分就是绝对值的二进制数
- 负数的原码是在其绝对值的基础上,最高位变为1
| 十进制 | 原码 |
|---|---|
| +15 | 0000 1111 |
| -15 | 1000 1111 |
| +0 | 0000 0000 |
| -0 | 1000 0000 |
原码表示法简单易懂,与带符号数转换方便,但是当两个正数相减或者不同符号数相加的时候,需要确定哪个数的绝对值大,才能确定结果的正负,所以原码不便于加减运算
反码
- 对于正数,反码与原码相同
- 对于负数 符号位不变,其他位置取反(0 变 1 ,1 变 0)
| 十进制 | 反码 |
|---|---|
| +15 | 0000 1111 |
| -15 | 1111 0000 |
| +0 | 0000 0000 |
| -0 | 1111 1111 |
反码运算也不方便通常用来作为补码的过渡
补码
在计算机系统中,数值一律使用补码来存储
- 对于正数,原码,反码,补码相同
- 对于负数,补码为它的反码+1
- 如果想要得到原码,补码符号位不变,其他位取反,最后整个数+1,就得到原码(这个方式是得到负数的原码)
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = -15;
printf("a = %X\n",a);
return 0;
}
分析: a 是int类型 占四个字节 因此原码应该是 8000000F,转成反码,符号位不变 其他按位取反应该是FFFFFFF0,补码是反码+1 应该是 FFFFFFF1 打印结果:
a = FFFFFFF1
分析结果: 计算机中存储都是补码,使用原码只是人为看着方便,补码转原码是符号位不变,其他按位取反之后再+1 ,因为 FFFFFFF1---->8000000E+1 ----->8000000F ---->-15
补码运算
-7+-5
分析: -7 的源码4个字节的十六进制表示 80000007,它的反码是FFFFFFF8,它在计算机中的存储的补码是FFFFFFF9
-5 的源码是80000005,它的反码是FFFFFFFC,在计算机中的存储的补码是FFFFFFFD
两数相加相当于在补码相加
11111111 11111111 11111111 11111001
+11111111 11111111 11111111 11111011
------------------------------------------
11111111 11111111 11111111 11110100 === FFFFFFF4
FFFFFFF4 ==取反===> 8000000B==+1===> 8000000C = -12
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = -7;
int b = -5;
printf("a = %X\n",a);
printf("b = %X\n",b);
printf("a+b = %X\n",a+b);
return 0;
}
打印结果
a = FFFFFFF9
b = FFFFFFFB
a+b = FFFFFFF4
-7+5
分析: -7 的源码4个字节的十六进制表示 80000007,它的反码是FFFFFFF8,它在计算机中的存储的补码是FFFFFFF9
5 的源码是00000005,它的反码是00000005,在计算机中的存储的补码是00000005
两数相加相当于在补码相加
11111111 11111111 11111111 11111001
+00000000 00000000 00000000 00000101
------------------------------------------
11111111 11111111 11111111 11111110 ==FFFFFFFE
FFFFFFFE ==取反===> 80000001==+1===> 80000002 = -2
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = -7;
int b = 5;
printf("a = %X\n",a);
printf("b = %X\n",b);
printf("a+b = %X\n",a+b);
return 0;
}
打印结果
a = FFFFFFF9
b = 5
a+b = FFFFFFFE
-7+9
分析: -7 的源码4个字节的十六进制表示 80000007,它的反码是FFFFFFF8,它在计算机中的存储的补码是FFFFFFF9
9 的源码是00000009,它的反码是00000009,在计算机中的存储的补码是00000009
两数相加相当于在补码相加
11111111 11111111 11111111 11111001
+00000000 00000000 00000000 00001001
------------------------------------------
00000000 00000000 00000000 00000010 ==00000002
00000002 =====>2
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = -7;
int b = 9;
printf("a = %X\n",a);
printf("b = %X\n",b);
printf("a+b = %X\n",a+b);
return 0;
}
打印结果
a = FFFFFFF9
b = 9
a+b = 2
-7+7
分析: -7 的源码4个字节的十六进制表示 80000007,它的反码是FFFFFFF8,它在计算机中的存储的补码是FFFFFFF9
9 的源码是00000007,它的反码是00000007,在计算机中的存储的补码是00000007
两数相加相当于在补码相加
11111111 11111111 11111111 11111001
+00000000 00000000 00000000 00000111
------------------------------------------
00000000 00000000 00000000 00000000 ==00000000
00000000 =====>0
# include <stdio.h>
# include <stdlib.h>
int main(){
int a = -7;
int b = 7;
printf("a = %X\n",a);
printf("b = %X\n",b);
printf("a+b = %X\n",a+b);
return 0;
}
打印结果
a = FFFFFFF9
b = 7
a+b = 0
在计算机系统中,数值一律用补码来存储,主要的原因
- 统一了0的编码
- 将符号位和其他位统一处理
- 将减法运算转变为加法运算
- 用两个补码表示的数相加时,如果最高位有近卫,进位被舍弃掉
有符号数和无符号数
- 有符号数的最高位为符号位,0 表示整数 1 表示负数
- 无符号数的最高位不是符号位,而是数的一部分 无符号数不可能为负值
| 数据类型 | 占用空间 | 取值范围 |
|---|---|---|
| short | 2字节 | -215~215-1 |
| int | 4字节 | -231~231-1 |
| long | 8字节 | -263~263-1 |
| unsigned short | 2字节 | 0~ 216-1 |
| unsigned int | 4字节 | 0~ ~232-1 |
| unsigned long | 8字节 | 0~ ~264-1 |
sizeof关键字
- sizeof 不是函数,所以不需要包含任何头文件,它的功能是计算一个数据类型的大小,单位是字节
- sizeof的返回值类型是size_t
- size_t类型在32操作系统下是unsigned int 是一个无符号的整数,在64系统中是unsigned long
# include <stdio.h>
# include <stdlib.h>
int main(){
short a = 10;
int b = 10;
long c = 10;
unsigned short d = 10;
unsigned int e = 0;
unsigned long f = 0;
printf("sizeof(short) = %lu\n",sizeof(a));
printf("sizeof(int) = %lu\n",sizeof(b));
printf("sizeof(long) = %lu\n",sizeof(c));
printf("sizeof(unsigned shot) = %lu\n",sizeof(d));
printf("sizeof(unsigned int) = %lu\n",sizeof(e));
printf("sizeof(unsigned long) = %lu\n",sizeof(f));
return 0;
}
输出结果:
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 8
sizeof(unsigned shot) = 2
sizeof(unsigned int) = 4
sizeof(unsigned long) = 8
char类型
char类型的定义和输出
char类型的变量用于存储一个单一的字符,每个字符占用一个字节,在给char类型的字符赋值时,使用单引号
字符变量实际上并不是把该字符本身放到变量的内存单元中去.而是将该字符对应的ASCII编码放到变量的存储单元中,char的本质就是一个字节的整型
#include <stdio.h>
int main()
{
char ch = 'a';
printf("sizeof(ch) = %lu\n", sizeof(ch)); //1
printf("ch[%%c] = %c\n", ch); //打印字符 ch[%c] = a
printf("ch[%%d] = %d\n", ch); //打印‘a’ ASCII的值 ch[%d] = 97
char A = 'A';
char a = 'a';
printf("a = %d\n", a); //97
printf("A = %d\n", A); //65
printf("A = %c\n", 'a' - 32); //小写a转大写A
printf("a = %c\n", 'A' + 32); //大写A转小写a
ch = ' ';
printf("空字符:%d\n", ch); //空字符ASCII的值为32
printf("A = %c\n", 'a' - ' '); //小写a转大写A
printf("a = %c\n", 'A' + ' '); //大写A转小写a
return 0;
// }
char类型的输入
#include<stdio.h>
int main()
{
char ch;
printf("请输入ch的值");
scanf("%c",&ch); // 输入不要带回车\n
printf("ch = %c\n", ch);
return 0;
}
转义字符
| 转义字符 | 含义 |
|---|---|
| \a | 警报 |
| \b | 退格,将当前位置移到前一列 |
| \f | 换页,将当前位置移动到下一页开头 |
| \n | 换行,将当前位置移动到下一行开头 |
| \r | 回车,将当前位置移动到本行开头 |
| \t | 水平制表,跳到下一个table位置 |
| \v | 垂直制表 |
| \ | 代表一个反斜杠字符“\” |
| ' | 代表一个单引号 |
| \“ | 代表一个双引号 |
| ? | 代表一个问号 |
| \0 | 代表数字0 |
| \ddd | 8进制转义字符,d范围0~7 |
| \xhh | 16进制转义字符,h范围0 |
#include<stdio.h>
int main(int argc, char const *argv[])
{
printf("abc");
printf("\rfg\n"); // /r是回到了行首,fg覆盖掉了ab 整体打印的效果是 fgc
printf("abc");
printf("\befg\n"); // /b 是向前退了一格,efg覆盖了c 整体的打印效果是abefg
printf("%d\n",'\123'); // 123 转换成10进制是83
printf("%d\n",'\x80'); // 80是二进制保存的 char 只存储一个字节 80是 10000000 这个是补码 值为-128
return 0;
}
浮点型
浮点型白娘是用来存储小数数值的,分为两种
- 单精度浮点数 float 内存中占4个字节
- 双精度浮点数 double 内存中占8个字节
由于浮点型变量是由有限的存储单元组成,因此只能提供有限的有效数字,在有效位以外的数字将会被舍去,这样可能会产生一些误差
- 以f结尾的常量是float类型(例如3.14f) ,其他类型的都是double类型的(例如3.14)
#include <stdio.h>
int main(int argc, char const *argv[])
{
// 传统方式赋值
float a = 3.14f;
double b = 3.14;
printf("a = %f\n",a); //打印float 使用%f a = 3.140000
printf("b = %lf\n",b); //打印double 使用%lf b = 3.140000
// 科学法赋值
a = 3.2e3f; //// 3.2*1000 = 3200; e可以写作E
printf("a = %f\n",a); // a = 3200.000000
a = 3.2e-3f; //// 3.2*0.0.001 = 0.0032;
printf("a = %f\n",a); // a = 0.003200
a = 3.141592657f;
printf("a = %f\n",a); //a = 3.141593
b = 3.141592657;
printf("b = %lf\n",b); //a = 3.141593
return 0;
}
- 打印时,默认输出6位小数点
- float类型能够保证的精度是7位有效数字
- double 类型能够保证的精度是15位有效数字
#include <stdio.h>
int main(int argc, char const *argv[])
{
float a = 3.1415926456;
double b = 3.1415926456;
printf("a=%.8f\n",a); //a=3.14159274
printf("b=%.8lf\n", b); //b=3.14159265
return 0;
}
类型限定符
| 限定符 | 含义 |
|---|---|
| extern | 声明一个变量,并不会创建存储空间 |
| const | 定义一个常量,其值不能被修改 |
| volatile | 防止编译器优化代码 |
| register | 定义寄存器变量,提高效率,这是一个建议型的指令,如果CPU有空闲寄存器,这个指令就会生效,如果没有就不会生效 |
字符串
- 字符串是内存中一段连续的char空间,以‘\0’(数字0)结尾
- 字符串常量是由双引号扩起来的字符串序列
字符常量与字符串常量的不同
- ‘a’ 表示的是字符常量,在内存中存储的是‘a’
- "a" 表示的是字符串常量,在内存中存储的是‘a’'\0'
- 每个字符串结尾,编译器都会自动添加一个结束标志位‘\0’
字符串/字符的输出
printf
printf是输出一个字符串,格式字符总结:
| 打印格式 | 对应的数据类型 | 含义 |
|---|---|---|
| %d | int | 接受整数数值并将表示为有符号的十进制整数 |
| %hd | short int | 短整数 |
| %hu | unsigned short | 无符号短整数 |
| %o | unsigned int | 无符号8进制 |
| %u | unsigned int | 无符号10进制 |
| %x,%X | unsigned int | 无符号16进制 |
| %f | float | 单精度浮点数 |
| %lf | double | 双精度浮点数 |
| %e,%E | double | 科学计数法表示的数 |
| %c | char | 字符 |
| %s | char* | 字符串 |
| %% | % | 输出一个百分号 |
字母l 加在d,u,x,o 前面 表示长整数
- 表示左对齐 m 表示数据的最小宽度 0 表示输出的前面补上0,直到占满制定列宽为止,不可以搭配使用- m.n m 表示域宽,对应的输出项在输出设备上所占的字符数,n 指的是精度,用于说明输出的浮点数的小数位,对于数值型来说 如果未指定n时,隐含的精度为n = 6
#include <stdio.h>
int main(int argc, char const *argv[])
{
int a = 100;
printf("a = %d\n", a); //格式化输出一个字符串
printf("%p\n",&a); //输出a在内存中的地址编号
printf("%%d\n"); //输出%d
int b = 10;
printf("b=%6d\n",b);//最小宽度是6 前面补了4个空格 b= 10
printf("b和a=%-6d%d\n",b,a);//左对齐,最小宽度是6 因为在后面补了4个0 :b和a=10 100
printf("b=%06d\n",b);//b=000010 前面补0
printf("b和a=%-06d%d\n",b,a);//左对齐如果后面补0的话改变了原来的含义,因此还是补的还是空格:b和a=10 100
double d = 12.3;
printf("d=%-10.3lf哈哈\n",d);//左对齐精度补0 剩余补空格d=12.300 哈哈
printf("d=%e\n",d);//d=1.230000e+01
return 0;
}
putchar
putchar 是输出一个字符
putchar(65); /// 输出A