参数传递
时间:2010-11-06 来源:liurhyme
在函数中实参变量对形参变量的数据传递是“单向值传递”,只由实参传给形参,不能由形参传回给实参。
作为这样一个人尽皆知的道理,但为什么在初始化函数中无法正确实现数组元素的初始化,感觉问题存在于初始化子函数中分配了堆空间,便让把分配空间的步骤移到主函数中,结果正确,但却产生疑惑了,这个现象出现的具体原因是什么,于是便写了一下测试小例子:
#include <stdio.h>
#include <stdlib.h>
void init(int *,int);
void point(int *); struct my_struct { int a; char *c; }; void test_struct(struct my_struct *my) { char *str = "hello world"; printf("%d\t%p\n",&(my->a),&(my->c)); my->a = 1; my->c = malloc(20); strcpy(my->c,str); printf("%d\t%s\n",my->a,my->c); printf("%d\t%p\n",&(my->a),&(my->c)); } int main(void)
{
int *array;
int test=0; struct my_struct my; init(array,2);
printf("%d\t%d\n",*array,*(array+1));
point(&test);
printf("%d\n",test); test_struct(&my); printf("%d\t%s\n",my.a,my.c); return 0;
}
void init(int *array,int n)
{
array=(int *)malloc(2);
*array=2;
*(array+1)=2;
printf("test value %d\t%d\n",*array,*(array+1));
// return ;
}
void point(int *num)
{
num=(int *)malloc(1*sizeof(int));
*num=3;
// return ;
}
void point(int *num)
{
*num=3;
// return ;
} 正如预料的,第一条printf语句无法打印出初始数值2,第2个函数能够打印出初始值3.
关于这个问题,其实很容易理解,这里面主要涉及到两方面的知识:系统内存堆栈空间分配和刚所说的参数传递。
栈 中存放函数的参数和函数局部变量的值,堆则是由程序员自己分配和释放,堆和栈位于不同的地址空间范围中。在测试函数中,main()函数中的array指 针为临时变量,存放在栈中,经init()函数参数传递后将其值赋给形参变量,在子函数中又讲过malloc()分配堆空间,此时返回地址为堆上的新地 址,等于在这个时候已经改变了形参array的值,这时由于C语言中的参数传递机制,子函数中形参值的改变不会反应在main函数中,所以在main函数 中不能显示出初始化的结果。而子函数point()则无这方面的问题。 总的来说,如果你需要在子函数中改变主函数的变量值,就必须传递此变量的地址,不管此变量是否为指针。所以,在测试函数中,只需将init函数的参数改为init(int **arr,int n)即可,这个问题也就暂时告一段落。 在此测试函数中,仍存在一个问题,在主函数中分配的指针并未初始化,期所指向的值属于未确定,在这样的情况下,Linux下不允许直接改变其所指向的值,运行时会出现段错误。这一点也需要注意. 为什么在结构体作为参数时,结构体的字符串变量在malloc变量之后的地址值没有发生改变呢,有些疑惑 若在main函数中定义结构体的指针的话,将此指针传进子函数时,会因为对位初始化的指针赋值而产生段错误。 什么个情况呢? 明天搞定!! 应该是这样理解的,结构体中字符串变量的my->c的值在malloc之后发生了变化,只 不过在测试语句中的打印打印的是&(my->c),它的类型为char **,它的值取决于结构体struct my的地址,在这里可以这样简单的理解,我们在test_struct中传递了两个参数,一个是int *a,一个是char **c,他们是两个指针,也就是两个地址,然后紧接着我们对*a = 1; *c = malloc(20); 在这里只是改变了这两个指针所指向的值,并没有对地址(也就是形参)作出修改,所以所作的改变时能够反映到主函数中的。 对于这个问题,最简单可以这样理解,我们参数传递的是结构体的指针,即其地址值,我们这里只是对其内部的变量作出修改,并没有改变结构体的地址值,所以修改时可以返回的 应该就是这个样子了。。。
#include <stdio.h>
#include <stdlib.h>
void init(int *,int);
void point(int *); struct my_struct { int a; char *c; }; void test_struct(struct my_struct *my) { char *str = "hello world"; printf("%d\t%p\n",&(my->a),&(my->c)); my->a = 1; my->c = malloc(20); strcpy(my->c,str); printf("%d\t%s\n",my->a,my->c); printf("%d\t%p\n",&(my->a),&(my->c)); } int main(void)
{
int *array;
int test=0; struct my_struct my; init(array,2);
printf("%d\t%d\n",*array,*(array+1));
point(&test);
printf("%d\n",test); test_struct(&my); printf("%d\t%s\n",my.a,my.c); return 0;
}
void init(int *array,int n)
{
array=(int *)malloc(2);
*array=2;
*(array+1)=2;
printf("test value %d\t%d\n",*array,*(array+1));
// return ;
}
void point(int *num)
{
num=(int *)malloc(1*sizeof(int));
*num=3;
// return ;
}
void point(int *num)
{
*num=3;
// return ;
} 正如预料的,第一条printf语句无法打印出初始数值2,第2个函数能够打印出初始值3.
关于这个问题,其实很容易理解,这里面主要涉及到两方面的知识:系统内存堆栈空间分配和刚所说的参数传递。
栈 中存放函数的参数和函数局部变量的值,堆则是由程序员自己分配和释放,堆和栈位于不同的地址空间范围中。在测试函数中,main()函数中的array指 针为临时变量,存放在栈中,经init()函数参数传递后将其值赋给形参变量,在子函数中又讲过malloc()分配堆空间,此时返回地址为堆上的新地 址,等于在这个时候已经改变了形参array的值,这时由于C语言中的参数传递机制,子函数中形参值的改变不会反应在main函数中,所以在main函数 中不能显示出初始化的结果。而子函数point()则无这方面的问题。 总的来说,如果你需要在子函数中改变主函数的变量值,就必须传递此变量的地址,不管此变量是否为指针。所以,在测试函数中,只需将init函数的参数改为init(int **arr,int n)即可,这个问题也就暂时告一段落。 在此测试函数中,仍存在一个问题,在主函数中分配的指针并未初始化,期所指向的值属于未确定,在这样的情况下,Linux下不允许直接改变其所指向的值,运行时会出现段错误。这一点也需要注意. 为什么在结构体作为参数时,结构体的字符串变量在malloc变量之后的地址值没有发生改变呢,有些疑惑 若在main函数中定义结构体的指针的话,将此指针传进子函数时,会因为对位初始化的指针赋值而产生段错误。 什么个情况呢? 明天搞定!! 应该是这样理解的,结构体中字符串变量的my->c的值在malloc之后发生了变化,只 不过在测试语句中的打印打印的是&(my->c),它的类型为char **,它的值取决于结构体struct my的地址,在这里可以这样简单的理解,我们在test_struct中传递了两个参数,一个是int *a,一个是char **c,他们是两个指针,也就是两个地址,然后紧接着我们对*a = 1; *c = malloc(20); 在这里只是改变了这两个指针所指向的值,并没有对地址(也就是形参)作出修改,所以所作的改变时能够反映到主函数中的。 对于这个问题,最简单可以这样理解,我们参数传递的是结构体的指针,即其地址值,我们这里只是对其内部的变量作出修改,并没有改变结构体的地址值,所以修改时可以返回的 应该就是这个样子了。。。
相关阅读 更多 +