面試題總結200306

1.簡單說下堆和棧的區別?

  • 程序內存分配方式不同
    stack:編譯器自動分配釋放,存放函數的參數值、局部變量的值…,類似於數據結構中的棧;
    heap:一般由程序員自己申請內存並且釋放;如果在程序結束後未釋放,可能會由操作系統進行釋放,與數據結構上的堆是兩回事,類似於數據結構中的鏈表;

  • 申請的方式不同
    stack:程序自行分配大小
    heap:程序員開闢內存空間,c語言中用malloc開闢,free釋放;C++用new開闢,delete釋放;

  • 申請系統的響應方式不同
    stack:只要申請的內存大小小於棧的剩餘空間大小,系統會自動分配內存,否則會造成棧溢出;
    heap:再說堆之前,我們首先要知道操作系統有一個記錄內存大小的鏈表;當系統收到申請內存的消息,就會遍歷該鏈表,找到第一個大於等於要申請的空間的堆結點,然後將這個結點從空間節點刪除,並將這個結點的空間分配給程序;

對大多數系統來說,會在這塊的內存空間的首地址記錄本次分配的內存的大小,這樣子delete/free時,就能正確釋放內存空間;
注意:所申請內存大小不會與堆結點剛好相等,系統會將多餘的部分放入空閒鏈表;

  • 申請大小限制不同
    stack:棧是像低地址擴展的數據結構,是一塊連續的內存空間,棧頂的地址和棧的最大容量是由系統決定的,在window下一般就1M-2M,所以從棧中所能獲得的空間較小;
    heap:堆是向高地址擴展的數據結構,是不連續的內存空間;因爲系統是由鏈表在存儲空閒內存地址,自然堆就是不連續的內存區域,且鏈表的遍歷也是從低地址像高地址遍歷的;堆的大小受限於計算機系統的有效虛擬內存空間,在此空間,堆獲得的空間比較靈活,也比較大;

  • 申請效率不同
    stack:系統分配,速度快,程序員無法控制;
    heap:程序員分配,速度慢,使用起來方便,但是容易造成內存碎片;

  • 存儲內容不同
    stack:在函數調用時,第一個進棧的是換函數調用後的下一條指令的地址,然後各個函數的參數,在大多數c編譯中,參數大多數都是從右往左入棧;調用結束後,局部變量先出棧,然後參數出棧,最後棧頂的指針指向最開始存的地址(主函數的下一條指令);
    heap:一般在堆的頭部用一個字節存放堆的大小,具體由程序員安排;

2.全局變量和局部變量能不能用同一個名字,能的話,調用時用哪個?

可以,在程序中如果出現了相同的兩個變量,一個是局部變量,一個是全局變量,編譯可以通過,但是打印出的值是局部變量的值,如果想打印全局變量的值的話,在全局變量之前加上“::”就可以了。

#include<iostream>
using namespace std;
int a;      //定義全局變量
int main()
{
int a = 3;      //定義局部變量並賦值
cout<<"a = "<<a<<endl;
::a = 2;    //給全局變量賦值
cout<<"a = "<<::a<<endl;
}
輸出結果爲:
a = 3;
a = 2;

3.靜態全局變量和全局變量的區別?

普通的全局變量在前面加上static就變成了靜態全局變量,假設我們的程序有多個源文件,普通的全局變量在整個源文件內都是有效的,但是靜態全局變量限制了其自身的作用域,只能在定義該變量的源文件內有效,在其他源文件不能使用,這樣可以避免在其他源文件中引起錯誤;

4.靜態局部變量和局部變量的區別?

靜態局部變量修改了普通局部變量的生存期,static只能被初始化一次,函數在此調用時,會調用上一次被調用之後的結果值;

5.內存泄漏問題?(內存泄漏了,程序結束後,這塊的內存釋放了沒)

在C語言程序設計中,內存泄漏幾乎是很難避免的,C程序產生泄漏內存,則運行速度會逐漸變慢,並最終停止運行;如果產生覆蓋內存,程序會變得非常脆弱,很容易受到惡意用戶的攻擊。內存泄漏是一種隱性危害,它們很難被發現,通常不能在相應的源代碼中找到錯誤,需要仔細分析與專門的檢測工具才能發現。

通常我們所說的內存泄漏,是指分配出去的內存在使用之後沒有釋放掉,沒有回收,長此以往,會造成沒有足夠的內存可以分配。一般表現爲運行時間越長,佔用的內存越多,最終導致系統奔潰。一般的內存泄漏是指堆內存的泄漏。堆內存是指程序從堆中分配的,大小任意的(內存塊的大小可以在程序運行期決定),使用完後必須顯式釋放的內存。應用程序一般使用malloc,realloc,new等函數從堆中分配到一塊內存,使用完後,程序必須負責相應的調用free或delete釋放該內存塊,否則,這塊內存就不能被再次使用,我們就說這塊內存泄漏了。

