指针
1、内存的概述
在32位平台,每一个进程 拥有4G的空间。
系统为内存的每一个字节 分配一个32位的地址编号
地址编号 == 指针
内存的最小分配单位为字节 最小存储单位二进制位
2、指针和指针变量的关系
指针 就是内存的地址编号。
指针变量:本质是变量 只是该变量 保存的是 内存的地址编号。(不是普通的数值)

3、指针变量的定义
1、定义步骤(定义的时候)
*修饰指针变量p。
保存谁的地址 你先定义谁。
从上往下整体替换
1 定义一个指针变量p 保存 int num的地址; int *p;
2 定义一个指针变量p 保存数组int arr[5]首地址; int (*p)[5]
3 定义一个指针变量p 保存函数的入口地址 int fun(int,int); int (*p)(int,int);
4 定义一个指针变量p 保存结构体变量的地址 struct stu lucy; struct stu *p;
5 定义一个指针变量p 保存指针变量int *p的地址 int **p2、指针变量的详解
1、在32位平台任何类型的指针变量 都是4字节
2、在64位平台任何类型的指针变量 都是8字节
3、指针变量和普通变量建立关系


4、指针变量的初始化
指针变量 在操作之前 必须指向合法的地址空间
1、指针变量 如果不初始化 立即操作 会出现段错误
2、指针变量 如果没有指向合法的空间 建议初始化为NULL
int *p = NULL;//NULL是赋值给p int *p; p = NULL3、将指针变量 初始化为 合法的地址(变量的地址、动态申请的地址、函数入口地地址)
1 int num = 10;
2 int *p = #//int *p; p = #
1 int data=10, *p=&data;5、指针变量的类型
1、指针变量自身的类型
将指针变量名拖黑,剩下的类型就是指针变量自身的
int *p; p自身的类型为int *2、指针变量指向的类型(重要)
将指针变量名和离它最近的一个* 一起拖黑,剩下的类型就是指针变量指向的类型
int *p; p指向的类型为int6、指针变量的指向类型 决定了取值宽度
1 int num = 0x01020304;
2 int *p = #
3 为啥 *p == num == 0x01020304?

最高位的0省略了
7、指针变量的指向类型 决定了+1跨度

案例1:取出0x0102的值(跨度和宽度都是一样的)

案例3:取出0x0203的值

8、*p等价num
1 int num = 10;
2 int *p = #
3 //p==&num
4 //*p == *&num == num9、指针变量的注意项
1、void 不能定义普通变量
void num;//error 不能给num开辟空间2、void * 可以定义指针变量
1 void *p;//ok p自身类型为void *,在32位平台任意类型的指针 为4B
2 那么系统知道为p开辟4B空间,所以定义成功p就是万能的一级指针变量, 能保存 任意一级指针的地址编号
万能指针 一般用于 函数的形参 达到算法操作多种数据类型的目的。
记住:不要直接对void *p的指针变量 取*
1 int num = 10;
2 void *p = #
3 *p;//err p指向的类型为void 无法确定p的取值宽度 所以不能*p对p取*之前 对p先进行指针类型强转。

3、指针变量 未初始化 不要取*
1 int *p;
2 *p;//err 段错误4、指针变量 初始化NULL 不要取*
1 int *p = NULL;
2 *p;//err 段错误5、指针变量 不要越界访问
1 char ch = 'a';
2 int *p = &ch;
3 *p;//error 越界访问非法内存1 int num = 10;
2 int *p = #
3 p++;
4 *p;//越界访问10、数组元素的指针变量
1、概述
1 int arr[5]={10, 20,30,40,50};
2
3 //需求定义一个指针变量 保存 数组元素的地址
4 int *p;
5 p = &arr[0];
6 p = arr;//arr作为地址 第0个元素的地址 arr==&arr[0]
7 p = &arr[3];2、数组元素的指针变量 和 数组名(作为地址) 等价

arr[i]
int *p = arr
*(p + i)
*(arr + i)3、在使用中 【】就是 *()的缩写
1 void test10()
2 {
3 int arr[5] = {10, 20, 30, 40, 50};
4 int n = sizeof(arr) / sizeof(arr[0]);
5
6 printf("arr[1] = %d\n", arr[1]);
7 printf("*(arr+1) = %d\n", *(arr + 1));
8 printf("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐\n");
9 printf("*(arr+1) = %d\n", *(1 + arr));
10 printf("1[arr] = %d\n", 1 [arr]);
11
12 //[]是*()的缩写 []左边的值 放在+的左边 []里面的值 放在+右边 整体取*
13 }11、指向同一数组元素的两个指针变量间的关系

12、字符串与指针
1、字符数组
char str1[128]="hello world";
sizeof(str1) == 128字节str1是数组 开辟128字节 存放字符串"hello world"
2、字符串指针变量
char *str2="hello world";
sizeof(str2) == 4字节 或 8字节
str2是指针变量 在栈区/全局区 保存的是字符串常量"hello world"的首元素地址,
而”hello world“在文字常量区
13、指针数组
指针数组:本质是数组 只是数组的每个元素为 指针。
32位平台:
1 char *arr1[4];
2 short *arr2[4];
3 int *arr3[4];
4
5 sizeof(arr1) ==16B
6 sizeof(arr2) ==16B
7 sizeof(arr3) ==16B1、数值的指针数组

2、字符的指针数组
char *arr[4]={"hehehehe", "xixixixixi", "lalalalala", "hahahahaha"};
3、二维字符数组
1 char *arr1[4]={"hehehehe", "xixixixixi", "lalalalala", "hahahahaha"};
2 char arr2[4][128]={"hehehehe", "xixixixixi", "lalalalala", "hahahahaha"};arr1是在指针数组 存放的是每个字符串的首元素的地址
arr2是二维字符数组 存放的是每个字符串
14、指针的指针
1 int num = 10;
2 int *p = #
3 int **q = &p;n级指针变量 可以保存 n-1级的地址
15、数组指针
1、数组首元素地址 和 数组首地址
int arr[5]={10, 20, 30,40,50}数组首元素地址:&arr[0] == arr +1跳过一个元素(4B)

数组的首地址:&arr +1跳过整个数组 (4b * 5 = 20)

数组首元素地址编号 和数组的首地址编号 一致。但是他们的类型不同
2、数组指针 本质是指针变量 保存的是数组的首地址
1 int arr[5]={10, 20, 30,40,50};
2 int (*p)[5] = NULL;//数组指针
3 p = &arr;
4 arr[2] = *(*p + 2) // 这里的*p == arr 相当于 *(arr+2) 元素+2
案例1:
1 int arr[5]={10, 20, 30,40,50};
2 int (*p)[5] = &arr;//数组指针
3
4 printf("%d", *((int *)(p+1)‐2) );//40 这里相当于直接跑到末尾总结:
1 int *arr[5];//指针数组 本质是数组 每个元素为int *
2 int (*arr)[5];//数组指针 本质是指针变量 保存的是数组的首地址(概数组必须5个元素每个元素为int)16、二维数组和数组指针的关系
1、深入了解二维数组

1 arr[1] => *(arr+1) 第一行第0列的列地址
2 &arr[1] => &*(arr+1)=>arr+1 第1行的行地址
3 *arr+1 => 第0行第1列的列地址
4 arr[1]+2 =>*(arr+1)+2 =>第1行第2列的列地址
5 **arr ==*(*(arr+0)+0) == arr[0][0]2、二维数组和一维数组指针的关系

1 int arr[n]; int *p;
2 int arr[n][m]; int (*p)[m];
3 int arr[n][m][k]; int (*p)[m][k]
4 n维数组 和 n‐1维的数组指针 等价
数组指针是变量,可以进行++等操作,arr是不行的17、多维数组的物理存储
不管几维数组在物理上都是一维存储
18、指针变量作为函数的参数
如果想在函数内部 修改外部变量的值 需要将外部变量的地址 传递给函数。(重要)
案例1:单向传递之值传递
函数内部 不能修改外部变量的值

案例2:单向传递 之 传递地址
函数内部 就可以修改 外部变量的值
1 void swap(int *a, int *b)
2 {
3 //*a == data1 *b == data2
4 int tmp= *a; *a=*b;*b=tmp;
5 }
6 swap(&data1, &data2);19、数组作为函数参数
函数内部 想操作(读或写)外部数组元素,将数组名 传递给函数。
1 void input_int_array(int *p, int n)
2 {
3 printf("请输入%d个int数据:", n);
4 int i = 0;
5 for (i = 0; i < n; i++)
6 {
7 scanf("%d", p + i);
8 }
9 return;
10 }
11 void get_max_min_data(int *arr, int *p_max, int *p_min, int n)
12 {
13 int max = arr[0], min = arr[0];
14
15 int i = 0;
16 for (i = 1; i < n; i++)
17 {
18 if (max < arr[i])
19 max = arr[i];
20 if (min > arr[i])
21 min = arr[i];
22 }
23
24 //*p_max = 外部max *p_min==外部的min
25 *p_max = max;
26 *p_min = min;
27
28 return;
29 }
30 void test03()
31 {
32 int arr[5] = {0};
33 int n = sizeof(arr) / sizeof(arr[0]);
34
35 //获取键盘输入
36 input_int_array(arr, n);
37
38 //求最大最小值
39 int max = 0, min = 0;
40 get_max_min_data(arr, &max, &min, n);
41 printf("max=%d, min=%d\n", max, min);
42 }20、二维数组作为函数参数
函数内部 想操作 函数外部的二维数组 需要将二维数组名 传递给函数。
1 //二维数组 作为函数的形参 会被优化成 一维的数组指针
2 //void printf_int_two_array(int arr[3][4], int row, int col)
3 void printf_int_two_array(int (*arr)[4], int row, int col)
4 {
5 printf("内部sizeof(arr)=%lu\n", sizeof(arr)); //8B
6 int i = 0, j = 0;
7 for (i = 0; i < row; i++)
8 {
9 for (j = 0; j < col; j++)
10 {
11 printf("%d ", arr[i][j]);
12 }
13 printf("\n");
14 }
15 return;
16 }
17 void test05()
18 {
19 int arr[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
20 int row = sizeof(arr) / sizeof(arr[0]);
21 int col = sizeof(arr[0]) / sizeof(arr[0][0]);
22
23 printf("外部sizeof(arr)=%lu\n", sizeof(arr)); //48B
24 printf_int_two_array(arr, row, col);
25 }21、函数的返回值类型 为指针类型
将函数内部的合法地址 通过返回值 返回给函数外部使用。
注意:函數不要返回值 普通局部变量的地址


22、函数指针
1、函数指针的定义
函数名 代表函数的入口地址;
函数指针:本质是一个指针变量 只是该变量 保存的是函数的入口地址
1 //函数指针 p只能保存 有两int形参以及int返回值 的函数入口地址
2 int (*p)(int, int) = NULL
2、函数指针变量注意:
函数指针变量 不要+1 无意义
不要对函数指针变量取* 无意义
1 int (*p)(int, int) = my_add;
2 *p会被编译器优化成p函数指针变量 判断大小 > < 无意义
函数指针变量 可以赋值 p2=p1
函数指针变量 可以判断相等 p2 ==p1
3、函数指针变量 使用typedef定义


23、函数指针 作为函数的参数
案例1:my_calc完成加减乘除
1 #include <stdio.h>
2 int my_add(int x, int y)
3 {
4 return x + y;
5 }
6 int my_sub(int x, int y)
7 {
8 return x ‐ y;
9 }
10 int my_mul(int x, int y)
11 {
12 return x * y;
13 }
14 int my_div(int x, int y)
15 {
16 return x / y;
17 }
18
19 //设计算法 完成加减乘除
20 int my_calc(int d1, int d2, int (*func)(int, int))
21 {
22 return func(d1, d2);
23 }
24 int main(int argc, char const *argv[])
25 {
26 printf("%d\n", my_calc(10, 20, my_add));
27 printf("%d\n", my_calc(10, 20, my_sub));
28 printf("%d\n", my_calc(10, 20, my_mul));
29 printf("%d\n", my_calc(10, 20, my_div));
30
31 return 0;
32 }案例2:完成加减乘除
1 #include <stdio.h>
2 #include <string.h>
3 int my_add(int x, int y)
4 {
5 return x + y;
6 }
7 int my_sub(int x, int y)
8 {
9 return x ‐ y;
10 }
11 int my_mul(int x, int y)
12 {
13 return x * y;
14 }
15 int my_div(int x, int y)
16 {
17 return x / y;
18 }
19
20 int main(int argc, char const *argv[])
21 {
22 char *cmd_buf[] = {"add", "sub", "mul", "div"};
23 int n = sizeof(cmd_buf) / sizeof(cmd_buf[0]);
24 //函数指针数组
25 int (*fun_arr[])(int, int) = {my_add, my_sub, my_mul, my_div};
26
27 while (1)
28 {
29 printf("请输入计算格式:add 10 20:");
30 char cmd[16] = "";
31 scanf("%s", cmd);
32 if (strcmp(cmd, "quit") == 0)
33 break;
34
35 int data1 = 0, data2 = 0;
36 scanf("%d %d", &data1, &data2);
37
38 //算法核心
39 int i = 0;
40 for (i = 0; i < n; i++)
41 {
42 //相等为0
43 if (strcmp(cmd, cmd_buf[i]) == 0)
44 {
45 printf("结果:%d\n", fun_arr[i](data1, data2));
46 break;
47 }
48 }
49 }
50
51 return 0;
52 }
53
阿源的知识库