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

站在巨人肩上的思考[连载] (8)

浏览 3387 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-12-03  
C++
 

5.2 数组

5.2.2 字符串文字量

         类似”this is a string.”这样一个字符串文字量,它是一个常量。正如代码中一个显式的数字0xff08一样,其值不可以被更改。如想修改,可以通过复制给一个变量来实现:

         <v:shapetype id="_x0000_t202" path="m,l,21600r21600,l21600,xe" o:spt="202" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:path o:connecttype="rect" gradientshapeok="t"></v:path></v:shapetype><v:shape id="_x0000_s1034" style="WIDTH: 374.2pt; HEIGHT: 36.05pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin" strokeweight="1pt" strokecolor="#95b3d7" type="#_x0000_t202"><v:fill type="gradient" focus="100%" focussize="" focusposition="1" color2="#b8cce4"></v:fill><v:shadow opacity=".5" type="perspective" offset2="-3pt" offset="1pt" color="#243f60" on="t"></v:shadow><v:textbox>

int a = 0xff08;

a = 0xff18;

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape><v:shapetype id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:spt="75" coordsize="21600,21600" stroked="f" filled="f" o:preferrelative="t"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype>

         对于字符串文字量则有一点要注意:

         <v:shape id="_x0000_s1033" style="WIDTH: 374.2pt; HEIGHT: 72.85pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin" strokeweight="1pt" strokecolor="#95b3d7" type="#_x0000_t202"><v:fill type="gradient" focus="100%" focussize="" focusposition="1" color2="#b8cce4"></v:fill><v:shadow opacity=".5" type="perspective" offset2="-3pt" offset="1pt" color="#243f60" on="t"></v:shadow><v:textbox>

char* cp = “this is a string”;       //危险!赋值给一个普通字符指针;

cp[4] = ‘e’;                     //未定义行为!不能给常量赋值;

char p[] = “this is a string”;        //可以;

p[4] = ‘e’;                      //正确执行;

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

         可以看出,用char *来引用字符串文字量是一个十分危险的地方。在上例中cp[4]=’e’;可以通过编译,但是在执行期间产生了一个Segmentation Fault。也就是说编译器并不能帮助程序员发现这类错误。

我个人是这样认为的:字符串文字量是一中很底层的数据,编译器把他放进汇编语言中的数据段;普通的char*指针也是一种很底层的指针,他可以指向内存空间中的任何地址;char* cp = “this is a string”;仅仅在栈空间生成一个指针,然后把他指向位于数据段的”this is a string”,初始化并不会导致错误。但是利用cp[4]更改数据段中的数据内容将会导致段错误,数据段是只读的。而利用char p[]形式的时候,意味着将在栈空间中生成一个字符数组,然后用”this is a string”来进行初始化,而后p指向这个栈空间中字符数组的首地址。此时p[4]=’e’;修改的是栈空间中的值,而不是数据段中的值。

但是p是什么类型呢?是char*么?他的大小是多少?是1么?为了使指针和数组首地址之间的区别更具普遍意义,我们用int类型来测试一下:

<v:shape id="_x0000_s1032" style="WIDTH: 374.2pt; HEIGHT: 104.65pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin" strokeweight="1pt" strokecolor="#95b3d7" type="#_x0000_t202"><v:fill type="gradient" focus="100%" focussize="" focusposition="1" color2="#b8cce4"></v:fill><v:shadow opacity=".5" type="perspective" offset2="-3pt" offset="1pt" color="#243f60" on="t"></v:shadow><v:textbox>

char p[] = "hello";

char* ptr = p;

cout << sizeof(p) << ":" << sizeof(*p) << endl;

cout << p << ":" << *p << endl;

cout << sizeof(ptr) << ":" << sizeof(*ptr) << endl;

cout << ptr << ":" << *ptr << endl;

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

这段代码在我的电脑上的输出是:

<v:shape id="_x0000_s1031" style="WIDTH: 374.2pt; HEIGHT: 87.2pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin" strokeweight="3pt" strokecolor="#f2f2f2 [3041]" type="#_x0000_t202" fillcolor="black [3200]"><v:shadow opacity=".5" type="perspective" offset2="-1pt" offset="1pt" color="#7f7f7f [1601]" on="t"></v:shadow><v:textbox style="mso-next-textbox: #_x0000_s1031">

[/home/gavin/test]# ./test

6:1

hello:h

4:1

hello:h

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

ptr是真正的char*类型,其sizeof4,但是psizeof却是6,也就是”hello”加一个‘\0’的长度。除此之外,ptrp表现都一样。但我们最好认为p是字符数组类型,而ptr才是字符指针类型,因为他们的行为上存在差异。很多教师、教材都说:“数组名就是指向数组首地址的指针。”这其实并不完全正确。

再仔细看看,我们cout<<pcout<<ptr的期望输出应该是pptr分别表示的地址。但事实上却是数组的内容。为了明显区分,再看下面这段代码:

<v:shape id="_x0000_s1030" style="WIDTH: 374.2pt; HEIGHT: 104.65pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin" strokeweight="1pt" strokecolor="#95b3d7" type="#_x0000_t202"><v:fill type="gradient" focus="100%" focussize="" focusposition="1" color2="#b8cce4"></v:fill><v:shadow opacity=".5" type="perspective" offset2="-3pt" offset="1pt" color="#243f60" on="t"></v:shadow><v:textbox>

int arr[4] = {0};

int* pa = arr;

cout << sizeof(arr) << ":" << sizeof(*arr) << endl;

cout << arr << ":" << *arr << endl;

cout << sizeof(pa) << ":" << sizeof(*pa) << endl;

cout << pa << ":" << *pa << endl;

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

在我的电脑上输出为:

<v:shape id="_x0000_s1029" style="WIDTH: 374.2pt; HEIGHT: 87.2pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin" strokeweight="3pt" strokecolor="#f2f2f2" type="#_x0000_t202" fillcolor="black"><v:shadow opacity=".5" type="perspective" offset2="-1pt" offset="1pt" color="#7f7f7f" on="t"></v:shadow><v:textbox style="mso-next-textbox: #_x0000_s1029">

[/home/gavin/test]# ./test

16:4

0xbfc26e5c:0

4:4

0xbfc26e5c:0

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

sizeof的输出刚才已经说过。这里可以看出,int数组名和char数组名的行为也不一样。事实上,cha数组名与标准类型数组名的行为都不一样。这也就是为什么C风格字符串为许多人诟病的地方。

C++在这方面提供了很好的改进:用一种更上层的类型string来代替C风格字符串。并强烈建议程序员在程序中尽量使用string来代替char *。这里是你需要做出选择的地方:

<v:shape id="_x0000_s1028" style="WIDTH: 374.2pt; HEIGHT: 180.35pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin" strokeweight="1pt" strokecolor="#95b3d7" type="#_x0000_t202"><v:fill type="gradient" focus="100%" focussize="" focusposition="1" color2="#b8cce4"></v:fill><v:shadow opacity=".5" type="perspective" offset2="-3pt" offset="1pt" color="#243f60" on="t"></v:shadow><v:textbox>

string str1("1");

string str2("1234567");

string str3("1234567890123456789012345678901234567890");

/*

char str1[] = "1";

char str2[] = "1234567";

char str3[] = "1234567890123456789012345678901234567890";

*/

cout << sizeof(str1) << endl;

cout << sizeof(str2) << endl;

cout << sizeof(str3) << endl;

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

当利用C风格字符串的输出为:

<v:shape id="_x0000_s1027" style="WIDTH: 374.2pt; HEIGHT: 123pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin; mso-left-percent: -10001; mso-top-percent: -10001; mso-position-horizontal: absolute; mso-position-vertical: absolute" strokeweight="3pt" strokecolor="#f2f2f2" type="#_x0000_t202" fillcolor="black"><v:shadow opacity=".5" type="perspective" offset2="-1pt" offset="1pt" color="#7f7f7f" on="t"></v:shadow><v:textbox style="mso-next-textbox: #_x0000_s1027">

[/home/gavin/test]# ./test

2

8

41

[/home/gavin/test]# ls -l

-rwxrwxr-x 1 863 863    6559 Dec  3 14:29 test

-rw-rw-r-- 1 863 863     391 Dec  3 14:29 test.cpp

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

而当使用string时:

<v:shape id="_x0000_s1026" style="WIDTH: 374.2pt; HEIGHT: 123pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line; mso-width-relative: margin; mso-height-relative: margin; mso-left-percent: -10001; mso-top-percent: -10001; mso-position-horizontal: absolute; mso-position-vertical: absolute" strokeweight="3pt" strokecolor="#f2f2f2" type="#_x0000_t202" fillcolor="black"><v:shadow opacity=".5" type="perspective" offset2="-1pt" offset="1pt" color="#7f7f7f" on="t"></v:shadow><v:textbox style="mso-next-textbox: #_x0000_s1026">

[/home/gavin/test]# ./test

4

4

4

[/home/gavin/test]# ls -l

-rwxrwxr-x 1 863 863    7578 Dec  3 14:30 test

-rw-rw-r-- 1 863 863     390 Dec  3 14:30 test.cpp

</v:textbox><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

我们也许可以得到如下结论:stingchar[]需要更少的运行时内存空间,但是char[]却比string占用更少的磁盘空间。你可以自己选择向左还是向右走。不过相比string的易用性、安全性、以及诸多的成员函数带来的实用功能来说,我个人并不认为char[]节省的磁盘空间是很突出的优点。

论坛首页 编程语言技术版

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