Chinaunix首页 | 论坛 | 博客
  • 博客访问: 447688
  • 博文数量: 111
  • 博客积分: 4290
  • 博客等级: 上校
  • 技术积分: 1301
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-24 14:22
个人简介

努力工作,建立一个幸福的家庭。

文章分类

全部博文(111)

文章存档

2015年(4)

2013年(9)

2012年(6)

2011年(17)

2010年(69)

2009年(6)

分类: C/C++

2010-04-22 16:16:53


# include
#include
#include

void Getmemery(char*p)
{
    p=(char*)malloc(100);
}

void main()
{
    char*str=NULL;

    Getmemery(str);
    strcpy(str,"hello world");
    printf("%s",str);
    free(str);
}

编译没有问题的,但是为什么执行的时候会错误退出呢?根据现象,很明显是指针的非法访问了,但是问题在哪里,我一时也蒙了,或者说被他的思路给引导到了一个错误的方向。

当然,最简单的解决办法是返回一个指针就没有问题,稍微修改一下:

 

# include
#include
#include

char*Getmemery(void)
{
    char*p=(char*)malloc(100);

    return p;
}

void main()
{
    char*str=NULL;

    str = Getmemery();
    strcpy(str,"hello world");
    printf("%s",str);
    free(str);
}

这样代码执行的很正常,这种风格也是很常用的,也就作罢。

 

但是为什么第一个程序不正确?理论上,按照理论上分析是“正确”的,心里一直有个结,解不开这个题目,心里总是有点不舒服。

直到今天在ouravr上面看到有个关于 typedef 用法的帖子,突然引起了我的兴趣,自己关于指针的,特别是二维数组和数组指针并不是理解的很透侧,于是就趁此机会好好的复习一下二维数组。

最后终于将之前的一个问题想明白了。正确的代码如下:

 

# include
#include
#include  
void Getmemery(void**p)
{
    *p=(void**)malloc(100);
}

void main()
{
    char*str=NULL;

    Getmemery(&str);
    strcpy(str,"hello world");
    printf("%s",str);
    free(str);
}

我们应该使用的是二重指针来完成任务。

分析一下之前的程序为什么会错了。

(1)void Getmemery(char *p)

(2)char *str=NULL;

(3)Getmemery(str);

1 中子程序的形参是一个指针,然后很自然会想到2,3中的调用方式,本来的想法是用malloc分配内存,然后修改传入的指针变量,那么最后就根据通过 strcpy(str,"hello world"); 就可以向分配的内存里面写数据了。一切都是那样流畅,对,因为这个用法平时用习惯了,所以根本不会去考虑正确性。

然而,这里就出问题了。首先,Getmemery(str) 传递的是 srt指针的地址,这个没有问题,C不同于C++,参数是通过传递的,而不是通过引用。也就是说,实际参数 srt 先自己copy一份,然后传递给形式参数 *P接收,这个C语言的指针的时候已经强调多次了,但是自己还是错了啊,哈哈。

然后,在子程序里面,如果通过 *P 那么访问到的将是 *str的内容,这是等价的。但是,本程序一个致命的错误,非常隐蔽,那是子程序企图修改 p 的内容,而不是 *p 的内容!!这个错误找了我很久终于给揪出来了。修改了 p 的值是没有意义的,这个值是形式参数,并不会返回任何的东西,而 *p 则是通过p的地址直接访问需要的变量,这是不同的用法。所以说白了,void Getmemery(char *p) 执行之后并没有改变任何的东西,str的值并没有修改过,保持NULL,所以访问 *0 地址会被操作系统禁止,得到一个错误。

解决办法,是用2重指针。目的是要修改指针的地址,但是按照上面的分析,我们并不能去修改,但是我们可以用2重指针,将*str的地址值str,用2重指针来改变。

void Getmemery(void **p)
{
 *p=(void **)malloc(100);
}

子程序修改为这个样子,出入的参数也得修改

char *str=NULL;
Getmemery(&str);

那么可以这样理解,因为形参是2重指针,所以 p 对应 &str ,*P 对应 str,之前说了,我们的目的是要修改 str的值,所以很自然,我们用 *p = xxx 这样的形式去修改了。

这样得到的程序就正确了。2重指针,使用起来还是有点晕,得多加练习。
详细出处参考:

------------------------------------------------------

#include
int main()
{
 int sum(int * const st,const int num );
 int s[10];
 int sm = 0;
 int i;
 for (i=0;i<10;i++) s[i]=i;
 sm = sum(s,10);
 printf("sum=%d",sm);
 getchar();
 return 0;
}

int sum(int *const st, const int num)
{
 int sum  = 0;
  int *s = st ;  //直接用st的话,则会出错。
 int i;
 for (i=0;i {
  sum += *st;
  printf("%d\t",*s);
  s++;
 }
 return sum;
}

正确

---------------------------------------------------

阅读(553) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~