日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解const char*p,char const*p,char *const p,const char **p,char const**p,char *const*p,char**const

發(fā)布時間:2023/12/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解const char*p,char const*p,char *const p,const char **p,char const**p,char *const*p,char**const 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
原文網(wǎng)址:http://www.cnblogs.com/rushuizhijing/archive/2011/08/26/2154737.html

深入理解const char*p,char const*p,char *const p,const char **p,char const**p,char *const*p,char**const p

一、可能的組合:

(1)const char*p

(2)char const*p

(3)char *const p
(4)const char **p

(5)char const**p

(6)char *const *p

(7)char **const p

當然還有在(5)、(6)、(7)中再插入一個const的若干情況,不過分析了以上7中,其他的就可類推了!

二、理解助記法寶:

1。關(guān)鍵看const 修飾誰。

2。由于沒有?const *的運算,若出現(xiàn)?const *?的形式,則const實際上是修飾前面的。

比如:char const*p,由于沒有const*運算,則const實際上是修飾前面的char,因此char const*p等價于const char*p。也就是說上面7種情況中,(1)和(2)等價。 同理,(4)和(5)等價。在(6)中,由于沒有const*運算,const實際上修飾的是前面的char*,但不能在定義時轉(zhuǎn)換寫成 const(char *)*p,因為在定義是"()"是表示函數(shù)。

三、深入理解7種組合

(0)程序 在執(zhí)行時為其開辟的空間皆在內(nèi)存(RAM)中,而RAM里的內(nèi)存單元是可讀可寫 的;指針只是用來指定或定位要操作的數(shù)據(jù)的工具,只是用來讀寫RAM里內(nèi)存單元的工作指針 。若對指針不加任何限定,程序中一個指針可以指向RAM中的任意位置(除了系統(tǒng)敏感區(qū),如操作系統(tǒng)內(nèi)核所在區(qū)域)并對其指向的內(nèi)存單元進行讀和寫操作(由RAM的可讀可寫屬性決定);RAM里內(nèi)存單元的可讀可寫屬性不會因為對工作指針的限定而變化(見下面的第4點),而所有對指針的各種const限定說白了只是對該指針 的 讀寫權(quán)限 (包括讀寫位置)進行了限定?。


(1)char *p:p是一個工作指針,可以用來對任意位置?(非系統(tǒng)敏感區(qū)域)進 行讀操作和寫操作 ,一次讀寫一個字節(jié)(char占一個字節(jié))。
(2)const char*p或者char const *p(因為沒有const*p運算,因此const修飾的還是前面的char):可以對任意位置(非系統(tǒng)敏感區(qū)域)進行“只讀” 操作。(“只讀”是相對于char *p來說所限定的內(nèi)容)
(3)char *const p(const 修飾的是p):只能對“某個固定的位置” 進 行讀寫操作,并且在定義p時就必須初始化(因為在后面不能執(zhí)行“p=..”的操作,因此就不能在后面初始化,因此只能在定義時初始化)。(“某個固定的位 置”是相對于char *p來說所限定的內(nèi)容)
可以總結(jié)以上3點為:char *p中的指針p通常是”萬能”的工作指針 ,而(2)和(3)只是在(1)的基礎(chǔ)上加了些特定的限制 ,這些限制在程序中并不是必須的,只是為了防止程序員的粗心大意而產(chǎn)生事與愿違的錯 誤。
另外,要明白“每塊內(nèi)存空間都可有名字;每塊內(nèi)存空間內(nèi)容皆可變(除非有所限) ” 。比如函數(shù)里定義的char s[]="hello";事實上在進程的棧內(nèi)存里開辟了6個變量共6個字節(jié)的空間,其中6個字符變量的名字分別為:s1[0]、s1[1]、 s1[2]、s1[3]、s1[4]、s1[5](內(nèi)容是'\0')

{

待驗證 : 還有一個4字節(jié)的指針變量s 。不過s是“有所限制”的,屬于char *const類型,也就是前面說的 (3)這種情況,s一直指向s[0], 即(*s==s[0]=='h'),可以通過*s='k'來改變s所指向的 s[0]的值,但不能執(zhí)行(char *h=“aaa”;s=h;)來對s另外賦值。

}

(4)上面的(2)和(3)只是對p進行限定,沒有也不能對p所指向的空間進行限定,對于"char s[]="hello";const char*p=s;" 雖然不能通過*(p+i)='x'或者p[i]='x'來修改數(shù)組元素s[0]~s[4]的值,但可以通過*(s+i)='x'或者s[i]='x'來修改原數(shù)組元素的值--RAM里內(nèi)存單元的可讀可寫屬性不因?qū)ぷ髦羔樀南薅ǘ淖?#xff0c;而只會因?qū)ζ浔旧淼南薅ǘ淖儭H鏲onst char c=‘A’,c是RAM里一個內(nèi)存單元(8字節(jié))的名字,該內(nèi)存單元的內(nèi)容只可讀,不可寫。

(5)const char **p或者char const**p :涉及兩個指針p和 *p。由于const修飾char ,對指針p沒有任何限定,對指針*p進行了上面情況(2)的限定。

(6)char *const *p:涉及兩個指針p和 *p。由于const修飾前面的char*,也就是對p所指向的內(nèi)容*p進行了限定(也屬于前面的情況(2))。而對*p來說,由于不能通過"*p=..."來進行另外賦值,因此屬于前面的情況(3)的限定。

(7)char **const p : 涉及兩個指針p和 *p,const修飾p,對p進行上面情況(3)的限定,而對*p,沒有任何限定。

四、關(guān)于char **p 、const char **p的類型相容性問題

1。問題

char *p1;const *p2=p1;//合法

char **p1;const char**p2=p1;//不合法,會有警告warning: initialization from incompatible pointer type

char **p1;char const**p2=p1;//不合法,會有警告warning: initialization from incompatible pointer type

char**p1;char*const*p2=p1;//合法

2。判斷規(guī)則

明確const修飾的對象!對于指針p1,和p2,若要使得p2=p1成立,則可讀做 :

“p1是指向X類型的指針,p2是指向“帶有const限定”的X類型的指針 “。只要二者的X類型一樣,就是合法的

char *p1;const *p2=p1;//合法:p1是指向(char)類型的指針,p2是指向“帶有const限定"的(char)類型的指針。

char **p1;const char**p2=p1;//不合法:p1是指向(char*)類型的指針,p2是指向 ((const char)*)類型的指針。

char **p1;char const**p2=p1;//不合法;與上等價。

char**p1;char*const*p2=p1;//合法: p1是指向(char *)類型的指針,p2是指向“帶有const限定"的(char*)類型的指針。

五、其他

1。 含有const的單層或雙層指針的統(tǒng)一讀法:

“p是一個指針,是一個[“帶有const限定”的]指向[”帶有const限定”的]X類型的指針”。

l例如:const char* const *p就是說:p是一個帶有const限定的指向帶有const限定的(char*)類型的指針。

2。定義時const修飾的對象是確定的,但不能在定義時加括號,不然就和定義時用“()”表示的函數(shù)類型相混淆了!因此定義時不能寫(char *)const *p或者(const char) **p。

六、問題探討(由于博文后的留言有字符數(shù)目限制,將回復(fù)移到這里)

問題1 (見博文后留言):講解非常好,不過有個問題想探討下: 例如: const char wang[]={"wang"}; char *p; p=wang; 是錯誤的。 所以char *p中的P不能指向常變量。 (1)需要補充糾正。

回復(fù) : 你好!謝謝指正!我在ubuntu 10.04(gcc 4.4.3)下做了如下測試:?
//test_const.c
#include<stdio.h>
int main()
{
const char wang[]={"wang"};
char *p;
p=wang;
p[2]='c';
printf("p is %s\n",p);
return 0;
}
編譯 :

gcc -o test_const test_const.c
輸出如下 :
test_const.c: In function ‘main’:
test_const.c:17: warning: assignment discards qualifiers from pointer target type
執(zhí)行:

./test_const
p is wacg
結(jié)論: 根據(jù)本博文中第四點--相容性問題,將const型的wang賦值給p是不合法的。但編譯器對其的處理只是警告,因此執(zhí)行時通過p修改了只讀區(qū)域的數(shù)據(jù)。這應(yīng)該是該編譯器處理不嚴所致后果,不知你用的什么編譯器?

問題2 回答?http://www.linuxsir.org/bbs/showthread.php?t=239058?提到的問題

在c語言里

// test.c
int main() {
const char* s1 = "test";
char *s2 = s1;
s2 = "It's modified!";
printf("%s\n",s1);
}
out: It's modified!;
這樣也可以嗎? 照我的理解豈不是const限定符在c語言里只是擺設(shè)一個?

回復(fù):

(1)首先,以上代碼編譯時會出錯warning: initialization discards qualifiers from pointer target type,

因為char *s2 = s1和問題1提到的一樣,不符合相容規(guī)則。


(2)輸出結(jié)果是正確的,代碼分析如下:

int main() {
const char* s1 = "test"; // 在只讀數(shù)據(jù)區(qū)(objdump -h test后的.rodata區(qū))開辟5字節(jié)存儲"test",并用s1指向首字符‘t’。?
char *s2 = s1; // s2也指向只讀數(shù)據(jù)區(qū)中“test”的首字符't'。?
s2 = "It's modified!"; // 在只讀數(shù)據(jù)區(qū)開辟15字節(jié)存儲"It's modified!",并將s2由指向't'轉(zhuǎn)而指向"It's modified!"的首字符'I'。?
printf("%s\n",s1); // 從s1所指的‘t’開始輸出字符串"test"。?
}


(3)總結(jié):提問者的誤區(qū)在于,誤以為s2 = "It's modified!"是對“test”所在區(qū)域的重新賦值,其實這里只是將“萬能”工作指針s2指向另外一個新開辟的區(qū)域而已。比如若在char *s2 = s1后再執(zhí)行s2[2]='a'則是對“test”的區(qū)域進行了寫操作,執(zhí)行時會出現(xiàn)段錯誤。但這個段錯誤其實與const沒有關(guān)系,因為“test”這塊區(qū)域本身就是只讀的。為了防止理解出錯,凡事對于對指針的賦值(比如 s2 = "It's modified!" ),則將其讀做:將s2指向“ It's modified! ”所在區(qū)域的首字符。


(4)額外收獲:執(zhí)行g(shù)cc -o test test.c后,“test”、“It's modified!”、"%s\n"都被作為字符串常量存儲在二進制文件test的只讀區(qū)

域 (.rodata)。事實上,一個程序從編譯到運行,對變量空間分配的情況如下:

A。賦值了的全局變量或static變量=>放在可執(zhí)行文件的.data段。

B。未賦值的全局變量或static變量=>放在可執(zhí)行文件的.bss段。

C。代碼中出現(xiàn)的字符串常量或加了const的A=>放在可執(zhí)行文件的.rodata段。

D。一般的局部變量=>在可執(zhí)行文件中不占空間,在該二進制文件作為進程在內(nèi)存中運行時才為它分配棧空間。

E。代碼中malloc或new出的變量=>在可執(zhí)行文件中不占空間,在該二進制文件作為進程在內(nèi)存中運行時才為它分配堆空間。

問題3:(待進一步分析) 驗證博文中 三(3)提到的是否為s分配空間,初步分析結(jié)果為:不分配!文中的s只是s[0]的地址的代號而已。

#include<stdio.h>
int main() {
int a=3;
char s1[] = "test";
int b=4;
char s2[] ="test2";
printf("the address of a is %u\n",&a);
printf("s1 is %u\n",s1);
printf("the address of s1 is %u\n",&s1);
printf("the address of b is %u\n",&b);
printf("s2 is %u\n",s2);
printf("the address of s2 is %u\n",&s2);
}

輸出結(jié)果:


the address of a is 3213037836
s1 is 3213037827
the address of s1 is 3213037827
the address of b is 3213037832
s2 is 3213037821
the address of s2 is 3213037821


由結(jié)果可以看出,編譯器做了些優(yōu)化。

七、其他相關(guān)經(jīng)典文章轉(zhuǎn)載


王海寧,華清遠見嵌入式學(xué)院講師,對const關(guān)鍵字的理解

http://www.embedu.org/Column/Column311.htm


目前在進行C語言補習(xí)時,發(fā)現(xiàn)很多的同學(xué)對于const這個關(guān)鍵字的理解存在很大的誤解。現(xiàn)在總結(jié)下對這個關(guān)鍵字理解上的誤區(qū),希望在以后的編程中,能夠靈活使用const這個關(guān)鍵字。

1、 const修飾的變量是常量還是變量

對于這個問題,很多同學(xué)認為const修飾的變量是不能改變,結(jié)果就誤認為該變量變成了常量。那么對于const修飾的變量該如何理解那?

下面我們來看一個例子:

int main
{
char buf[4];
const int a = 0;

a = 10;
}

這個比較容易理解,編譯器直接報錯,原因在于“a = 10;”這句話,對const修飾的變量,后面進行賦值操作。這好像說明了const修飾的變量是不能被修改的,那究竟是不是那,那么下面我們把這個例子修改下:

int main
{
char buf[4];
const int a = 0;

buf[4] = 97;
printf(“the a is %d\n”,a);
}

其中最后一句printf的目的是看下變量a的值是否改變,根據(jù)const的理解,如果const修飾的是變量是不能被修改的話,那么a的值一定不會改變,肯定還是0。但是在實際運行的結(jié)果中,我們發(fā)現(xiàn)a的值已經(jīng)變?yōu)?7了。這說明const修飾的變量a,已經(jīng)被我們程序修改了。

那綜合這兩個例子,我們來分析下,對于第二例子,修改的原因是buf[4]的賦值操作,我們知道buf[4]這個變量已經(jīng)造成了buf這個數(shù)組變量的越界訪問。buf數(shù)組的成員本身只有0,1,2,3,那么buf[4]訪問的是誰那,根據(jù)局部變量的地址分配,可以知道buf[4]的地址和int a的地址是一樣,那么buf[4]實際上就是訪問了const int a;那么對buf[4]的修改,自然也修改了const int a的空間,這也是為什么我們在最后打印a的值的時候看到了97這個結(jié)果。

那么我們現(xiàn)在可以知道了,const修飾的變量是不具備不允許修改的特性的,那么對于第一個例子的現(xiàn)象我們又如何解釋那。

第一個例子,錯誤是在程序編譯的時候給出的,注意這里,這個時候并沒有生成可執(zhí)行文件,說明const修飾的變量可否修改是由編譯器來幫我們保護了。而第二個例子里,變量的修改是在可執(zhí)行程序執(zhí)行的時候修改的,說明a還是一個變量。

綜上所述,我們可以得出一個結(jié)論,那就是const修飾的變量,其實質(zhì)是告訴程序員或編譯器該變量為只讀,如果程序員在程序中顯示的修改一個只讀變量,編譯器會毫不留情的給出一個error。而對于由于像數(shù)組溢出,隱式修改等程序不規(guī)范書寫造成的運行過程中的修改,編譯器是無能為力的,也說明const修飾的變量仍然是具備變量屬性的。

2、 被const修飾的變量,會被操作系統(tǒng)保護,防止修改

如果對于第一個問題,有了理解的話,那么這個問題,就非常容易知道答案了。Const修飾的變量是不會被操作系統(tǒng)保護的。

其原因是操作系統(tǒng)只保護常量,而不會保護變量的讀寫。那么什么是常量?比如“hello world”這個字符串就是被稱為字符串常量。

對于這個問題的另一種證明方法,可以看下面這個程序:

int main
{
const int a;
char *buf = “hello world”;

printf(“the &a is %p, the buf is %p\n”,&a, buf);
}

可以發(fā)現(xiàn)buf保存的地址是在0x08048000這個地址附近的,而a的地址是在0xbf000000這個地址附近的,而0x08048000附近的地址在我們linux操作系統(tǒng)上是代碼段。這也說明了常量和變量是存放在不同區(qū)域的,自然操作系統(tǒng)是會保護常量的。

如果我們知道這個道理后,再看下面的題目:

int main
{
char *buf = “hello”;

buf[0] = ‘a(chǎn)’;
printf(“the buf is %s\n”,buf);
}

我們可以思考下,這個程序的運行結(jié)果會是什么呢?

答案是:報錯error :在0x08048000處不可以寫。也就是說os保護常量的的區(qū)域,只能讀不能寫。

總結(jié)

以上是生活随笔為你收集整理的深入理解const char*p,char const*p,char *const p,const char **p,char const**p,char *const*p,char**const的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。