6.malloc和free簡單說明一下?

malloc

在C語言中用內存分配函數來實現內存的動態分配,這些函數有:malloc()和realloc()等函數。malloc():使用這個函數時需要包含頭文件#include<stdlib.h>。使用該函數需要指定要分配的內存字節數作爲參數,例如:

 int *pNumber=int *) malloc(100

這條語句分配了100個字節的內存,並把這個內存塊的地址賦給pNumber,這個內存塊可以保存最大25個int值, 每個int佔4個字節。如果不能分配請求的內存,malloc()會返回一個null指針。

malloc是一個函數,專門用來從堆上分配內存。使用malloc函數需要幾個要求:內存分配給誰?分配多大內存?是否還有足夠內存分配? 內存將用來存儲什麼格式的數據?分配好的內存在哪裏? 如果這5點都確定,那內存就能分配。下面看看malloc的原型:

void *)malloc(int size)

malloc函數的返回值是一個void類型的指針,參數爲int類型的數據,即申請分配的內存大小,單位是字節。內存 分配成功之後,malloc函數返回這塊內存的首地址,你需要一個指針來接受這個地址。也就是說這塊內存將來要 用來存儲什麼類型的數據,如:

char *p =char *)malloc(100

在堆內存分配了100個字節的內存,返回這塊內存的首地址,把地址強制轉換成char *類型後賦給char *類型的指針變量p;同時告訴我們這塊內存將用來存儲char類型的數據。你只能通過指針變量p來操作這塊內存,這塊內存本身沒有名字,對它的訪問是匿名訪問。但是,不一定每次malloc函數都能成功分配到內存。既然malloc函數申請內存存在不成功的可能,那我們在使用指向這塊內存的指針時,必須用if( NULL != p)語句上來驗證內存分配確實成功了。

注意:如果所申請的內存塊大於目前堆上剩餘的內存塊(整塊),則內存分配就會失敗,函數函數NULL。注意這裏說的是“堆上剩餘內存塊”不是所有剩餘內存塊之和,因爲malloc函數申請的是連續的一塊內存。既然malloc函數申請內存又不成功的可能,那我們在使用指向這塊內存的指針時,必須用if(NULL != p)語句上來驗證內存分配確實成功了。

free

free函數只有一個參數,就是所要釋放的內存塊的首地址(指針)。free函數其實它就做了一件事:斬斷指針變量和這塊內存的對應關係。free函數就是把這塊內存和p之間的關係斬斷;p本身的值並沒有改變或者消失,即指針變量p本身保存的地址並沒有改變,那塊被釋放的內存裏面保存的值也沒有改變。這就是free函數的功能,一個malloc對應一個free,是一夫一妻制。在使用free(p)函數內存釋放後,指針變量p本身保存的地址並沒有改變,那我們必須需重新把p的值變爲NULL:p = NULL。如果沒有把該指針置NULL,這個指針就成爲了“懸空指針”,這是很危險的,且也是經常出錯的方。

釋放動態分配的內存堆上分配的內存會在整個應用程序結束之後,由操作系統負責回收,但最好是在使用完這些內存後立即釋放。如果不釋放,會引起內存泄漏,極大佔用系統資源,可能會產生各種未知的錯誤。所以,必須使用free()函數釋放內存,參數是內存地址(指針),例如:free(pNumber),依上例。

7.const * char p char *const p char const *p有什麼區別

char* const p; p爲指向字符變量的指針,地址不變,地址內容可變

const char *p; p爲指向字符變量的指針,地址可變,地址內容不變

char const *p 與const char *p等價。

#include <stdio.h"> 
int main(int argc, char const *argv[])  
{  
    char str[]="abcd";  
    char const *p;  
    p=str;  
    p++;  //指針的地址可變
    char* const q=&str[1];  
    *q='m';  //指針的內容可變
    printf("%c,%c\n",*(p+1),*q );  
    return 0;  
} 

示例:

char const *p;  
p=str;  
*p='n'; 

~/src/demo13$ gcc test.c -o test  
test.c: 在函數‘main’中:  
test.c:8:2: 錯誤: 向只讀位置‘*p’賦值  
char* const q=&str[1];  
q++;  


lifeihu@ubuntu:~/src/demo13$ cc test.c -o test  
test.c: 在函數‘main’中:  
test.c:11:2: 錯誤: 令只讀變量‘q’自增  

注意:對於指針常量char* const q,在定義時必須初始化。

char* const q;  
q=&str[1];  


lifeihu@ubuntu:~/src/demo13$ cc test.c -o test  
test.c: 在函數‘main’中:  
test.c:10:2: 錯誤: 向只讀變量‘q’賦值
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章