QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2041|回复: 33

一个关于指针问题的程序,望大侠帮忙!

[复制链接]
发表于 2004-12-7 18:36:49 | 显示全部楼层 |阅读模式
#include<stdio.h>
#include<conio.h>

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

void test( void )
{
   char *str = NULL ;
   getMemory( str ) ;
   strcpy( str , " hello world ! " ) ;
   printf( "%s\n" , str ) ;
}

void main( void )
{
   clrscr() ;
   test() ;
   getch() ;
}

程序运行结果是: (null) ,也就说并没有进行字串拷贝!请大家帮忙解答!谢谢!
发表于 2004-12-7 19:32:59 | 显示全部楼层
典型的错误

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

这里应该用char **,要是c++的话用引用
因为 getMemory()给p赋值了(而不是str),而main中的str仍然是null
回复

使用道具 举报

发表于 2004-12-8 12:45:08 | 显示全部楼层
嗯,getMemory只改变了形参p的值,确无法改变实参str的值啊
回复

使用道具 举报

发表于 2004-12-8 19:14:58 | 显示全部楼层
参数传值传递。
回复

使用道具 举报

 楼主| 发表于 2004-12-8 21:59:43 | 显示全部楼层
哦,这为仁兄果然是志同道合之人,不知道是否可以讲的再详细些,把其中的道理讲出来:它为什么就是“参数传值传递”呢?
回复

使用道具 举报

 楼主| 发表于 2004-12-8 22:12:57 | 显示全部楼层
我希望的到程序的原理,而不是程序表面的答案,我的问题再延伸一下,为什么只要是我把程序中的“char *str = NULL ;”语句的赋值去掉变成“char *str ;”而程序可以得到正确的答案(hello world !)呢?
回复

使用道具 举报

发表于 2004-12-8 23:33:34 | 显示全部楼层
[quote:d65ba8c964="yueyemingming"]我希望的到程序的原理,而不是程序表面的答案,我的问题再延伸一下,为什么只要是我把程序中的“char *str = NULL ;”语句的赋值去掉变成“char *str ;”而程序可以得到正确的答案(hello world !)呢?[/quote]

里面的值是乱的,你不知道把那部分的内存覆盖了,那块内存碰巧在你程序的运行空间里,而右碰巧没有引起问题。


所以说白了,能正常结束纯粹是运气。
回复

使用道具 举报

 楼主| 发表于 2004-12-9 10:45:12 | 显示全部楼层
这为仁兄,我很感谢你能热心的帮我解答问题,谢谢。不过我觉得,事实不是这样的!
昨天晚上,我下了网,又调试了这个程序,用printf语句打印地址( printf( "%p", str ) ; )时我发现:当你给str变量赋值时(char *str = NULL ; ),此句就相当于( char *str = '\0' ; ),然而此时(因为函数getMomery没有改变str的地址,str的地址仍然是原先的0x0000,它的内容可以说是"\0"(进行变量赋值的情况下))printf就相当于打印字符串"\0"(printf( "%s" , str ) ;),所以就会显示(null) 。
比如打印语句printf( "aaa\0aaaa" ) ;,只显示:aaa,后面的东西也就没有了。
你看我说的对吗,你也调试调试看看!谢谢!
回复

使用道具 举报

发表于 2004-12-9 12:46:38 | 显示全部楼层
[quote:9aa5b41e7a="yueyemingming"]str的地址仍然是原先的0x0000[/quote]无论在win还是unix下,当str是0时,是不可能对它进行操作的。
你给str=NULL是正确方法。之后程序结果不对,正表明这句str=NULL起了作用(程序有问题)。楼上的几位说的全是对的。之所以你不加str=NULL时程序有结果,是因为这时str!=NULL ,而这时的str值还在本程序数据地址空间中,逃脱了编译器的检查(这个地址在一个谁也说不清的地方),你的strcpy就起了作用,仅此而已。
回复

使用道具 举报

发表于 2004-12-9 13:16:37 | 显示全部楼层
你定义指针的时候,不妨把它想成是一个特殊的整数变量,这个变量特殊之处在于它里面存储的是某个内存的地址,而不是一般的整数。打个比方,一个整数变量A你可以想象成是一个盒子,盒子上的标签是A,盒子里面放了一整数。相应的,一个指针变量B也是一个盒子,这个盒子上也有个标签是B。不过这个盒子B里放的不是整数,而是另一个盒子的名字,例如A。这样你打开盒子B后看到的是盒子A的名字A,然后你再去打开盒子A,才能找到你要的整数。

至于你的函数getMemory (ptr),实际上是这样的:当你调用函数getMemory (B)的时候,程序其实复制了一个和B一样的盒子C,盒子C里面放的东西和盒子B里放的是同样的,例如都是A。这样你在函数getMemory里只是把盒子C里的东西改动了,例如改成了D,这样盒子B里的内容还是没有改变啊。
回复

使用道具 举报

发表于 2004-12-9 13:28:31 | 显示全部楼层
> 当你给str变量赋值时(char *str = NULL ; ),此句就相当于( char *str = '\0' ; ),然而此时(因为函数getMomery没有改变str的地址,str的地址仍然是原先的0x0000,它的内容可以说是"\0"(进行变量赋值的情况下))printf就相当于打印字符串"\0"(printf( "%s" , str ) ;),所以就会显示(null) 。

此处理解完全错误。

char* str = NULL,是把指针指向地址NULL(通常为0),也就是地址0。

'\0'是一个字符,其值实际为为(char) 0,注意它只有一个字节大小!而一个整数0,即(int) 0通常有4个字节大小。当然你用char* str = '\0'的时候,编译器自动把(char) 0扩展成4个字节的整数0。

"\0"是一个字符串,其长度为2个字节,第一个字节是'\0', 即(char) 0。第二个字节是字符串的结尾字符,正好,也是'\0',即(char) 0。这种程序里固定的字符串通常系统会给它分配好一段内存来存储它。

至于printf ("%s", str)打印出(null),那是因为printf比较聪明,发现你传给它的是内存地址0,而不是指向任何有效的内存地址。所以它打印出(null),意即你给了它一个指针指向NULL地址。
回复

使用道具 举报

发表于 2004-12-9 13:37:59 | 显示全部楼层
1  char *str;
2  getMemory( str ) ;
3  strcpy( str , " hello world ! " ) ;
4  printf( "%s\n" , str ) ;

你第一句如果没有初始话str的话,str这个指针变量里的值是没有定义的,没有定义的意思是它的值是”随机“的,既有可能是无效的地址,例如NULL,也有可能是有效地址。当是有效地址的时候,是什么地址,通常是未知的。

你第二句其实没有任何效果,没有改变str的值。str还是指向一个未知地址。

第三句你走运了,str恰恰指向一个有效的内存地址,strcpy把字符串复制到了str指向的一段内存里,而没有立刻引起程序访问出错。

第四句把str指向的地址里存储的字符串打印了出来。

记住:在任何程序里,你都只应该访问已知的地址,绝对不能访问一个未知地址,因为它会引起不可知的问题。或许这个问题没有立刻引起明显的错误,但是天知道在程序运行过程中会发生什么事情?!

好了,今天我老人家心情好,罗嗦了一大堆,希望对你有所帮助。
回复

使用道具 举报

发表于 2004-12-10 09:48:47 | 显示全部楼层
楼上的如果能常来,公社fans有福了
回复

使用道具 举报

发表于 2004-12-10 13:29:31 | 显示全部楼层
楼主大概在看林锐博士写的《高质量C++编程》吧?
关键还是要体会指针的概念啊。
回复

使用道具 举报

 楼主| 发表于 2004-12-11 19:17:11 | 显示全部楼层
TII老人家,小生这里有礼了。对小生的教导,感激不尽,可否推荐几本学习C、C++、JAVA和数据结构的好书?谢谢了!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-6 23:20 , Processed in 0.076645 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表