文章目录

读者,你好!

如果你精通C,希望得到你的斧正;如果你是初学者,希望对你有所帮助!

加粗的是我认为比较重要的内容

#一、指针变量做函数参数

##1、列子引出

先用一个列子来说明,何为指针,指针在函数中是什么身份。

比如下课后,两位同学拿错了作业本,老师告诉了班长两位同学的宿号,让班长去换回作业本。

列子中,老师就是main函数,而班长是swap函数,两位同学的宿舍号就是swap函数的形参,老师告诉班长同学宿舍号就是参数传递的过程。 ##2、源码实现

/*this programmer is used to compear 2 double num, and output which is max and which is min*/

#include

int main()

{

void swap(double *p1, double *p2);

double a = 0, b = 0, *p1 = &a, *p2 = &b;

scanf("%lf%lf", &a, &b);

if(*p1 < *p2)//也可以写为if(a < b){ swap(&a, &b);}

{

swap(p1, p2);

}

printf("max = %lf\nmin = %lf\n", *p1, *p2);

return 0;

}

void swap(double *p1, double *p2) //形参p1,p2是指针变量

{

double temp;

temp = *p1;//通过指针访问了main空间的内容

*p1 = *p2;//通过指针访问和修改了main空间的内容

*p2 = temp;//通过指针修改了main空间的内容,并把swap函数的数据temp传回了main

}

运行结果为:

代码解析: swap函数的形参p1,p2前都有* 标识,表明当函数被调用时,p1和p2将被作为swap函数的指针变量(而不是普通变量),p1和p2中只能保存地址,不能保存普通数据。这里形参名为p1和p2,不能说成是*p1 和*p2。main函数对swap函数的调用语句是swap(p1,p2),这里将p1的值(地址)传给p1,将p2的值(地址)传给p2。 swap函数通过参数p1,p2获得了a,b的地址,在swap函数中,通过这两个地址就可以任意存取a,b这两个变量了,而不论a,b这两个参数位于哪个函数。

注意,swap函数中不能直接使用变量名a,b来访问main函数中的变量a,b如在swap中写为temp = a;a = b;b = temp; 是不行的。在swap中只能通过地址的方式访问它们。 ##3、错误分析 ###①错误类型一 如将swap函数写为如下形式:

void swap(double *p1, double *p2)

{

int *temp;

temp = p1;

p1 = p2;

p2 = temp;

}

不能达到预期结果,因为这只交换了p1和p2的值,只是交换了他们的储存空间,没有交换内容,并且本身修改后不能传回实参,即不能传到main函数。 ###②错误类型二

void swap(double *p1, double *p2)

{

double *temp;

*temp = *p1;

*p1 = *p2;

*p2 = *temp;

}

上述方式,定义了一个未知空间temp,并且通过指针修改了其数据。如果temp中存的是非常重要的内容,那么程序就会出问题,所以这种方法也是非常不可取的。 ###③错误类型三

void swap(double x, double y)

{

int temp;

temp = x;

x = y;

y = temp;

}

这种方式,只能单向传递,就是把main函数中想,x,y对应的值传到swap函数中,而不能传回交换后的值。 ##4、主调函数传回数据的第二种方式 先看代码

#include

int main()

{

void fun(int a, int b, int *sum, int *sub);

int a = 0, b= 0, m1,m2;

scanf("%d%d", &a, &b);

fun(a, b, &m1, &m2);

printf("sum = %d\nsub = %d\n", m1, m2);

}

void fun(int a, int b, int *sum, int *sub)

{

int p, q;

p = a + b;

q = a - b;

*sum = p;

*sub = q;

}

运行结果为:

这里直接用指针返回和与差,而没有用到return。

#二、数组做函数参数 数组做函数参数,说具体是指向数组的指针变量做函数参数。 由于数组名是该数组的首地址,指针变量的值也是首地址,所以函数的实参和形参都可以指向数组名或者数组的指针。于是有了以下四种对应关系: 数组名和数组指针做函数参数时的对应关系

实参形参数组名数组名数组名指针变量指针变量指针变量指针变量数组名

下面用一段代码来说明问题:

#include

int main()

{

float ave(int *b, float num);

int counter,a[5] = {0};

float all =0, res;

scanf("%f", &all);

for(counter = 0; counter < all; counter++)

{

scanf("%d", &a[counter]);

}

res = ave(a, all);

printf("%f", res);

return 0;

}

float ave(int *b, float num)

{

int i, sum =0;

float ave;

for(i = 0; i < num; i++)

{

sum = sum + b[i];

}

ave = (float)sum/num;

return ave;

}

这里传入函数ave的是数组a的首地址,而不是将整个数组传入。传入首地址后,ave函数就按照一定顺序去访问a的储存空间,从而得到a中的数据。

当然float ave(int *b, float num) 也可以写为float ave(int b[], float num) 或者float ave(int b[100], float num) 也就是说b[] 后面方括号内可以是任意数字,因为那个数字是没有意义的,真真起作用的是b和方括号。 总结一下这部分就是: 数组做形参,其实就是指针做形参。只要指针向函数内传入数组首地址,那么函数形参和实参是指同一数组。函数内部对数组所做的处理,就是对主调函数中的实参数组所作的处理,可以传回主调函数。 #三、函数的指针 部分编译器不支持这部分内容 ##1、函数语句的存储和函数的指针的定义 函数是由语句组成的,语句也是被存在连续的一段储存区域中的,所以我们考虑,能不能把函数的首地址也存在一个变量中,方便用一个变量调用不同的函数。。其实这种指向函数首地址的指针变量称为函数的指针,

int (*pf)();

上述语句就是对一个函数的指针的定义,它可以且只能保存函数的首地址。并且该函数的返回值是int形的。当然也可以在后面的()中加上函数的参数如int (*pf)(int , int )

下面介绍一个很重要的定义形式逆序阅读法 int (*pf)(); 有()先读()内的内容,读作:pf是指针,指向函数,函数返回值是int。 int *pf(); ()比*优先, 先读() 后读*, 读作pf 是函数, 其返回值是int * int pf(); 先读(),读作pf 是函数,函数返回值是int。

##2、变量指向函数及函数调用 让指针变量指向函数的方法如下:

pf = 函数名;

注意了,这里是干干净净的,没有任何零碎。 不要写为pf = &函数名, 或者*pf = 函数名;。 通过函数指针调用函数的方法如下:

(*pf)(参数,参数,.......);

或:

pf(参数,参数,....);

注意,调用函数时用(*pf), 或者直接用pf, 均可。(*pf)的* 仍然是一个标志,不是取其内容。 ##3、示例

#include

int main()

{

int max(int a,int b);

int (*pmax)();

int x, y, z;

pmax = max;

printf("input two numbers:");

scanf("%d%d", &x, &y);

z = (*pmax)(x, y);

printf("maxmum = %d", z);

return 0;

}

int max(int a, int b)

{

if(a > b)

{

return a;

}

else

{

return b;

}

}

部分编译器,不支持函数的指针。 送福利了

打印出9*9乘法表c语言输入年月日,输出这是一年中的第几天有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?