有一天师弟兴冲冲的跑过来和我说:“师兄,我发现c语言设计存在一个bug。”
我问到:“什么bug呢?”
师弟说道:“你看我这段程序,没有生效。”
我笑着说到:“难道没有可能是你写的代码有问题?”
师弟说:“不会,我检查了好几遍了,这么简单的代码应该不会有问题的。”
我说:“那好,我们就简单分析一下。”
师弟的代码
#include <stdio.h>
#include <stdint.h>
/**
* add - 求两个整数的和
* @a: 一个有效int数据
* @b: 一个有效int数据
* @sum: 有个int数和
*
* Returns: 0 on success
* -1 on error
*/
int add(int a, int b, int sum) {
if (((long long int)a + (long long int)b) > INT32_MAX) {
return -1;
}
sum = a + b;
return 0;
}
int main()
{
int a, b, sum = 0, ret;
scanf("%d %d", &a, &b);
ret = add(a, b, sum);
if (!ret) { //没有溢出时,输出2个数的和
printf("%d + %d = %d\n", a, b, sum);
} else { //溢出时,打印不支持
printf("sum is overflow, no support!\n");
}
return 0;
}
最后代码执行,sum输出是0,而不是a + b的和。有一种“他强任他强,清风拂山岗;他横由他横,明月照大江。”我还是我之感。
add函数,将sum值传入到函数中,却没有将sum值带回,为什么呢?
这里其实是典型的传值和传址的问题。
传值(pass by value)和传址(pass by reference)是函数调用的两种参数传递方式。传值意味着函数接收的是变量的副本,因此在函数内部对参数所做的修改,不会影响到原始变量。传址意味着函数接收的是变量地址的副本(通常使用指针),因此在函数内部对参数所做的修改,会影响到原始变量。
当前这个情况就是,将sum的值传给了形参,而并没有将地址传给形参。
修正的方法也比较简单,如下,只需把sum的地址传入就行。
#include <stdio.h>
#include <stdint.h>
int add(int a, int b, int *sum) { //接收sum的地址
if (((long long int)a + (long long int)b) > INT32_MAX) {
return -1;
}
*sum = a + b;
return 0;
}
int main()
{
int a, b, sum, ret;
scanf("%d %d", &a, &b);
ret = add(a, b, &sum); //传入sum的地址
if (!ret) {
printf("%d + %d = %d\n", a, b, sum);
} else {
printf("sum is overflow, no support!\n");
}
return 0;
}
这里只是简单的传值和传址的示例,当遇到更加复杂的双重指针问题时,很多时候容易被绕错。当发现存在修改值失效时,就需要考虑自己是不是传参存在问题了。师弟挠了挠脑袋,不好意思的笑着说道:“我二了,还是回去继续学习去”。