指针
指针是什么?
- 指针(Pointer)是编程语言的一个对象,利用地址,他的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能够找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”,意思是通过它就能找到以它为地址的内存单元。
指针类型
- 指针类型决定了指针进行解引用操作的时候,能够访问空间的大小。
- 指针类型决定了指针的步长
指针的大小与系统的操作位数有关,32位/64位 4byte/8byte
野指针
-
概念:
- 指针指向的位置是不可知的(随机的)
-
造成野指针的原因:
- 指针未初始化
- 数组越界
- 指向了已经释放的指针
int* test6(){
int a = 0;
return &a;
}
int main(){
int* c = test6();
printf("%d",*c);
return 0;
}
-
如何避免野指针:
- 指针初始化
- 小心指针越界
- 及时将释放了的指针指向NULL
- 使用指针前检查其有效性
内存泄漏
-
造成的原因:
- 指向内存区域的指针的值发生了改变
指针运算
-
指针±整数
- 其数据类型决定了指针在内存中走多远(多少个字节)
int arr[] = {1,2,34,5,6,7,8,9,10};
for(int i =0;i<10;i++){
printf("%d",*(p+i));
}
-
指针-指针
-
在两个指针指向同一个内存单元,指针-指针得到的是指针地址之间的元素个数。
- 例题一:
-
int test7(char * str){
//求字符数组的元素个数
char* start = str;
char* end = str;
while (*end != '\0'){
end++;
}
return end - start;
}
int main(){
char arr[] = "qwdcsvz";
printf("%d", test7(arr));
return 0;
}
- 指针的关系运算
指针和数组
-
数组名是首元素的地址
-
数组名不是数组首元素地址的是:
-
&arr
- 整个数组的地址
-
sizeof(arr)
- 整个数组
-
二维数组
- 第一个一维数组的地址
-
以及二维以上数组
-
-
注意:允许最后一个数组元素后面的那个内存地址进行比较,但不允许首元素前一个内存地址进行比较。
二级指针
- 存放一级指针地址的指针
指针数组
- 存放指针地址的数组
- 如果指针数组内存放的是指针,则需要两次解引用才能访问其值。
//指针数组
void test3(){
int a = 1;
int b = 2;
int c = 3;
int* p[3] = { &a, &b, &c};
int i = 0;
for (i = 0; i < 3; i++){
printf("%d ", *(p+i));
printf("\n");
}
}
数组指针
-
存放指针数组地址的指针
- //数组指针
int arr[6] = { 1, 2, 3, 4, 5, 6 };
int(*p)[6] = &arr;
// int 为指向数组的元素类型
//(*p)指的是 指针变量p
//[6] 指的是指针指向的数组有6个元素
- 主要用二维及以上的数组传参使用
指向数组指针的指针数组
- //指向数组指针的指针数组
int arr1[6] = { 1, 2, 3, 4, 5, 6 };
int arr2[6] = { 2, 3, 4, 5, 6,7 };
int arr3[6] = { 3, 4, 5, 6,7,8 };
//数组指针
int (*pArr1)[6] = &arr1;
int (*pArr2)[6] = &arr2;
int (*pArr3)[6] = &arr3;
//指向数组指针的指针数组
int(*p[3])[6] = { pArr1, pArr2, pArr3 };
//指向数组指针的指针数组的指针
int(*(*ps)[3])[6] = &p;
printf("%d",*(*(p+1)+1));
字符指针
-
char arr[] = “abcdef”;
- 实际将除了字符串内容放到字符数组内外,还将\0放到了字符数组的末尾
-
char* arr = “abcdef”;
- 实际将常量字符串a的地址放在了字符指针arr中
- 注意: 此时不可通过间接引用修改*arr的值
- 最好使用一下写法:
const char* arr = “abcdef”;
-
例题:
- ①:相同的字符串的数组名相比较是否相同
- ②:比较相同字符串的字符指针否相同
//判断两值是否相同
char arr1[] = "abcdefg";
char arr2[] = "abcdefg";
char* p1 = "abcdefg";
char* p2 = "abcdefg";
if (arr1 == arr2){
printf("haha");
}
else{
printf("hehe");
}
//结果是“hehe”
//判断两值是否相同
char arr1[] = "abcdefg";
char arr2[] = "abcdefg";
char* p1 = "abcdefg";
char* p2 = "abcdefg";
if (p1 == p2){
printf("haha");
}
else{
printf("hehe");
}
//结果是“haha”
指针作为函数参数
-
一级指针char* arr可以接收什么样类型的数据
- ①:一级指针变量
- ②:char类型变量的地址(&变量名)
-
二级指针char** arr可以接收什么样类型的数据
- ①:二级指针变量
- ②:一级指针变量的地址
- ③:字符指针数组的地址。
const 修饰指针变量
-
const int* p
- 指针所指向的值不能发生改变
- 不能通过(*p)修改指向内存单元内的值
-
int* const p
- 指针的值不能发生改变
- 不能修改指针边内指向的地址
函数指针
-
定义:指向函数的指针称为函数指针。
-
函数指针的声明:
- 返回值类型 (*函数指针名) (函数参数列表) = 函数名
-
((void ()())0)()
- 该式子为将整型0转换为函数指针,然后解引用地址0,并调用该函数,参数为空。
-
void (* signed(int,void (*)()))(int);
- 其实是一个函数声明,函数signed为两个参数int、函数指针的函数,返回值为函数指针。
-
函数指针的调用:
- int(*p)(int) = test5;
//其结果都是一样的。
printf("%d “, (*p)(5));
printf(”%d “, (**p)(5));
printf(”%d “, (*p)(5));
//函数指针也可以不带调用,但带必须与指针变量在一个小括号内
printf(”%d ", p(5));
5 5 5 5 请按任意键继续. . .
- int(*p)(int) = test5;
-
函数指针数组
-
int(*p[5])()
-
案例:计算器
- 方法一: 普通调用
- 方法二:(转移表)
-
//计算机入口 方法一
int Add(int x ,int y){
return x + y;
}
int Min(int x, int y){
return x - y;
}
int Mul(int x, int y){
return x * y;
}
int Div(int x, int y){
return x / y;
}
void test6(){
int input = 0;
int(*func[4])(int, int) = {Add,Min,Mul,Div};
do{
menu();
printf("请输入功能按键>");
scanf("%d", &input);
int x = 0, y = 0;
switch (input){
case 1:printf("请输入两个操作数,空格隔开>");
scanf("%d %d", &x, &y); printf("%d\n", func[0](x, y)); break;
case 2:printf("请输入两个操作数,空格隔开>");
scanf("%d %d", &x, &y); printf("%d\n", func[1](x, y)); break;
case 3:printf("请输入两个操作数,空格隔开>");
scanf("%d %d", &x, &y); printf("%d\n", func[2](x, y)); break;
case 4:printf("请输入两个操作数,空格隔开>");
scanf("%d %d", &x, &y); printf("%d\n", func[3](x, y)); break;
case 0:break;
default:printf("输入有误,请重新输入!\n"); break;
}
} while (input);
printf("程序退出。\n");
}
//计算机入口 方法二
int Add(int x ,int y){
return x + y;
}
int Min(int x, int y){
return x - y;
}
int Mul(int x, int y){
return x * y;
}
int Div(int x, int y){
return x / y;
}
void test7(){
int input = 0;
int(*func[])(int, int) = { 0,Add, Min, Mul, Div };
do{
menu();
printf("请输入功能按键>");
scanf("%d", &input);
int x = 0, y = 0;
if (input > 0 && input <= sizeof(func) / sizeof(func[0])){
printf("请输入两个操作数,空格隔开>");
scanf("%d %d", &x, &y);
printf("%d\n", func[input](x, y));
}else
if (input == 0){
printf("程序退出。\n");
}
else{
printf("输入有误,请重新输入!\n");
}
} while (input);
}
-
回调函数
- 回调函数就是一个通过指针调用的函数。当一个函数当做实参传递给另一个函数时,另一个函数通过该函数指针调用其指向的函数时,我们程为回调函数。
-
指向函数指针数组的指针
- int fun(int x,int y){
return x + y;
}
函数指针数组
int (p[3])(int,int) = {fun1,fun2,fun3};
函数指针数组的指针
int ( (*p)[3])(int,int) = &p;
指针p指向一个元素为3的数组,元素类型为返回值类型int,参数为2个int类型的函数。
- int fun(int x,int y){
void * 指针
- void*指针为通用指针(无类型指针),可以接收任意类型的指针
- void* 不能解引用操作
- void* 不能进行±整数操作