[C/C++]C語言中字符串常量存儲在哪里

常量存儲總結

局部變量畦贸、靜態(tài)局部變量八堡、全局變量碍扔、全局靜態(tài)變量、字符串常量以及動態(tài)申請的內存區(qū)

1秕重、局部變量存儲在棧中
2不同、全局變量、靜態(tài)變量(全局和局部靜態(tài)變量)存儲在靜態(tài)存儲區(qū)
3溶耘、new申請的內存是在堆中
4二拐、字符串常量也是存儲在靜態(tài)存儲區(qū)

  • 棧中的變量內存會隨著定義所在區(qū)間的結束自動釋放;而對于堆凳兵,需要手動free百新,否則它就一直存在,直到程序結束庐扫;
  • 對于靜態(tài)存儲區(qū)饭望,其中的變量常量在程序運行期間會一直存在,不會釋放形庭,且變量常量在其中只有一份拷貝铅辞,不會出現(xiàn)相同的變量和常量的不同拷貝。

關于字符串常量萨醒,下面有篇文章解釋的很清晰:

char *c="hello world";

書上說:"hello world"這個字符串被當作常量而且被放置在此程序的內存靜態(tài)區(qū)斟珊。
c為一個字符型指針,若為局部變量富纸,則存儲在棧內囤踩,該指針變量里面存了個地址,

該地址為字符串中第一個字母h的地址晓褪。
當使用printf()輸出時堵漱,格式化時選擇%s,會輸出hello world涣仿,這是printf()遇到結尾符號'\0'即停止顯示打印勤庐。

字符串"hello world"是個常量,存儲在一片連續(xù)的內存中,末尾有結尾符表示字符串的結束埃元。

那一般的int i=1;

所有的字符竄常量都被放在靜態(tài)內存區(qū)
因為字符串常量很少需要修改涝涤,放在靜態(tài)內存區(qū)會提高效率

char str1[] = "abcd";
char str2[] = "abcd";

const char str3[] = "abcd";
const char str4[] = "abcd";

const char *str5 = "abcd";
const char *str6 = "abcd";

char *str7 = "abcd";
char *str8 = "abcd";


cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;

結果是:0 0 1 1
str1,str2,str3,str4是數(shù)組變量媚狰,它們有各自的內存空間岛杀;字符數(shù)組作為局部變量被存儲在棧區(qū);
而str5,str6,str7,str8是指針崭孤,它們指向相同的常量區(qū)域类嗤。"abcd"被存儲在靜態(tài)數(shù)據區(qū),而且是全局的辨宠,

問題的引入:
看看下面的程序的輸出:

#include <stdio.h>
char *returnStr()
{
char *p="hello world!";
return p;
}
int main()
{
char *str=NULL;//一定要初始化遗锣,好習慣
str=returnStr();
printf("%s\n", str);

return 0;
}
 

這個沒有任何問題,因為"hello world!"是一個字符串常量嗤形,存放在靜態(tài)數(shù)據區(qū)精偿,
把該字符串常量存放的靜態(tài)數(shù)據區(qū)的首地址賦值給了指針,
所以returnStr函數(shù)退出時赋兵,該該字符串常量所在內存不會被回收笔咽,故能夠通過指針順利無誤的訪問。

但是霹期,下面的就有問題:

#include <stdio.h>
char *returnStr()
{
char p[]="hello world!";
return p;
}
int main()
{
char *str=NULL;//一定要初始化叶组,好習慣
str=returnStr();
printf("%s\n", str);

return 0;
}

"hello world!"是一個字符串常量,存放在靜態(tài)數(shù)據區(qū)历造,沒錯甩十,
但是把一個字符串常量賦值給了一個局部變量(char []型數(shù)組),該局部變量存放在棧中吭产,
這樣就有兩塊內容一樣的內存侣监,也就是說char p[]="hello world!";這條語句讓"hello world!"這個字符串在內存中有兩份拷貝,一份在動態(tài)分配的棧中臣淤,另一份在靜態(tài)存儲區(qū)达吞。這是與前者最本質的區(qū)別,
returnStr()函數(shù)退出時荒典,棧要清空酪劫,局部變量的內存也被清空了,
所以這時的函數(shù)返回的是一個已被釋放的內存地址寺董,所以打印出來的是亂碼覆糟。

如果函數(shù)的返回值非要是一個局部變量的地址,那么該局部變量一定要申明為static類型遮咖。如下:

static 主要是為了限定范圍用的滩字。

#include <stdio.h>
char *returnStr()
{
static char p[]="hello world!";
return p;
}
int main()
{
char *str=NULL;
str=returnStr();
printf("%s\n", str);

return 0;
}

這個問題可以通過下面的一個例子來更好的說明:

