论坛首页 编程语言技术论坛

一个C语言指针问题

浏览 16418 次
精华帖 (1) :: 良好帖 (0) :: 新手帖 (6) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-06-26   最后修改:2011-06-27
C
今天重新拿起C语言的书学习学习,遇到了一个诡异的问题,开始不可理解,现在记录下整个分析过程。
首先上代码:
#include <stdio.h>

void strcopy(char *s, char *t)
{
    while ((*s++ = *t++) != '\0')
    ;
}

int main()
{
    int i = 3;
    char a[] = "abcdefg";
    char *p;	
    strcopy(p, a);
    printf("%d\n",i);
}

我估计大多数人看到这个程序都会认为会打印出3,但是结果出乎意料:


于是我分别做了两次修改,都使程序正常了。
第一次,我把strcopy函数注释掉了
#include <stdio.h>

void strcopy(char *s, char *t)
{
    while ((*s++ = *t++) != '\0')
    ;
}

int main()
{
    int i = 3;
    char a[] = "abcdefg";
    char *p;	
    //strcopy(p, a);
    printf("%d\n",i);
}

打印结果是3.
第二次,我把int i = 3;移动p指针下面定义:
#include <stdio.h>

void strcopy(char *s, char *t)
{
    while ((*s++ = *t++) != '\0')
    ;
}

int main()
{
    char a[] = "abcdefg";
    char *p;	
    int i = 3;
    strcopy(p, a);
    printf("%d\n",i);
}

也得到了正确的结果。
于是我用C free对原来的程序进行调试。

找到变量i的内存地址,可知其存放的是00000003,也就是数字3。
接着我执行strcopy方法后,就出状况了:


结果表明字符串被拷贝到了变量i的内存地址处。我对i处内存的内容进行十六进制转十进制,64636261转十进制后正好是1684234849.也就是这个诡异的输出结果。
综合以上的分析,所得结果如下:
#include <stdio.h>

void strcopy(char *s, char *t)
{
    while ((*s++ = *t++) != '\0')
    ;
}

int main()
{
    int i = 3;    //定义int型变量i,分配内存空间,并赋值
    char a[] = "abcdefg";
    char *p;    //定义指针p,并为初始化指针的位置,在此程序中p默认指向了i的地址
    strcopy(p, a);
    printf("%d\n",i);
}

现在真相大白了,不过任然让我疑惑的在指针p被定义的时候,p的默认指向地址是否有规律可循呢?任旧是个疑问,还请看到这篇文章的各位童鞋指点一二。
不过这个程序本来就是写的有问题,C语言的内存分配果然很容易出错(⊙o⊙)…
我想正确的程序应该是这样的...
#include <stdio.h>

void strcopy(char *s, char *t)
{
    while ((*s++ = *t++) != '\0')
    ;
}

int main()
{
    int i = 3;
    char a[] = "abcdefg";
    char *p = (char *)malloc(sizeof(a));    //给指针分配新的内存空间
    strcopy(p, a);
    printf("%d\n",i);
}

另外,搜索了下,函数malloc()和函数calloc() 的主要区别是前者不能初始化所分配的内存空间,而后者能。
  • 大小: 2.7 KB
  • 大小: 18.7 KB
  • 大小: 18.7 KB
   发表时间:2011-06-26  
为什么我用VC++运行不了
0 请登录后投票
   发表时间:2011-06-26  
liusondark 写道
为什么我用VC++运行不了

不太清楚,vc我不太会用,还是比较习惯gcc编译,C Free用的比较顺手
0 请登录后投票
   发表时间:2011-06-26   最后修改:2011-06-26
看都不用看,这个程序问题多得很。

1. s 一般表示source ,t表示target ,而写的时候source和target根本就是反的。

2. t根本就是未分配的地址,这样的拷贝根本随编译器的开心在任一地址中乱写。 微软vc的保护函数在这一方面做出了改进,但是可惜没有成为标准,否则用strcpy_s就能预防这种情况。glibc就比较陈旧了。

3. 改完了的结果还是错,有malloc就一定要有free,有new就要有delete否则就是退出,那内存就再不会被系统分配。
0 请登录后投票
   发表时间:2011-06-26  
ray_linn 写道
看都不用看,这个程序问题多得很。

1. s 一般表示source ,t表示target ,而写的时候source和target根本就是反的。

2. t根本就是未分配的地址,这样的拷贝根本随编译器的开心在任一地址中乱写。 微软vc的保护函数在这一方面做出了改进,但是可惜没有成为标准,否则用strcpy_s就能预防这种情况。glibc就比较陈旧了。

3. 改完了的结果还是错,有malloc就一定要有free,有new就要有delete否则就是退出,那内存就再不会被系统分配。

谢谢指点,第一条和第三条是看明白了,程序的确有问题,不过第二条有点糊涂,t根本就是未分配的地址是什么意思呢?还请这位哥们讲解一下啊
0 请登录后投票
   发表时间:2011-06-26  
ray_linn 写道
3. 改完了的结果还是错,有malloc就一定要有free,有new就要有delete否则就是退出,那内存就再不会被系统分配。

Quick overview of how processes exit on Windows XP
Raymond Chen 写道
Moral of the story: If you're getting a DLL_PROCESS_DETACH due to process termination,† don't try anything clever. Just return without doing anything and let the normal process clean-up happen. The kernel will close all your open handles to kernel objects. Any memory you allocated will be freed automatically when the process's address space is torn down. Just let the process die a quiet death.
0 请登录后投票
   发表时间:2011-06-27  
能否上传obj文件,gcc复现不了你说的问题,
O3编译倒是会出现尝试修改代码段的举动
默认编译,也没指令会体现出p的内容会是i的地址
0 请登录后投票
   发表时间:2011-06-27   最后修改:2011-06-27
RednaxelaFX 写道
ray_linn 写道
3. 改完了的结果还是错,有malloc就一定要有free,有new就要有delete否则就是退出,那内存就再不会被系统分配。

Quick overview of how processes exit on Windows XP
Raymond Chen 写道
Moral of the story: If you're getting a DLL_PROCESS_DETACH due to process termination,† don't try anything clever. Just return without doing anything and let the normal process clean-up happen. The kernel will close all your open handles to kernel objects. Any memory you allocated will be freed automatically when the process's address space is torn down. Just let the process die a quiet death.


呵,你总是比我有耐心啊。其实是这样的,it depends。“现代”OS的内存管理器是可以在process结束的时候回收这些内存,换句话说,free现在更多的是在process内释放内存,但是这不是每个os都是如此工作,在嵌入式里更是如此,有些os可能没办法正确回收这些内存导致奇怪的错误或者必须在一个时间周期里回收内存,在这之前这些内存仍是无法被分配,导致内存紧张。

一些我知道的不会free的OS,有dos, win98,老版本的netware等等。

所以在不确定OS怎么去做前,最好还是把这样的malloc/free对当成C/C++的铁律。
0 请登录后投票
   发表时间:2011-06-27  
新手 小白吧

p你只定义了一个指针,没有分配变量空间,运行中无意占用了i的空间。

这都不清楚?

一般这样
char str[128];
char * p=str;
strcpy(p,a);
0 请登录后投票
   发表时间:2011-06-27  
这个就是野指针吧。。。不能说是奇怪,这个情况可能在不同的编译器下出现的结果不一定相同。。你没初始化指针,那么指向哪都有可能的。。不过挺有意思的,让LZ加深了对指针初始化的意识的加强
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics