C 传递指针给函数
C 语言允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。
下面的实例中,我们传递一个无符号的 long 型指针给函数,并在函数内改变这个值:
实例
#include <stdio.h>
#include <time.h>
void getSeconds(unsigned long *par);
int main ()
{
unsigned long sec;
getSeconds( &sec );
/* 输出实际值 */
printf("Number of seconds: %ld\n", sec );
return 0;
}
void getSeconds(unsigned long *par)
{
/* 获取当前的秒数 */
*par = time( NULL );
return;
}
#include <time.h>
void getSeconds(unsigned long *par);
int main ()
{
unsigned long sec;
getSeconds( &sec );
/* 输出实际值 */
printf("Number of seconds: %ld\n", sec );
return 0;
}
void getSeconds(unsigned long *par)
{
/* 获取当前的秒数 */
*par = time( NULL );
return;
}
当上面的代码被编译和执行时,它会产生下列结果:
Number of seconds :1294450468
能接受指针作为参数的函数,也能接受数组作为参数,如下所示:
实例
#include <stdio.h>
/* 函数声明 */
double getAverage(int *arr, int size);
int main ()
{
/* 带有 5 个元素的整型数组 */
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
/* 传递一个指向数组的指针作为参数 */
avg = getAverage( balance, 5 ) ;
/* 输出返回值 */
printf("Average value is: %f\n", avg );
return 0;
}
double getAverage(int *arr, int size)
{
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = (double)sum / size;
return avg;
}
/* 函数声明 */
double getAverage(int *arr, int size);
int main ()
{
/* 带有 5 个元素的整型数组 */
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
/* 传递一个指向数组的指针作为参数 */
avg = getAverage( balance, 5 ) ;
/* 输出返回值 */
printf("Average value is: %f\n", avg );
return 0;
}
double getAverage(int *arr, int size)
{
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = (double)sum / size;
return avg;
}
当上面的代码被编译和执行时,它会产生下列结果:
Average value is: 214.40000
Sigma
175***[email protected]
通过传递指针给函数,可以直接修改原参数(实参),而不是引用实参到形参。
如上例中:
直接修改了sec 的值。
Sigma
175***[email protected]
Wanghaha2333
297***[email protected]
参考地址
指针和函数的关系
1、函数指针(指向函数的指针)
一个函数在编译之后,会占据一部分内存,而它的函数名,就是这段函数的首地址。
可以把一个指针声明成为一个指向函数的指针。
C 语言规定函数名会被转换为指向这个函数的指针,除非这个函数名作为 & 操作符或 sizeof 操作符的操作数(注意:函数名用于 sizeof 的操作数是非法的)。也就是说 f = test; 中 test 被自动转换为 &test,而 f = &test; 中已经显示使用了 &test,所以 test 就不会再发生转换了。因此直接引用函数名等效于在函数名上应用 & 运算符,两种方法都会得到指向该函数的指针。
指向函数的指针必须初始化,或者具有 0 值,才能在函数调用中使用。
与数组一样:
示例1:
示例2:
示例2:
运行结果为:
这里的玄学就是 *test 为什么能和上面两个之前介绍过的输出一样的值。
首先来看函数名 test,是一个符号用来标识一个函数的入口地址,在使用中函数名会被转换为指向这个函数的指针,指针的值就是函数的入口地址,&test 在前面已经说了:显示获取函数的地址。*test 可以认为由于 test 已经被转换成了函数指针, 指向这个函数,所以 *test 就是取这个指针所指向的函数名,而又根据函数名会被转换指向该函数的指针的规则,这个函数也转变成了一个指针,所以 *test 最终也是一个指向函数 test 的指针。也就是说:*test --> *(&test) --> test --> &test。
上述关系十分重要!
为了更加明确,把示例 1 做补充:
2、指针函数(返回值为指针的函数)
所谓指针函数,就是返回指针的函数。在前面笔记中“从函数返回数组”中已经介绍。
C 语言的库函数中有很多都是指针函数,比如字符串处理函数,下面给出一些函数原型:
3、两者混用(不常用)
注意函数的返回值不仅仅局限于指向变量的指针,也可以是指向函数的指针。
首先来看这个声明:*int (*function(int)) (double*, char); 要了解此声明的含义,首先来看 function(int),将 function 声明为一个函数,它带有一个 int 型的形式参数,这个函数的返回值为一个指针,正是函数指针 int (*) (double*, char); 这个指针指向一个函数,此函数返回 int 型并带有两个分别是 double* 型和 char 型的形参。
如果使用typedef可以将这个声明简化:(没看懂。。。。之后的结构体再补充)
另一个例子:
现在要分析的是 signal,因为紧邻 signal 的是优先级最高的括号,首先与括号结合,所以 signal 为一个函数,括号内为 signal 的两个形参,一个为int型,一个为指向函数的指针。接下来从向左看,* 表示指向某对象的指针,它所处的位置表明它是 signal 的返回值类型,现在可以把已经分析过的 signal 整体去掉,得到 void (*) ( int siga )。又是一个函数指针,这个指针与 signal 形参表中的第二个参数类型一样,都是指向接受一个 int 型形参且不返回任何值的函数的指针。
用 typedef 可以将这个声明简化:
这个 signal 函数是 C 语言的库函数,在 signal.h 中定义,用来处理系统中产生的信号。
4、函数指针数组
假设现在有一个文件处理程序,通过一个菜单按钮来选择相应的操作(打开文件,读文件,写文件,关闭文件)。这些操作都实现为函数且类型相同,分别为:
现在定义一个函数指针类型的别名PF:
把以上 4 种操作取地址放入一个数组中,得到:
如果不使用 typedef,那么分析起来就会比较复杂,结果是 void (*file_options[ ]) ( );
这个数组中的元素都是指向不接受参数且不返回任何值的函数的指针,因此这是一个函数指针数组。接下来,定义一个函数指针类型的指针action并初始化为函数指针数组的第一个元素:PF* action = file_options;,如果不好理解,可以类比一下:
这里 PF 相当于 int,这样应该比较好懂了。
复习:
通过对指针 action 进行下标操作可以调用数组中的任一操作,如:action[2]( ) 会调用 write 操作,以此类推。在实际中,指针 action 可以和鼠标或者其他 GUI 对象相关联,以达到相应的目的。
5、函数与指针的复杂声明(不做要求,一般用 typedef 代替它)
只举一个例子:
阅读步骤:
所以 fp 是指向函数的指针(函数指针), 该函数返回一个指向数组的指针,此数组有 10 个 int* 型的元素。
int *(*(*fp)(int)) [10]; (*fp)(int)是一个指向函数的指针ptr*(*fp)(int)相当于一个指针ptr1(指针函数的返回值)最后剩下int *ptr1[10],可以理解。Wanghaha2333
297***[email protected]
参考地址
rookie
liy***[email protected]
指出楼上第3个小目录一个小问题
ps: 应该是大佬无意写错了,无伤大雅,其他知识点理的都很好
用 typedef 可以将这个声明简化,应该是:
rookie
liy***[email protected]