Day16
- 指针变量的使用
-
- 指针进阶
- 指针函数
- 函数指针
- 数组指针
- 指针数组
- 函数指针数组
- 二级指针
- 万能指针

指针变量的使用
指针变量和字符串的关系
- " hello world":字符类型的数组,本质是一个地址
520:整形类型
‘A’:小数类型
3.14:实数类型 - 字符串的本质是一个地址,可以使用一个指针变量存储该地址
char *p = “hello world”; - 字符串常量存储在静态区的只读区域,如果对上面这个指针 p修改的话将会出现段错误
指针进阶
指针函数
- 指针函数本质上是一个函数,返回值为指针的函数就是指针函数
- 指针函数调用的结果是一个左值
- 指针函数返回的必须是一个生命周期比较长的空间的地址,不能返回局部空间的地址
- 全局变量的空间
- 静态变量的空间
- 堆区申请的空间
- 主调函数以地址传入的空间
- 指针函数实现了将被调函数中的内存传递给主调函数使用
- 定义格式:
返回值类型 *函数名(参数列表){函数体;return 地址;}
#include <stdio.h>
int fun_1(int n)
{n += 10;return n;
}
int *fun_2()
{static int s = 66;return &s;
}int main(int argc, const char *argv[])
{int num = 520;int res = fun_1(num); printf("res = %d\n", res);int *ptr = fun_2();printf("*ptr = %d\n", *ptr);*fun_2() = 777; return 0;
}
函数指针
- 函数指针本质上是一个指针,用于指向函数的入口地址的指针
任何函数在被调用时系统都会为其分配运行空间,有空间就会有地址,有地址就可以用指针变量来指向他。存储函数运行空间地址的指针变量称为函数指针变量 - 任何一个函数的函数名都是该函数对应的入口地址,是一个地址常量
- 函数指针定义格式:
返回值类型 (* 变量名)(参数列表);
- 函数指针变量的用法:和函数名用法一致
#include <stdio.h>int sum(int m, int n)
{return m+n;
}int judge(int m)
{return m%2 == 0 ? 1 : 0;
}void sort(int *arr, int n)
{for (int i = 1; i < n; i++){for (int j; j < n-i; j++){if (arr[j] > arr[j+1]){int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}printf("排序成功\n");
}int main(int argc, const char *argv[])
{printf("%p\t%p\t%p\t\n", sum, judge, sort); int (*sum_ptr)(int,int) = sum;int (*judge_ptr)(int) = judge;void (*sort_ptr)(int *,int) = sort;printf("和为: %d\n", sum(1,4));printf("和为: %d\n", sum_ptr(1,4));if (judge(56)){printf("是一个偶数\n");}else{printf("是一个奇数\n");}if (judge_ptr(56)){printf("是一个偶数\n");}else{printf("是一个奇数\n");}return 0;
}
- 使用函数指针完成函数回调(回调函数)
函数回调:当调用某个函数时,不仅要向该函数中传递数据参数,也可以向该函数中传入一个功能
#include <stdio.h>int he(int m,int n)
{return m+n;
}int cha(int m, int n)
{return m-n;
}int ji(int m, int n)
{return m*n;
}
void calculate(int m, int n,int (*x)(int,int))
{int res = x(m,n);printf("结果为:%d\n", res);
}int main(int argc, const char *argv[])
{int num = 3, key = 6;calculate(num, key, he);calculate(num, key, cha);calculate(num, key, ji);return 0;
}
数组指针
- 数组指针的本质是一个指针,记录的是整个数组的地址
数组指针针对的是整个数组,每偏移一个单位,内存地址就偏移了整个数组的大小 - 数组指针的定义格式:
数据类型 (*指针名)[数组长度];
- 数组指针与一维数组的关系
- 数组名是第一个元素的地址 ----> 变量的地址
- 对一维数组名,再取地址,就得到了当前数组的地址(数组的地址)
#include<stdio.h>int main(int argc, const char *argv[])
{int arr[5] = {4,7,2,8,1}; int *ptr = arr; int (*arr_ptr)[5] = NULL; arr_ptr = &arr; printf("sizeof(arr) = %ld\n", sizeof(arr)); printf("ptr = %p,arr=%p, &arr[0]=%p, &arr = %p,arr_ptr=%p\n",\ptr, arr, &arr[0], &arr, arr_ptr);printf("ptr+1 = %p,arr+1=%p, &arr[0]+1=%p, &arr+1 = %p, arr_ptr+1=%p\n",\ptr+1, arr+1, &arr[0]+1, &arr+1, arr_ptr+1);printf("数组元素分别是:");for(int i=0; i<5; i++){printf("%d\t", arr_ptr[0][i]); }return 0;
}
- 数组指针与二维数组的关系
- 二维数组的数组名本质上是一个数组指针
- 当数组指针与二维数组结合后,指针的偏移才有现实的意义
#include<stdio.h>int main(int argc, const char *argv[])
{int arr[2][3] = {{1,2,3}, {4,5,6}}; int (*arr_ptr)[3] = arr; printf("&arr[0][0]=%p, arr[0]=%p, arr=%p, arr_ptr=%p\n",\&arr[0][0], arr[0], arr, arr_ptr);printf("&arr[0][0]+1=%p, arr[0]+1=%p, arr+1=%p, arr_ptr+1=%p\n",\&arr[0][0]+1, arr[0]+1, arr+1, arr_ptr+1);printf("数组元素分别是:\n");for(int i=0; i<2; i++){for(int j=0; j<3; j++){printf("%d\t", *(*(arr_ptr+i)+j));}printf("\n");}return 0;
}
指针数组
- 指针数组本质上是一个数组,但是每个元素都是一个指针变量
- 定义格式:
数据类型 *数组名 [数组长度]
函数指针数组
- 函数指针数组本质上是一个数组,数组中的每个元素都是一个函数指针变量,都可以存储函数入口的地址
- 能够实现对函数的批量调用
- 定义格式:
返回值类型 (* 数组名[数组长度])(形参列表)
二级指针
- 每个指针变量都占有内存空间,有空间就有地址,就可以使用指针存储他的地址
- 存储一级指针变量的地址的指针变量就是二级指针变量
一级指针变量的地址为二级指针 - 定义格式:
数据类型 **指针名
- 二级指针变量的值为:一级指针变量的地址
二级指针指向的内存空间中的值是一级指针(也就是变量的地址)—> *二级指针变量
二级指针取值两次是变量的值 —> **二级指针变量
- 二级指针变量常用于函数参数为主程序中的一级指针变量进行赋值
万能指针
- 万能指针就是可以接收任意地址的指针变量
- 定义格式:
void *指针名
- 由于没有任何类型的限制,导致该指针变量可以接收任意类型的地址
- 对于万能指而言不能直接进行
*
运算