#include <stdio.h>
//返回的是局部變量的地址,該地址位于動態(tài)數(shù)據區(qū),棧里
char *s1()
{
char* p1 = "qqq";//為了測試‘char p[]="Hello world!"’中的字符串在靜態(tài)存儲區(qū)是否也有一份拷貝
char p[]="Hello world!";
char* p2 = "w";//為了測試‘char p[]="Hello world!"’中的字符串在靜態(tài)存儲區(qū)是否也有一份拷貝
printf("in s1 p=%p\n", p);
printf("in s1 p1=%p\n", p1);
printf("in s1: string's address: %p\n", &("Hello world!"));
printf("in s1 p2=%p\n", p2);
return p;
}

//返回的是字符串常量的地址,該地址位于靜態(tài)數(shù)據區(qū)
char *s2()
{
char *q="Hello world!";
printf("in s2 q=%p\n", q);
printf("in s2: string's address: %p\n", &("Hello world!"));
return q;
}

//返回的是靜態(tài)局部變量的地址奇昙,該地址位于靜態(tài)數(shù)據區(qū)
char *s3()
{
static char r[]="Hello world!";
printf("in s3 r=%p\n", r);
printf("in s3: string's address: %p\n", &("Hello world!"));
return r;
}

int main()
{
char *t1, *t2, *t3;
t1=s1();
t2=s2();
t3=s3();

printf("in main:");
printf("p=%p, q=%p, r=%p\n", t1, t2, t3);

printf("%s\n", t1);
printf("%s\n", t2);
printf("%s\n", t3);

return 0;
}

運行輸出結果:

in s1 p=0013FF0C
in s1 p1=00431084
in s1: string's address: 00431074
in s1 p2=00431070
in s2 q=00431074
in s2: string's address: 00431074
in s3 r=00434DC0
in s3: string's address: 00431074
in main:p=0013FF0C, q=00431074, r=00434DC0
$
Hello world!
Hello world!

這個結果正好應證了上面解釋夜涕,同時,還可是得出一個結論:
字符串常量享钞,之所以稱之為常量,因為它可一看作是一個沒有命名的字符串且為常量诀蓉,存放在靜態(tài)數(shù)據區(qū)栗竖。
這里說的靜態(tài)數(shù)據區(qū),是相對于堆渠啤、棧等動態(tài)數(shù)據區(qū)而言的狐肢。
靜態(tài)數(shù)據區(qū)存放的是全局變量和靜態(tài)變量,從這一點上來說沥曹,字符串常量又可以稱之為一個無名的靜態(tài)變量份名,
因為"Hello world!"這個字符串在函數(shù) s1和s2 中都引用了,但在內存中卻只有一份拷貝妓美,這與靜態(tài)變量性質相當神似僵腺。

另外還有個實驗:

#include <stdio.h>  
#include <stdlib.h>  
#include <math.h>  
int main() 
{ 
 
    char *b; 
    char *c; 
    char a[]="hello world"; 
    b="hello world"; 
    c="hello world"; 
    printf("%d,%d,%d,%d\n",b,a,c,&("hello world")); 
} 

實驗結果為:

4282272,1244988,4282272,4282272

對了,字符常量'a'

sizeof('a')

為4部脚,及一個字長想邦。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市委刘,隨后出現(xiàn)的幾起案子丧没,更是在濱河造成了極大的恐慌,老刑警劉巖锡移,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呕童,死亡現(xiàn)場離奇詭異,居然都是意外死亡淆珊,警方通過查閱死者的電腦和手機夺饲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來施符,“玉大人往声,你說我怎么就攤上這事〈亮撸” “怎么了浩销?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長听哭。 經常有香客問我慢洋,道長塘雳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任普筹,我火速辦了婚禮败明,結果婚禮上,老公的妹妹穿的比我還像新娘太防。我一直安慰自己妻顶,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布杏头。 她就那樣靜靜地躺著盈包,像睡著了一般沸呐。 火紅的嫁衣襯著肌膚如雪醇王。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天崭添,我揣著相機與錄音寓娩,去河邊找鬼。 笑死呼渣,一個胖子當著我的面吹牛棘伴,可吹牛的內容都是我干的。 我是一名探鬼主播屁置,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼焊夸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蓝角?” 一聲冷哼從身側響起阱穗,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎使鹅,沒想到半個月后揪阶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡患朱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年鲁僚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裁厅。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡冰沙,死狀恐怖,靈堂內的尸體忽然破棺而出执虹,到底是詐尸還是另有隱情拓挥,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布声畏,位于F島的核電站撞叽,受9級特大地震影響姻成,放射性物質發(fā)生泄漏。R本人自食惡果不足惜愿棋,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一科展、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧糠雨,春花似錦才睹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至松邪,卻和暖如春坞琴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背逗抑。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工剧辐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邮府。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓荧关,卻偏偏與公主長得像,于是被迫代替她去往敵國和親褂傀。 傳聞我的和親對象是個殘疾皇子忍啤,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容