#define 定义常量和宏

define 是一个预处理指令

define 定义标识符常量

1
2
3
4
5
6
7
//define 定义标识符常量
#define MAX 1000
int main()
{
printf("%d\n",MAX); //1000
return 0;
}

define 定义宏

1
2
3
4
5
6
7
8
9
10
define 定义宏
#define ADD(x,y) x+y
#define ADD2(x,y) ((x)+(y))
int main()
{
printf("%d\n",ADD(2,3));//5
printf("%d\n", 4*ADD(2, 3));//11 4*2+3
printf("%d\n", 4 * ADD2(2, 3));//20
return 0;
}

define 定义宏的时候,字符串出现运算符,需要在合适的位置上加括号

否则宏的参数会被替换 替换成 4*x+y

指针

内存

内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的。

所以为了有效使用内存,就把内存划分成一个个小内存单元,每个内存单元的大小是1个字节

为了能够有效的访问到内存的每个单元,就给内存单元进行编号,这些编号就被称为内存单元地址

内存是怎么编号的?

32位 - 32根地址线 - 物理线 - 通电 - 1/0

64位 - 64根地址线 - 物理线 - 通电 - 1/0

电信号转换位数字信息:1和0组成的二进制序列

00000000000000000000000000000000

01111111111111111111111111111111

10000000000000000000000000000000

11111111111111111111111111111111

一共2的32次方的序列

而这些序列都可以成为内存的编号

解析一个内存单元有多大空间?

一共有2的32次方个内存单元

假设:

一个内存单元是1bit

那么一共就有2的32次方bit

换算成十进制就是

4,294,967,296bit

/8 = 536,870,912byte

/1024 = 524,288kb

/1024 = 512Mb

/1024 = 0.5GB

那么 一个数据类型 比如char 占一个字节,一个字节占有8bit 那么就要有8个地址

这显然是不合理的

结果:一个内存单元是一个字节,一个字节是一个编号,然后分配地址

指针变量

1
2
3
4
5
int main()
{
int a = 10;//a在内存中要分配空间 - 4个字节
return 0;
}

我们使用F10进行调试

通过&a我们可以看到它的内存地址为00B8F804

在内存中存储为十六进制

而且 int类型占用4个字节,也就使用了4个地址

但如图可以看出,只有第一个地址有值,其余地址是没有使用的

所以&a仅仅只是调用了第一个地址进行存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main()
{
int a = 10;//a在内存中要分配空间 - 4个字节
//%p 打印内存地址
//&可以获取地址
printf("%p\n",&a);//00B8F804 这个就是现在这个a 的内存地址
//* 说明 pa是指针变量
//int 说明pa执行的对象是int类型
int * pa = &a;//pa是用来存放地址的,在C语言中叫指针变量

char ch = 'w';
char * pc = &ch;
return 0;
}

那么我们能不能通过地址来找到a呢

1
2
3
4
5
6
7
8
9
10
int main()
{
int a = 10;
int* pa = &a;
// 这里的 * 是解引用操作
// *pa就是通过pa里的地址,找到a
*pa = 20;
printf("%d\n", a);
return 0;
}

指针的大小

1
2
3
4
5
6
7
8
9
10
11
int main()
{
printf("%d\n", sizeof(char*));//4
printf("%d\n", sizeof(short*));//4
printf("%d\n", sizeof(int*));//4
printf("%d\n", sizeof(long*));//4
printf("%d\n", sizeof(long long*));//4
printf("%d\n", sizeof(float*));//4
printf("%d\n", sizeof(double*));//4
return 0;
}

我们可以发现,指针的大小都是相同的

因为指针使用了存放地址的,指针需要多大空间取决于地址的存储需要多大的空间

32位平台 - 32bit - byte

64位平台 - 64bit - 8byte

vs2019可以在如图位置修改位数

结构体

结构体 - 可以让C语言创建新的类型出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//创建一个学生类型
struct stu
{
char name[20];//成员变量
int age;
double score;
};
//创建一个书的类型
struct Book
{
char name[20];
float price;
char id[30];
};
int main()
{
struct stu s1 = {"张三",20,85.5};//结构体的创建和初始化
//怎么拿到结构体里的数据 结构体变量.成员变量 比如 s1.name
printf("%s %d %lf\n", s1.name, s1.age, s1.score);//张三 20 85.500000
return 0;
}

那么我们运用一下前面指针的知识点

能不能通过指针来找到结构体的成员变量呢

1
2
3
4
5
6
7
8
9
int main()
{
struct stu s1 = {"张三",20,85.5};//结构体的创建和初始化
//怎么拿到结构体里的数据 结构体变量.成员变量 比如 s1.name
printf("1: %s %d %lf\n", s1.name, s1.age, s1.score);//1: 张三 20 85.500000
//指针
struct stu* pa = &s1;
printf("2: %s %d %lf\n", (*pa).name, (*pa).age, (*pa).score);//2: 张三 20 85.500000
}

我们定义了一个指针变量 pa 存储了s1的地址

然后使用*解引用操作,找到了s1

扩展:

使用上面的方法有一点麻烦了,我们可以使用->操作符来拿到结构体的成员变量

-> 的使用 结构体指针 -> 成员变量

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
struct stu s1 = {"张三",20,85.5};//结构体的创建和初始化
//怎么拿到结构体里的数据 结构体变量.成员变量 比如 s1.name
printf("1: %s %d %lf\n", s1.name, s1.age, s1.score);//1: 张三 20 85.500000

struct stu* pa = &s1;
printf("2: %s %d %lf\n", (*pa).name, (*pa).age, (*pa).score);//2: 张三 20 85.500000
// -> 的使用 结构体指针 -> 成员变量
printf("3: %s %d %lf\n",pa->name, pa->age, pa->score);//3: 张三 20 85.500000
return 0;
}