Chinaunix首页 | 论坛 | 博客
  • 博客访问: 372461
  • 博文数量: 73
  • 博客积分: 3574
  • 博客等级: 中校
  • 技术积分: 1503
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-26 11:17
文章分类

全部博文(73)

文章存档

2012年(14)

2011年(15)

2010年(44)

分类: C/C++

2010-04-14 21:13:29

   作为任意一个C语言的学习者都明白这样一个规定,在函数中实参变量对形参变量的数据传递是“单向值传递”,只由实参传给形参,不能由形参传回给实参。
   作为这样一个人尽皆知的道理,前两天却遇到了这样的问题。同学忽然问我一个关于数组初始化的问题,问说为什么在初始化函数中无法正确实现数组元素的初始化,看了他的代码感觉问题存在于初始化子函数中分配了堆空间,便让他把分配空间的步骤移到主函数中,结果正确,但我自己却产生疑惑了,这个现象出现的具体原因是什么,于是便写了一下测试小例子:
#include
#include
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); 在这里只是改变了这两个指针所指向的值,并没有对地址(也就是形参)作出修改,所以所作的改变时能够反映到主函数中的。
对于这个问题,最简单可以这样理解,我们参数传递的是结构体的指针,即其地址值,我们这里只是对其内部的变量作出修改,并没有改变结构体的地址值,所以修改时可以返回的
应该就是这个样子了。。。
 
阅读(1017) | 评论(0) | 转发(0) |
0

上一篇:Linux内核线程

下一篇:堆和栈的区别

给主人留下些什么吧!~~