august 发表于 2008-1-24 17:21:38

地址問題


#include<iostream>
using namespace std;
void print(char *[],int);
void main()
{
    char *pn[]={"fred","barney","wilma","betty"};
    int num=sizeof(pn)/sizeof(char *);
    print(pn,num);
    cout<<sizeof(string);
}
void print(char *arr[],int len)
{
    for(int i=0;i<len;i++)
      cout<<(int)arr<<" "//輸出地址
      <<arr<<endl;
}

為什麼地址間是相差8,不是相差4呢?

duzhi5368 发表于 2008-1-25 10:28:04

为什么会是4呢?

august 发表于 2008-1-25 17:39:29

那為什麼是8呢?

呆呆蜗牛 发表于 2008-1-26 00:45:06

这个估计是和编译器的实现有关。

以下论述基于系统GNU/Linux + GCC 4.2.2 on X86-64,因此仅供楼主参考,目前正在虚拟机中下载安装VC6,重新测试后将通知楼主结果。 :)

楼主如果用(int)arr的形式,其结果不(一定)是arr中的地址值也不是arr自身的地址(****请楼主注意这两者的区别****),虽然说似乎应该是前者,但要注意指针值是32位无符号整数(这当然是对于32位机器而言),而int是32位有符号整数,转换是有一定危险的,应该使用(void*)arr,这也是我对楼主程序作出的修改。

【补记】实际上由于64位地址不能转换到32位的整型,楼主的程序在我的64位环境中是根本无法编译通过的~TAT~

我的程序编译后输出结果如下:

0x400cca fred
0x400ccf barney
0x400cd6 wilma
0x400cdc betty

可以看到各个指针之间的差值不等,仔细观察发现其差值正好是各单词长度+1,也就是说,在gcc的编译结果中,是将整个数组的值作为常量连续存储的,内存格局如下:

0x400cca:fred\\0barney\\0wilma\\0betty\\0

注意在C++标准中规定, 所有的字符串字面值都是不可变的,也就是说像fred这一类直接在代码中写出的字符串都是常量,而字符指针数组中的每个指针都只是一个指向常量区域对应的字符串开头的指针而已,并不能自己开辟新的空间来存放之。

从实际效果来说,就是以下几点:

第一,字符串常量之间的地址关系可以由编译器实现决定。
第二,所有形如char *str = &quot;abc&quot;的代码都是危险的,修改str的值会造成程序崩坏,应该使用const char*。

也就是说,如果楼主想要的是arr中指向的地址,那么它们的差值不是4是完全正常的。

如果说楼主要的是arr这个变量自身的地址,应该使用&arr来表达,如此则结果变为:

0x7fff61f73730 fred
0x7fff61f73738 barney
0x7fff61f73740 wilma
0x7fff61f73748 betty

这是在我的64位系统中测试的结果,所以差值为8是正常的。

但是在楼主的32位系统中,差值应该是4才对,无测试,无真相,待用VC6测试后即可确认了~

此外楼主的程序中,void main()的写法也不是标准写法,应该换成int main()。

事实上由于VC6对于C++标准的支持不佳,建议楼主使用dev-C++/Code::Blocks + MinGW的组合,或者使用VC++ 2005/2008这样的新版本,可以少犯不少的错误。(但是要小心M$使用C++/CLR劫持标准的行为……)

希望能对楼主有所帮助。 :)

呆呆蜗牛 发表于 2008-1-26 02:13:21

在VC6上的测试结果:

楼主的原程序运行结果:

4669504 fred
4669496 barney
4669488 wilma
4669480 betty
16

确实是8字节呢,不过楼主发现没有,这个8字节是反的!即后续元素的地址反而在前面!而且barney和wilma可是差了16个字节呢!

可见VC6所使用的常量字符串存储格局与gcc是不同的,我认为它把这个常量字符串数组中的每一个元素的实际存储区域都设置为最小可用的2的幂次个,如fred是4个字节,连上终结符是5个字节,最接近的是2的立方8,而最长的字符串barney连上终结符是7个字节,占用空间16字节的原因可能是在字符串间有其它填充物。这些元素采用了栈结构来存储,所以定义在后的,反而存储在前。

以上内容只是一些推测,我并没有研究过VC6的实际实现(恩,了解一下去),如果有大大是此方面的熟手的话,还请赐教!

楼主认为应该是相差四字节的其实是arr中的指针变量其自身的地址相差的字节数,它们应该是正序的!

将(int)arr替换为&arr,得到结果为:

0012FF70 fred
0012FF74 barney
0012FF78 wilma
0012FF7C betty
16

间隔4个字节!正序!

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

此外注意,替换为(void*)arr的结果为:

00474040 fred
00474038 barney
00474030 wilma
00474028 betty
16

是与楼主的原程序的结果不同的,但实际上做一下十六进制和十进制的转换就可以发现其实还是一样的哈。

而替换为(unsigned int)arr的结果与原程序相同。

但在此还是建议楼主慎重对待指针与整型数间的转换,这是一个很容易掉进去的陷阱,实际上C和C++的标准里面对于这一块的东西,几乎都是“implementation-dependent”的,就是说各个编译器的处理都可能是不同的,尽可能不要依赖于这方面的特性。

august 发表于 2008-1-26 10:25:54

雖然還不是很懂,
不過非常感謝這么詳細的回答!

呆呆蜗牛 发表于 2008-1-26 12:22:00

简单的说就是,楼主的程序输出的是“指针变量所指的地址”(虽然有转换上的问题),其间隔是不一定的,楼主看到差8个字节,是VC6的内存布局造成的,不同的编译器结果不同。

而在这个指针数组中,“指针变量自身的地址”,间隔才是一定的,为4个字节。
页: [1]
查看完整版本: 地址問題