C语言简明指针教程(2)只做了一点微小的工作
指针是 C/C++的精华,如果未能很好地掌握指针,那 C/C++也基本等于没学。
函数指针
- 函数指针是指向函数的指针,指向函数的指针变量中存储的是一个函数在内存中的入口地址。
- 冯·诺依曼体系结构强调,程序与数据共同存储在内存中,函数是子程序,当然也存储在内存中,指向存储这个函数的第一条指令的地址,称为函数的入口地址。
- 一个函数名就是这个函数的源码在内存中的起始地址,编译器将不带()的函数名解释为该函数的入口地址。
- 函数指针可以像一般函数一样,用于调用函数、传递参数。
- 函数指针变量的声明:返回值类型 ( * 指针变量名) ([形参列表]);
程序示例3:
int max(int x, int y)
{
return x > y ? x : y;
}
主函数里:
int (* p)(int, int) = &max; // 定义函数指针,&可以省略
int a = 8, b = 5, c = 7, d;
d = p(p(a, b), c); // 与直接调用函数等价
printf("abc三个数字中最大的是: %d\n", d);
示例3运行结果:
- 如果去掉* p两侧的圆括号,它声明的将是一个两个整形形参并返回整形指针的函数。
从函数返回指针
- 必须声明一个返回指针的函数,如下所示:
int * myFunction()
{
内容
}
程序示例4:
以重写字符串连接函数strcat()为例:
char * MyStrcat(char * dstStr, char * srcStr)
{
char * pStr = dstStr;
while (*dstStr != '\0'){
// 将指针移到字符串dstStr的末尾
dstStr++;
}
for( ; *srcStr != '\0'; dstStr++, srcStr++){
*dstStr = *srcStr;
}
*dstStr = '\0';
return pStr;
}
主函数里:
char first[160] = "Hello";
char second[80] = " World!";
MyStrcat(first,second);
printf("%s\n",first);
示例4运行结果:
解决问题一:从函数中返回修改后的数据值
按值调用与模拟按引用调用
程序示例5:
void Fun1(int pa){
printf("Fun1 : pa = %d\n", pa );
pa = 2; // 改变值
}
void Fun2(int * pa){
printf("Fun2 : *pa = %d\n", *pa ); // 传出*pa指向的变量的值
*pa = 2; // 改变指向
}
主函数里:
int a = 1;
printf("a = %d\n",a );
Fun1(a);
printf("a = %d\n",a );
Fun2(&a); // 传递变量a的地址
printf("a = %d\n",a );
示例5运行结果:
- 模拟按引用调用是一种常用的从函数中返回修改后的数据值的方法。(用数组名做函数实参就属于这类)
程序示例6:
void Swap(int * pa, int * pb){
int temp;
temp = *pa;
*pa = *pb;
*pb = temp;
}
主函数里:
int a = 1,b = 2;
printf("Before : a = %d, b = %d \n", a, b);
Swap(&a, &b);
printf("After : a = %d, b = %d \n", a, b);
示例6运行结果:
- 当函数形参为指针类型而实际上却接受了一个整型的实参数据时,某些编译器会将这个整型值当做地址值,并按照这个地址值去访问内存,从而在程序运行时引发非法内存访问错误,另一些编译器会给出警告信息(不能轻视warning同志们)。
解决问题二:函数单返回值
程序示例7:
找出给定的n个数中的最大值及其对应的最小下标(下标从0开始)。(数组输入过程略)
void FindMax(int num[], int n, int * max, int * m){
int i;
*max = num[0];
*m = 0;
for(i = 0; i < n ; i++)
{
if(num[i] > *max)
{
*max = num[i];
*m = i;
}
}
}
主函数里:
int n = 5,max ,m ,i ;
int num[5]={3 ,5 ,6 ,1 ,6};
FindMax(num,n,&max,&m);
printf("最大值%d 对应的最小下标%d",max ,m);
补:数组输入过程示例:
int n;
int num[10]; // 一般为宏常量N
scanf("%d",&n);
for(int i = 0; i < n ; i++)
{ scanf("%d",&num[i]);}
示例7运行结果:
解决问题三:通用处理函数
回调函数
- 函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
简单讲:回调函数是由别人的函数执行时调用你实现的函数。
程序示例8:
int a = 0;
// 回调函数
void populate_array(int * array, int n, int (* anybody)(void))
{
int i;
for (i = 0; i < n; i++)
array[i] = (*anybody)(); // (*anybody)()等价于直接用名字anybody()
}
// 获取值
int getValue1(void)
{a++; return a;}
int getValue2(void)
{a--; return a;}
主函数里:
int num[10],i;
populate_array(num, 10, getValue1);
for(i = 0; i < 10; i++) {
printf("%d ", num[i]);
}
printf("\n");
populate_array(num, 10, getValue2);
for(i = 0; i < 10; i++) {
printf("%d ", num[i]);
}
示例8运行结果: