指针的一些问题
1、c++/c語言中不少地方,數組和指針可以相互替換使用,容易讓人產生一種錯覺,指針和數組是等價的。
數組要么在靜態存儲區域創建,如全局數組;要么在棧上創建如函數內的數組。數組的名稱對應著(而不是指向)一塊內存,它的地址和容量在其生命周期內保持不變,數組的內容可變。
指針可以指向任意類型的內存塊,它的特征是可變的,所以常常用指針來操作動態內存,指針比數組靈活,當時容易出錯。
char a[] = "hello"; a[0] = 'x'; cout<<a<<endl; char *p = "world"; //這里的p指向的是常量字符串 p[0] = 'x'; //編譯器不能發現該錯誤 cout<<p;如上邊一段代碼,a是容量為6的字符數組,a中的內容是可以改變的,如a[0]='x'。指針p指向的是一個常量字符串“world”(位于靜態存儲區),常量字符串的內容是不能夠被修改的。但是從語法的角度看,編譯器并不知道p[0]='x'有什么問題,但是該語句在企圖執行時,就會出錯。
char a[] = "hello"; char *p = "world"; cout<<sizeof(a)<<endl; //6 cout<<sizeof(p)<<endl; //4 cout<<sizeof(char *)<<endl; // 4 cout<<sizeof(void *)<<endl; //4 cout<<sizeof(int *)<<endl; //4 cout<<sizeof(short *)<<endl; //4?
另外指針和數組的容量計算也是有區別的。以上一段代碼為例,sizeof(a)的值為6,但是sizeof(p)的值為4,這是因為sizeof(a)可以計算出數組的字節數,但是sizeof(p)得到的是一個指針變量的字節數,相當于sizeof(char *),而不是p所指向的內存容量。c++、c語言是沒有辦法知道指針所指向的內存容量,除非在申請內存時記住。
?
void test(char p[100]) {cout<<sizeof(p)<<endl;//4 }?
注意:當數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針。如上邊的代碼,sizeof(p)的大小為4。
2、指針參數傳遞內存
void GetMemory(char *p) {p = (char *)malloc(100); }int main() {char *str = NULL;GetMemory(str);strcpy(str,"hello");printf("%s",str); //運行出錯free(str); }這段代碼運行出錯,原因出自函數Getmemory中。編譯器總是要為函數的每個參數制作臨時副本,指針參數p的副本是_p,編譯器使_p=p。如果函數體內的程序修改了_p的內容,就導致了參數p的內容作相應的修改。這就是指針可以用作輸出參數的原因。但是在本例中,_p申請了新的內存,只是把_p所指向的內存地址改變了,但是p絲毫未變。所以函數GetMemory并不能輸出任何東西,每次執行一次GetMemory就會泄露一塊內存。因為沒有執行free釋放內存。
void GetMemory2(char **p,int num) {*p = (char *)malloc(num); }如果一定要使用指針參數去申請內存,那么可以使用指向指針的指針,如上邊的代碼。當然也可以使用函數返回值來傳遞動態內存,如:
char *GetMemory3(int num) {char *p = (char *)malloc(num);return p; }但是值得注意的是,我們這里使用返回值返回的是動態分配的堆內存,不是棧內存,如果不小心返回的是棧內存,就會出錯,因為在函數結束時,棧內存自動消亡了。
char *GetMemory4() {char p[] ="hello world!"return p; //編譯器會發出警告 }對上邊的程序稍作修改
char *GetMemory5() {char *p ="hello world!"return p; }這時候p指向的是字符串常量,位于靜態存儲區,生命周期恒定不變,那么此時返回的是一個只讀的內存塊。
?
3、結構體的存儲分配
struct Align1 {int a;char b;char c; }; struct Align2 {char b;int a;char c; };如上邊所示兩個結構體的數據元素一樣,但是位置順序不同,那么他們占用的內存大小不同。在32位機器中整型4個字節,并且他的起始存儲位置必須能夠被4整除。所以以上兩個結構體在內存中分配如圖所示
編譯器按照成員列表的順序一個接著一個的給每個成員分配內存。只有當成員之間滿足正確的對齊要求時,成員之間才會出現用于填充的額外內存空間。有些時候,我們有充分的理由決定不對數據結構成員進行重排,減少因邊界對齊帶來的空間損失。例如,我們可能想把相關的結構成員存儲到一起,提高程序的可維護性和可讀性。但是,如果不存在這樣的理由,結構成員應該根據他們的邊界進行重排,減少因為邊界對齊而造成的內存損失。當程序創建幾百個甚至上千個結構時,減少內存浪費的要求就比程序的可讀性更為緊迫了。在這種情況下,在聲明中增加注釋可以彌補可讀性方面的損失。
運行結果:
?
?
?
轉載于:https://www.cnblogs.com/newpanderking/p/3825417.html
總結
- 上一篇: HDOJ 4253 Two Famous
- 下一篇: zoj2008 最短路