1 多级指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>

void test1(int ** n) {}

// 1.多级指针。
int mainT2() {

int num = 999;
// 一级指针 *
// 在真实开发过程中,最多三级指针 int ***
int * num_p = &num; // 取出num的内存地址给 num_p(一级指针)

int ** num_p_p = &num_p; // 取出num_p的内存地址给num_p_p(二级指针)

int *** num_ppp = &num_p_p;

printf("num_p的值是:%p, num_p_p的值是:%p\n", num_p, num_p_p);
// num_p的值是:0061FF18, num_p_p的值是:0061FF14

// 我先输出 999
printf("获取最终的值:%d\n", **num_p_p);
printf("获取最终的值:%d\n", *** num_ppp);

// 多级指针的意义是什么啊,使用框架的时候,给自己定义的结构体赋值
// test1(num_p_p)

// printf("num_p的自己的内存地址是:%p, num_p_p自己的额内存地址是:%p\n", &num_p, &num_p_p);

// *num_ppp 取的是什么? 取出二级指针的值

return 0;
}

2 数组与数组指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
int mainT3() {
// 定义数组
// int [] arr = {1,2,3,4}; 错误的写法
int arr[] = {1,2,3,4};

// 遍历数组
// 其他平台不能用 Clion能用, Linux上报错,int定义在外面
/*for (int i = 0; i < 4; ++i) {

}*/

// VS非常严格,规范,CLion包容

// Linux上没有问题,Clion没有问题,Mac没有问题
int i = 0;
for (i = 0; i < 4; ++i) {
printf("%d\n", arr[i]); // 取值
}

// 数组 和 指针 挂钩
// 数组的内存地址 == 第一个元素的内存地址 == &arr
// 数组的内存地址 == 第一个元素,不是第二个元素,也不是第n个元素
// 以下三种写法都是数组arr首地址
printf("arr = %d\n", arr);
printf("&arr = %d\n", &arr);
printf("&arr[0] = %d\n", &arr[0]);

// 既然数组就是一个内存地址
int * arr_p = arr;

printf("%d\n", *arr_p); // *arr_p 取出元素一内存地址的值 1

arr_p ++; // 指针挪动 元素二的内存地址了

printf("%d\n", *arr_p); // *arr_p 取出元素二内存地址的值 2

arr_p += 2;

printf("%d\n", *arr_p); // 输出4

// 输出1

arr_p -= 3; // 挪动指针指向到 元素一

printf("%d\n", *arr_p);

arr_p += 2000;

printf("%d\n", *arr_p); // 系统值 572662306

// 以后:我想 三维数组/三级指针
// int *** arrPpp;

return 0;
}

3 采用指针遍历数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int mainT4() {

// 定义数组
// int [] arr = {1,2,3,4}; 错误的写法
int arr[] = {1,2,3,4};

// 数组是连续的内存空间(没有断层,有规律) 数组 每次挪动 4个字节 == int数组

int * arr_p = arr;

int i = 0;
for (i = 0; i < 4; ++i) {
printf("位置%d的值是:%d\n", i, * (arr_p + i));

// 04 08 12 16
printf("位置%d的内存地址是:%p\n", i, (arr_p + i));
}

return 0;
}

4 循环时给数组赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int mainT5() {

// 定义数组
// int [] arr = {1,2,3,4}; 错误的写法
int arr[4];

int * arrP = arr;

// sizeof arr == sizeof(arr)

// 循环赋值操作
int j = 0;
for (j = 0; j < 4; ++j) {
// 1.拿到 元素一 元素二 元素三 元素四 的内存地址 (arrP + j)
// 2.取出 元素一 元素二 元素三 元素四 的内存地址 所对应的值 * (arrP + j)
* (arrP + j) = (j + 10001);
}

// sizeof arr = 16(sizeof arr) / 4(sizeof(int))
// 变量 刚刚赋值的数组
for (int i = 0; i < sizeof arr / sizeof(int); ++i) {
printf("位置%d的值是:%d\n", i, * (arrP + i));
}

return 0;
}

5 数组指针操作的几种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main() {

int arr[] = {1,9,0,9999};

int * arrP = arr;

for (int i = 0; i < 4; ++i) {
// printf("%d\n", arrP[i]);
// printf("%d\n", *(arrP + i)); // + i 挪动元素3内存地址 再取元素3内存地址所对应的值
printf("%d\n", *arrP + i); // 取数组第一个元素循环加i
}

return 0;
}

6 指针类型用途

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main() {

int num = 12;

int * num_p = &num;

// 优化处理,VS报错:检测无法通过的
double * num_p_d = num_p;

printf("%d\n", sizeof num_p);
printf("%d\n", sizeof num_p_d);

// 指针占用的内存大小是? int double xxx 的指针 永远都是 4个字节(32) 4*2(64位操作系统)

// 6.指针类型有何用?。 既然都是 4个字节,为什么还要分 指针类型
// 答:取值的时候,怎么取,这就是类型规定的好处

// int * p; // 类型是为了计算偏移量

char c = 'a';
// char * p = &c;
// char * p = "AAAA";

return 0;
}

7 指针函数

函数指针一般用于回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void add(int num1, int num2); // 先声明

void mins(int num1, int num2) {
printf("num1 - num2 = %d\n", (num1 - num2));
}

// 操作 回调到 add mins
// void(*method)(int,int) 声明好 函数指针
// void 返回值
// (*method) 函数名
// (int,int) 两个参数
void opreate(void(*method)(int,int), int num1, int num2) {
method(num1, num2);

printf("opreate函数的 method指针是多少:%p\n", method);
}

// 7.函数指针。(回调) Java接口的回调
int mainT8() { // 【第一种写法】

opreate(add, 10, 10);
opreate(mins, 100, 10);

printf("main函数的 add指针是多少:%p\n", add);
printf("main函数的 mins指针是多少:%p\n", mins);

// &add和add是一样的值吗
printf("%p, %p\n", add, &add); // 004018CE, 004018CE 一样的

return 0;
}

// 再实现 使用
void add(int num1, int num2) {
printf("num1 + num2 = %d\n", (num1 + num2));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void add(int i,int j) {
printf("i+j=%d\n", i+j);
}

void add2(int i,int j) {
printf("2 i+j=%d\n", i+j);
}

// 函数 函数指针声明来接收函数
void test(void(*p)(int, int)) {
p(9, 9); // 省略*

(*p)(9, 9);
(p)(9, 9); // 省略*

// (&p)(9, 9); 在源码没有看到这种写法

// 思考:p 为什么也可以不用写 * 函数的上面已经声明就是 函数指针,所以可以省略*

}

int mainT1() {
test(add);
test(add2);
return 0;
}