分享
 
 
 

[文章] 有关char指针的文章一篇

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

[文章] 有关char指针的文章一篇

先看以下代码:

char *p;

p="abc";

你认为是对的吗?

答案:语法上是对的,但不提倡这种写法。

误区1:没有给p分配内存空间就赋值,怎么会是对的呢?

正解:不少人第一眼将这里的p="abc"看成了*p="abc",然后就做出了以上的论断。这是比较笨笨的错误咯:)

看清楚就好啦,其实赋给p的是"abc"的地址。再说,*p="abc"也不对呀,字符串可不能这么赋值。

误区2:这"abcd"哪来的地址,怎么能直接赋给p呢?

正解:先自己试试吧。在2K/XP + VC下运行这段代码,是不会出错的,说明这段代码并无问题。晕吧?猜想的话呢,就是"abcd"不知道被放在了什么地方,然后弄来了一个地址,给了p。

这到底是怎么回事呢?

要知道,这两个语句和char *p="abc"是完全一样的,所以其中的道理也一样。

char *p="abc"曾经迷惑了不少人呀。问问你:p到底是什么类型的?char *?错,是const char *!

也就是说,它所指向的内容是不可改变的。不过要补充的是,a的指向是可以改变的。

所以为了不再引起误会,char *p="abc这种写法是不提倡的。

既然char *p="abcd"被建议写成const char *p="abcd",那么char *p; p="abcd";也应该写成const char *p; p="abcd";

讲来讲去,最后来得看看汇编代码。看完就明白是怎么回事了。(我才发现汇编代码原来这么爽看!VC下,没开编译器优化):

我们重点先看const char *p="abc"和char p[]="abc"有什么不同(都放在main()中声明):

PHP源码:

void main()

{

const char *p="abc";

}

3: const char *p="abc";

00401028 mov dword ptr [ebp-4],offset string "abc" (0041f01c)

void main()

{

char p[]="abc";

}

3: char p[]="abc";

00401028 mov eax,[string "abc" (0041f01c)]

0040102D mov dword ptr [ebp-4],eax

看出差别了吗?上一段ASM用offset取"abc"的地址,然后赋给[ebp-4],也就是p(下同)。

而下一段ASM却转了一个弯,先把"abc"的地址转到寄存器eax,然后再转赋给p。

有疑问了:为什么不和上面的一样,直接用offset?VC是很聪明的(废话,M$的东西呀),不用offset,恐怕就是用不了了。

offset是一条伪指令,在编译的时候就已经把偏移量算好了。offset是无法执行间接寻址的计算的。

说明了什么?

const char *p="abc"中的"abc",在编译期间就已经处理好,要了一块内存,存起来了!在把地址赋给p的时候,就可以直接用offset计算。

而char p[]="abc"中的"abc",是在运行期间动态分配内存给"abc",然后再算出地址,赋给p。hehe,这同时也说明了数组和指针的等价性。

我们再做一次实验,这一次我们把char p[]="abc"放在main()外,并在main()内用一个指针再指向p看看。

PHP源码:

char p[]="abc";

void main()

{

char *t=p;

}

5: char *t=p;

00401028 mov dword ptr [ebp-4],offset p (00421adc)

这回p[]的声明放在main()外,变成了全局变量。结果main()内的t取p的指针的时候,直接用offset可以计算出来。

据小石头所说,字面值,const,static,inline,全局变量都是放在静态数据区的。(但我感觉似乎不是如此,只是全局变量和字符串在编译时就处理好放在一起)

不难发现,p[]被声明成全局变量后,就可以直接用offset计算地址,说明静态数据区是编译时就已经处理好的。

再对照const char *p="abc"的ASM,我们马上想到:"abc"就是被C/C++存在静态数据区中的!它的地址就是"abc"在静态数据区的地址!

弄清了这个,有些问题也就可以想得通了。下面这种用法,看来不能说是错误的了,因为"abc"是在静态数据区的,生存期可以说是整个程序:

PHP源码:

#include "stdio.h"

const char *fun()

{

const char *p="abc";

return p;

}

void main()

{

const char *t=fun();

printf ("%s",t);

}

看ASM:

PHP源码:

5: const char *p="abc";

00401038 mov dword ptr [ebp-4],offset string "%d" (0042001c)

一样也是使用offset计算地址。

C/C++给字符串的待遇真是太好了。为了一个字符串,几乎可以打破所有的指针规则。晕~~~~(完)

附:第一次写这么长的文章,写得挺晕的。本来我的C/C++也不是很纯熟的,ASM也是一知半解,今天在CSDN上为这个问题郁闷了半天,和几个人讨论了一下,最后就写了这么一篇文章。希望大家赏脸看看~~~有错一定要指正啊!最后特别感谢小石头(想飞的菜鸟,骄傲的石头,菜菜,都是他咯),还有小阿哥(就是Kingzeus咯)的帮忙~~~~~~谢谢咯~~~~~~

__________________

小菜虎 -> 菜菜的老虎

骄傲的石头回复:

堆几盘积木,心情好些了,所以再重新写一遍。

关于字符串的这个问题,我一直在心里困惑着。所以呢,昨天就看了一下。

以前回答别人的时候,总是很简单的回答,字符串就是const char *指针,指向它的入口地址。现在想来真是惭愧,虽然这个事实好象已经为大家所接受,甚至没有人探讨过这个问题!所以我相信我的发现对大家大多数是有好处的。

首先请看以下代码

PHP源码:

#include <iostream>

#include <iomanip>

using namespace std;

int main()

{

const char *p = 0;

char *p2 = p;

return 0;

}

以上代码有问题吗? 如果你说没有,请你试一下。很明显,这是有问题的。const是为了保证不变性,而你把他变成non const,肯定有错误或者警告,要么就要用const_cast转换。

所以上面的代码不能通过编译。

那么这就很明显的在lee的post里出现了问题,当然我以前也一直是这么认为,甚至很多人都是这么认为。难道这是编译器对字符串的特殊处理吗? 还是其他的原因?

于是我想看看究竟。就动用了RTTI,我飞快的键入了以下代码。

PHP源码:

#include <iostream>

#include <iomanip>

using namespace std;

int main()

{

cout << typeid("abc").name() << endl;

return 0;

}

你说结果是什么?

是char [4]!而不是const char *;

好,这个结果解决了我心中的疑点,原来是这样!这可以很简单的解释char *p = "abc"这个问题。 数组是一个char *const 指针,当然可以赋给char *指针而不会影响其常量性。所以这是完全正确的赋值。

其实这想起来也很平常,指针是没有分配空间的地址而已,而数组是一种容器,占用连续的储存空间。想想字符串就该知道它是一个数组!而不是指针!真正意义上的指针只能是地址,而它在分配了连续的空间后可以作为数组来使用,这是由于他们的共性而决定的。

哈哈!心情愉快,所以也接着看了下lee上面所做的探讨。字符串是放在静态储存区没错,毫无疑问。至于位置~ 偶不想多说,lee在上面分析了很多。所以我只对它进行了一下简单的测试。

我手头上只有dev c++ 和 vc70编译器,所以就只用他们进行了测试。(打开了全部优化)

PHP源码:

#include <iostream>

#include <iomanip>

using namespace std;

int main()

{

char *p = "abc"

char *p2 = "abc";

p[1] = 'k';

p2[1] = 'j'

cout << p1 << endl;

cout << p2 << endl;

return 0;

}

结果呢?在dev c++下报错, 原因我想可能是因为在dev c++在对静态储存区进行了保护。而vc70下,通过,并且两个输出是不同的。所以偶去看vc70产生的msil码,原来vc70每次处理字符串都在静态区分配了空间,而且这两个"abc"是连续分配的!这里就没有出现Solmyr说的那种情况。我想一般比较好的编译器也应该这么说。至于vc60,偶没有测试,但是可能Solmyr说的情况会出现吧。但这样是不好的,相信这样会出现很多微妙的情况。

所以,引用字符串的最佳格式是const char *指针,但char *指针是完全没错的。于情于理,也说的过去吧

如果你还要问,那用指针接受数组呢? 呵呵,你该仔细看看前面了。相信这会给你帮助。

__________________

不可一日无酒无肉无女人

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有