C_C++字符串和字符數組的本質


 

1、 常量字符串

在代碼里直接出現的”abcdef”這種字符串,在程序執行的時候,系統會將它們放在常量區,所謂常量區就是一直存在的,只讀的,不可更改的數據區域,並且一個字符串只會有一份。假設你在程序里有兩行代碼

char* p1 = “agcd” ;

char* p2 = “agcd” ;

無論你這兩個行代碼隔了多遠,如果你想知道p1和p2所指向的字符串在內存中是不是同一個,那答案是肯定的,p1和p2的值完全一樣。”agcd”這是一個存在於內存中的常量字符串,它從程序一開始就在那里,一直到程序結束讀不會改變。在內存中,”agcd”是以如下方式存儲的

‘a’

’g’

‘c’

‘d’

‘\0’

它的最后肯定有一個字符串結束標志’\0’。在種字符串的名字叫“以空字符為結束標志的字符串”。

char* p1 = “agcd” ;

如果你這時候想改變第一個字符的值,用p[0] =’b’,系統會報一個錯,常量字符不能更改。(這里為什么指針可以當數組用,下面再解釋)。

 

2、 字符數組

如果你定義一個char a[10],那么系統會“只分配”10個char這么長的內存區域,一個char是一個字節,那么系統會分配十個字節的內存控件,並且將這一片連續的內存空間的首地址賦值給a。也就是說“數組名的值是數組所在內存區域的首地址”換句話說“數組名是一個指針,指向數組第一個值的地址”。

如果你定義一個char a[] = “abcdefg”;這句代碼就復雜點了。定義一個數組,數組長度未知,那么系統會根據等號后面的值來“初始化”這個數組,等號后面是什么?前面說過,它是一個常量字符串。在內存中占8個字節,7個字符加上一個結束標志。這時候在內存中就有兩個”abcdefg”的字符串了,一個是常量區域的,另一個是根據前者復制了一份的。這句代碼的意思就是復制一個常量區域的字符串,將復制后的字符串的首字母的地址賦值給a。

也就是說,最后a所指向的內存區域,已經不是常量里的”abcdefg”了,這里為什么要復制一份呢?原因是因為常量是不允許更改的,而數組一般都意味着需要修改,所以就復制了一份數據,放在非常量區域,就可以更改了。下面的測試程序可證明上述結論:

      char* p1 = "abcdef" ;

      char* p2 = "abcdef" ;

      char a[]= "abcdef" ;

 

      unsigned long dwP1 = (unsigned long)p1 ;

//32位系統里的指針就是4個字節的整數,這樣可以具體查看指針的值。

      unsigned long dwP2 = (unsigned long)p2 ;

      unsigned long dwA = (unsigned long)a ;

 

      printf("p1的值(32位地址) = 0x%X\n",dwP1);

      //%X是打印十六進制,X是大寫,x是小寫

      printf("p2的值(32位地址) = 0x%X\n",dwP2);

      printf("a的值(32位地址) = 0x%X\n",dwA);

             從上面的結果可看出,常量字符串在內存中只有一份。而賦值給數組的時候,系統會拷貝一份。如果我們打印a[6]會是什么結果呢,請注意,字符串只有6個,最高索引是5。

             printf("a[6]的值=%d",a[6]);//以整數打印

         雖然數組的可用長度是6,但是它第7個位置還是存在的,那就是空字符結束標志。空字符結束標志是必須的,因為很多時候系統並不知道你的字符串有多長。

 

3、 應用

當明白了這些本質后,我們怎么來靈活使用字符數組呢。在實際的編碼中,比如從文件里讀一段文字出來,假設當前文件中的字符串有20個字母。

第一步讀取文件大小。

int fileSize = file.getSize();

第二步,分配緩存。這是動態分配數組。這種用法和java相似。

char* p = new char[fileSize+1] ;//加1是為了后面放’\0’.

第三步,讀取

file.read(p,fileSize);//意思是從文件里讀取filesize個字節,並且放在p所指向的緩存中

第四步,標志結尾

P[fileSize] = ‘\0’; //由於指針指向的是字符串首字母地址,而數組名也是一樣的,所以C/C++里指針和數組幾乎用法一樣。其他語言里不一樣。這也是C/C++的魅力所在,夠靈活。

 

這時候的p所指向的就是一片連續的內存控件,它的內容就是文件里的字符串,並且它的最后有一個結束標志(這樣就可以在系統里靈活使用了)。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM