从getmemery()函数看内存管理、函数传参等一系列问题
在C 面試題目中,會經常出現getmemery()函數的改錯題,比如下面這道題,
例一:代碼如下:
[cpp]?view plaincopy
咱們先執行一下,先不管編譯時會出現什么錯誤,執行結果如下:
可以看到執行結果是一段亂碼,而不是想象中的 hello world!
為什么會出現這種結果,在編譯是就能看到,編譯時出現了警告如下:
警告:函數返回局部變量的地址;函數返回局部變量的地址會產生什么后果呢
我們知道,局部變量存儲在棧區,在代碼塊執行前申請一片內存,執行完畢后,這塊內存即被釋放;*getmemery()函數是個指針型函數,指針型函數返回的是一個指針,就是返回的是一個地址,但是指針型函數要注意的是,其返回的地址必須是函數調用結束后依然存在的存儲單位地址;而此處p[]是局部變量,其返回的地址p在函數調用結束后已經不存在了,所以執行是會出現亂碼!先看看如何更改會正確,代碼如下:
[cpp]?view plaincopy
執行結果如下:
執行結果正確!
看看代碼,只是將p[] = "hello world!"改成了*p = "hello world!",結果卻不同呢! 將字符串賦給數組和指針有什么區別呢?
一個字符串,如"hello world!",一般為字符串常量,既然是常量,存儲在常量區,常量的生存周期是伴隨著整個程序的,可以用它對字符指針賦值,或初始化,相當于把這個字符串常量的首地址賦給這個指針,正如上面代碼中 char *p="hello world!";
但是,當用"hello world!"給字符數組作初始化時,這里的"hello world!",并非一個字符串常量,只是復制了一份放在數組里,而是相當于一個初始化列表{'h','e','l','l','o',' ','w','o','r','l','d','\0'},在其他任何時候,他對表示一個字符串常量。而數組名也是一個指針常量,不能對常量賦值。所以char p[]="hello world!"正確,而char p[12]; p="hello world!"錯誤,p為指針常量,不能修改,當然也不能賦值!
回到剛才的兩段代碼,結果的差別便區別在上述論述中!
當然,我們也可以這樣改:
[cpp]?view plaincopy
仍能得到正確結果!
static的作用在這里先不詳解,但C語言面試中,經常會考察static的作用,static的作用簡單說就兩種:(1)限制變量的作用域;(2)限制變量的生存周期;
所以上述代碼中用static 修飾p[],使p[]此時不是存儲在棧區,而是存儲在靜態存儲區,生存周期是整個程序的開始到結束!
例二:下面再給出一個getmemery()函數的改錯題,代碼如下:
[cpp]?view plaincopy
我們先對代碼進行編譯,并沒有錯誤與警告,執行結果如下:
段錯誤 (核心已轉存儲),這個錯誤在前面的文章中提到過,現在再解釋一下;
一 般來說,段錯誤就是指訪問的內存超出了系統所給這個程序的內存空間,通常這個值是由gdtr來保存的,他是一個48位的寄存器,其中的32位是保存由它指 向的gdt表,后13位保存相應于gdt的下標,最后3位包括了程序是否在內存中以及程序的在cpu中的運行級別,指向的gdt是由以64位為一個單位的 表,在這張表中就保存著程序運行的代碼段以及數據段的起始地址以及與此相應的段限和頁面交換還有程序運行級別還有內存粒度等等的信息。一旦一個程序發生了 越界訪問,cpu就會產生相應的異常保護,于是segmentation fault就出現了. ?在編程中以下幾類做法容易導致段錯誤,基本是是錯誤地使用指針引起的
? ?1)訪問系統數據區,尤其是往 系統保護的內存地址寫數據 ? ?最常見就是給一個指針以0地址?
? ?2)內存越界(數組越界,變量類型不一致等)
? ?3) 訪問到不屬于你的內存區域 ?
這段文字是復制別人的,我們先來解決問題,從上述描述中,問題還是出在錯誤的使用指針:
(1)訪問系統數據區,尤其是往 系統保護的內存地址寫數據 ? ?最常見就是給一個指針以0地址?
這里并不是這個原因
(2)內存越界(數組越界,變量類型不一致等)
這里我們給其分配的大小是足夠的
(3) 訪問到不屬于你的內存區域 ?
問題出在這,上述代碼傳入getmemery(char *p)函數的字符串指針是形參,在函數內部修改形參并不能真正的改變傳入形參的值,執行完char *str = NULL; gememory(str);后的str仍為NULL;
一般函數的傳遞都是值傳遞,不會改變函數外的變量值。簡單地說,就是形參不能夠改變實參,實參只是復制了一份給形參!其自身并沒有被改變
所以str所指向的仍是一個未知區域,所以會出此上述錯誤;
如何修改呢?
[cpp]?view plaincopy執行結果如下:
[cpp]?view plaincopy
所以,我們要記住函數傳參的兩種方式:1)值傳遞 2)地址傳遞。
總結
以上是生活随笔為你收集整理的从getmemery()函数看内存管理、函数传参等一系列问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【案例分享】KTV网络机顶盒
- 下一篇: 转HTML+CSS总结/深入理解CSS盒