常量和宏/指针/结构体
Define 定义常量和宏
define 是一个预处理指令
- define 定义标识符常量
#define MAX 1000
- define 定义宏
#define ADD(X,Y) X+Y
int main()
{
printf("%d\n",ADD(2, 3));
return 0;
}
这个结果是5
但是如果我的程序是这样的话:
#define ADD(X,Y) X+Y
int main()
{
printf("%d\n", 4*ADD(2, 3));
return 0;
}
结果并不是20,而是11,WHY?
原因在于4*ADD(2,3),ADD(2,3)被完整地替换成了2+3。
也就是4 * 2+3,相当于并不是先算了ADD,再相乘,而是完整的替换成了2+3。
这就说明一个概念就是宏,它是完整替换的。
如果我想得到20的话,就要这样定义:
#define ADD(X,Y) ((X)+(Y))
指针
这是一个有难度的概念。
要谈指针就必须要讲明白内存。
内存
计算机所有的程序的运行就在内存上运行,内存被划分为不同的内存单元,每个内存单元的大小是1个字节。为了有效访问内存单元,就给内存单元编了号,这些编号被称为该内存单元的地址。
这个时候需要回答两个问题:
- 内存是怎么编号的?
- 一个这样的内存单元是多大的空间?
内存怎么编号?我们有的机器是32位的,有的是64位的。32位指的是32根地址线,它是物理线,通电了之后,产生了1,0这样的信号。如果一条线上通电了,那么就表示1,不通电就是0.所以一个32位地址线产生了从0000000…到11111…的可能。这个可能性是232 个。也就是说我可以管理2的32次方个内存单元,一个内存单元是1 bit。
换句简单的话说,多少个位的机器就用2的那么多位次方。再把这个数字转换成十进制。再用这个十进制的数字除以8得到byte,再除以1024得到KB,再除以1024得到MB。。。所以32位的机器可以管理0.5G左右的内存。
一个内存单元多大?一个内存单元是一个字节。
不是很懂,但是总结下来就是,一个内存就是8个bit,也就是一个字节。
比方说我现在要存储一个int
int a = 0;
之前说了,一个int是4个字节,那也就是说,我要用四个内存单元去储存这个a。
那我如果要取a的地址怎么办?当a占有的内存是四个字节,也就是说四个内存单元的时候,取地址取的是第一个内存单元的地址。取地址的指令是:
&a
如果我想将这个地址打印出来该怎么办?
printf("%p",&a);
用%p来表示地址
地址它本身也是一个值,那么存放地址的地方是pa(这个只是名字),它是专门用来存放地址的。
int * pa = &a;
而这个所谓的pa,在C语言中就叫做指针变量,这个变量的类型,如果是储存int的话,它的类型就是int*。这一个“*”说明了pa是指针变量,而int说明pa指向的对象是int类型。
所以这就是指针变量。
而取地址&就是之前漏掉没讲的一个单目操作符
指针的作用?
指针给地址,迟早是要用的。
int main()
{
int a = 0;
int * pa = &a;
*pa = 20;
return 0;
}
这里出现一个新的表达式*pa。 *是一个解引用操作。就是通过pa里边的地址,找到a。
这个时候再打印a,就会变成20,因为这是一个把a重新赋值的过程。把a改掉不一定要直接改a,也可以通过地址来解引用的方式来改。这个操作符 * 也是之前没讲的。
指针的作用弹幕里还有一种说法:比方说一个函数只能返回一个值,但是指针可以返回字符或者数组的地址,从而达到返回多个值的目的。
再用一句话精辟总结:指针就是地址
指针的大小是相同的。
为什么?
指针就是地址,
指针需要多大的空间,取决于地址的存储需要多大的空间
32位的电脑 32bit作为一个地址 32个bit就是4个byte(字节)
64位的电脑 64bit作为一个地址 也就是8个byte(字节)
结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。比如描学生,学上包涵:名字+年龄+成绩。
这就要用结构体
struct stu
{
char name[20];
int age;
float grade;
};
结构体可以让c语言创建新的类型出来。以上就是用struct创建出来的学生stu的类型。同样的道理可以创建很多的复杂类型。当类型创建出来之后,怎么去用呢?
结构体有一个初始化的过程:
struct Stu s = {"张三",20,85.5};
printf("%s %d &lf\n",s.name, s.age, s.grade);//结构体类型的名称.成员变量。
假如我要取s的地址, 用指针的方法也能打印出来,以下第一个printf和第二个printf打印的结果是一样的。
int main()
{
struct stu s = {"张三",20,85.5};//姓名 年龄 成绩
printf("1:%s %d %lf\n",s.name, s.age, s.grade);
struct stu * ps = &s;
printf("2:%s %d %lf\n", (*ps).name, (*ps).age, (*ps).grade);
return 0;
}
为什么要用第二种打印方法?因为有的时候你手里拿的并不是某个结构体本身,而是它的指针罢了。
我甚至还有第三种打印方法
printf("3:%s %d %lf\n", ps->name, ps->age, ps->grade);
这个小箭头就是之前没讲的操作符,这个箭头也叫做结构体的指针。剪头左边是结构体的位置,箭头右边是这个结构体的成员变量名。
到此为止,初识C语言的部分就已经告一段落了。
我入门了??