一. 指针常见的几个错误
1.1 字符串常量
cpp
int main()
{
char *p = "hello";//字符指针,p指向的是一个字符串常量,只可读,存储在.rodata中
//且在内存中只存储一份
char str[10] = "hello";//字符数组,开辟一份空间将hello字符串复制给数组
// printf("%s\n",p);
// *(p + 0) = 'e';//会出现段错误
// printf("%s\n",p);
printf("%s\n",str);
*(str + 0) = 'e';//可以对字符中的内容进行修改
printf("%s\n",str);
return 0;
}

原因:

char *p = "hello";//这是一个字符指针,p指向的是一个字符串常量,只可读,存储在数据区
的.rodata中,且在内存中只存储一份。
char str[10] = "hello";// 这是定义的一个数组,里面存放的是hello这个字符串,存储在栈区中,可
读可改。
1.2 指针未初始化
cpp
void swap(int *a, int *b)
{
int *t;//野指针
*t = *a;//对野指针进行写操作,段错误
*a = *b;
*b = *t;
}
二. 指针函数与函数指针
2.1 指针函数
指针函数:函数的返回值是指针类型。
eg:

注意:不能返回是局部作用域的指针。
希望函数在同一个语句里面可以连续调用
希望返回一段内存区域(数组,堆空间)
2.2 函数指针
函数指针 :指向一个函数。本质上是一个指针变量。
函数名:其实函数名是地址值。里面储存函数实现的代码。
目的:避免代码的重复。 方便后期代码的扩展。函数功能的解耦合 。
回调函数:一个函数被当作参数 ,传递给另外一个函数。 被传递这个参数(函数指针,回调函
数)被动调用。主调函数只是传参(函数)。
回调函数就是通过函数指针调用的函数。如果把函数指针作为参数传递给另一函数,当这个指针被用来调用其所指向的函数时,就称其为回调函数。回调函数不是由函数的实现方直接调用,而是在满足特定的条件下由另一方直接调用,用于对该事件进行响应。
eg:
cpp
int add(int a, int b)
{
return a + b;
}
int main()
{
int a = 10, b = 20;
int ret = 0;
int (*pfun)(int,int) = add;
ret = add(a,b);
printf("a + b = %d\n",ret);
ret = pfun(a,b);
printf("a + b = %d\n",ret);
return 0;
}
函数指针两个练习:说明下面两段代码分别干了什么:
完成一次函数调用:
cpp
*((void(*)())0)();
完成函数的声明:
cpp
void (*signal(int, void(*)(int)))(int);
三. typedef关键字
类型重命名
cpp
typedef 老数据类型名 新数据类型名;
使用typedef可以使函数指针的写法更易懂:
cpp
typedef char c8;
typedef unsigned long u64;
typedef unsigned short u16;
typedef int* (*PFUN)(int, int, char*);
int* func(int a, int b, char* c)
{
return NULL;
}
int func2(int a, int b, PFUN pfun)
{
char str[10] ={ 0 };
pfun(a,b,str);
return 0;
}
比如2.2的第二个例子:
cpp
void (*signal(int, void(*)(int)))(int);
可以使用typedef:更易懂。
cpp
typedef void(*pfun)(int);
pfun signal(int, pfun);