一、变量与常量
1.什么是变量?
其值在其作用域内可以改变的量称为变量。一个变量有一个名字并在内存中占据一定的存储空间。变量在使用前必须要定义,每个变量都有自己的地址。变量按定义的类型分有整型变量、字符型变量、浮点型变量、指针型变量等。变量的值可以发生改变,意味着它可以被覆盖、被写入、被赋值。每个变量必须要有一个名字和它所在内存空间绑定。
2.什么是常量?
其值不会发生改变的量称为常量,它们可以和数据类型结合起来分类,如整型常量、浮点型常量、字符常量等。常量是可以不通过定义和初始化,而直接引用的,常量又分为直接常量和符号常量,直接常量又叫做字面常量,如12,0,4.6,‘a’,“abcd”;符号常量,如宏定义的“#define PI 3.14”。
3.初始化和赋值的区别:
在定义变量的时候给变量赋值叫初始化;
如果变量定义之后,在另外的语句中给变量赋值,叫赋值。
4.数据类型的字节大小:sizeof运算符来计算!以后要和strlen区别,strlen是函数;
int在不同的编译系统里面可能是4个字节(32位机),可能是2个字节;
unsigned int 4字节;short int 2字节;unsigned short int 2字节;long int 4字节;unsigned long 4字 节;char 1字节;unsigned char 1字节。
数据类型的字节大小,C语言并没有规定,而是由各个编译系统所决定的!=》因为内存空间大小是由编译器在编译的时候决定的;
关于字节概念:一个字节占8位,每一个位只能够是0或者1;
对于char类型,一个字节占8位;
=》有符号和无符号的概念:
有符号的最高位是符号位,表示的是正负,0正1负!
无符号的最高位不是符号位,不表示正负,可以用来存储数据;
如果这样定义:char a;int b; long c;=》默认是有符号的;=》既可以用来存储整数,也可以用来存储负数;
如果这样定义:unsigned char a;unsigned int b;unsigned long c;=》明确规定是无符号的;=》只能够用来存储正数;
5.补码的概念:
正数的补码就是这个数的二进制形式;
负数的补码:先把负数的取绝对值,然后对绝对值的二进制进行按位取反,再加1;
数据在计算机中的保存都是以补码的形式进行保存的;
unsigned char a = -1;
printf("a = %d\n",a);的值是255的原因:
1.首先-1的补码是:取绝对值为1=》0000 0001=》1111 1110=》1111 1111=》-1是以补码1111 1111保存到计算机里面的;
2.给a定的数据类型是unsigned类型,所以最高位不是符号位(不表示正数或负数);是可以参与最后数值范围计算的;此时a空间存放的是1111 1111,然后打印出来的时候,因为a这块空间存储的类型是unsigned char,所以会默认是正数,按照正数的补码规则转化为源码!
6.sizeof的用法注意点:
sizeof变量; //对
sizeof(变量名); //对
sizeof(数据类型); //对
sizeof数据类型; //错
7.关键字:
①const:修饰变量,希望将这个变量变成“常量”!
用法:1.修饰普通变量;const无论是放在数据类型的前面或者是后面,都是将变量修饰为常量,不能够改变变量的值!
2.和指针变量结合起来使用:
记住一句话:如果想知道const是修饰谁的,从const开始往右看!看你是先遇到谁,如果先遇到*p,那就是*p,不能够 被改变!如果是先遇到p,那么p就不能够被改变!【近水楼台先得月】
②static:静态变量!
作用:1.修饰局部变量:延长局部变量的生命周期;
2.如果修饰全局变量、函数;具有“隐藏”的功能,保证函数和全局变量只能够在本文件中使用(.c),不能够在其他的文件中使用,也就是不能够在其他的.c文件中使用!
小结:
static 可以用来修饰局部变量、全局变量和函数;
static具有“隐藏的功能”!
③volatile:防止编译器优化处理!
volatile int temp = 10;
提醒编译器,volatile后面修饰的变量随时可能改变!要求编译器将编译后的程序,每次读取变量数据的时候,直接从变量的地址里面去读取!而不是从寄存器里面去读取!=》寄存器里面的数值和地址里面的数据不一样!【多线程,中断程序】
④register:有register修饰的变量,是寄存器变量!
告诉编译器,register修饰的变量会经常调用,请求编译器尽可能把register修饰的变量保存到寄存器上!而不是通过内存取地址来调用!=》提高效率!
注意点:
1.对变量的操作,因为可能不是保存到内存里面,所以就不能用&来对变量进行操作;
2.变量的类型能够被CPU所接受!register修饰的变量《=》int型的,但有些机器也可以是浮点型!
3.不能够修饰全局变量函数!可以修饰局部变量!
⑤extern:外部声明:
1.函数定义的时候,在前面加上extern表明这个函数是外部函数,可以在其他文件中调用!如果不加,默认为是外部函数,可以在其他的文件中调用!=》static相区别;
2.在调用的地方用extren进行外部声明,表明这个函数在别的文件中定义了!如果不用extern声明的话会有警告!【最好声明!】
8.define和typedef的区别:
共同点:都可以对数据类型进行重命名!【只要记住】
不同点:
①#define是在预处理阶段就处理的,typedef不是;【记住】
②#define dInt int*
typedef int* tInt
dInt a,b; //a:int* b:int define只是单纯的替换!
tInt a,b; //a:int* b:int*
③#define 可以自由组合,而typedef不可以;
#define dint int;
typedef int tint;
unsigned dint a;
unsigned tint b; X
④typedef可以组建新的数据类型的;
typedef struct node
{
}
9. 枚举类型:
#define MAX 10
什么叫枚举:一个一个地列举!
此类繁多,不胜枚举!
怎么用?
//封装一个枚举类型
enum demo //枚举类型的名字
{
//枚举的内容;
A, //以逗号区分!而结构体和共用体是以分号区分。
B,
C
};
利用枚举类型来定义枚举变量
enum demo Demo;
总结:
1.枚举类型中的元素都是整型常量,不是变量!
2.枚举类型里面的元素,一开始默认为0,并且依次加1;
3.我们可以规定枚举类型中的元素的大小:
enum test
{
A, //默认为0;
B = 3; //B明确规定为3;
C, //C比B大1,所以C是4
D //同理:D是5
};
宏定义和枚举的区别:
1.枚举是有类型的,宏定义没有类型;
2.枚举比宏的功能要少,只能表示整形常量,而宏定义还有参数的宏定义呢;
3.枚举是编译阶段进行处理,宏定义是在预处理阶段;
4.当需要有大量的宏定义的时候,可以用枚举来代替!
10.位运算:位与(&)、位或(|)、位抑或(^)、取反(~)
①&:只要有0的都是0,同时为1的才是1;
0&1 = 0;
1&1 = 1;
3&5 = 1;
3 = 0011;
5 = 0101;
& = 0001=》1 //按位与(&)与逻辑与(&&)要能够区分!
②|:有1的就是1,全为0的才是0;
0|0 = 0;
0|1 = 1;
1|1 = 1;
3|5 = 7;
③^:相同为0,不同为1
0^0 = 0;
0^1 = 1;
1^1 = 0;
④~:
~0 = 1;
~1 = 0; //位取反与逻辑非相区分!
⑤左移:<<
5 = 0000 0101;
5 << 2 = 0001 0100 = 20;
首先左移一位:0000 1010 = 10;
再左移一位:0001 0100 = 20;
左移n位:扩大了2的n次方倍;
⑥右移:>>
同理......
将特定位清零的话:&0;
将特定位置为1的话:|1;
将特定位取反的话:~;