- 相關推薦
c語言面試常見問題
1.const意味著”只讀",下面的聲明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指針(也就是,整型數是不可修改的,但指針可以)。第四個意思a是一個指向整型數的常指針(也就是說,指針指向的整型數是可以修改的,但指針是不可修改的)。最后一個意味著a是一個指向常整型數的常指針(也就是說,指針指向的整型數是不可修改的,同時指針也是不可修改的)。
結論:·;關鍵字const的作用是為給讀你代碼的人傳達非常有用的信息,實際上,聲明一個參數為常量是為了告訴了用戶這個參數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多余的信息。(當然,懂得用const的程序員很少會留下的垃圾讓別人來清理的。) ·;通過給優化器一些附加的信息,使用關鍵字const也許能產生更緊湊的代碼。 ·;合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的參數,防止其被無意的代碼修改。簡而言之,這樣可以減少bug的出現。
(1)欲阻止一個變量被改變,可以使用const關鍵字。在定義該const變量時,通常需要對它進行初始化,因為以后就沒有機會再去改變它了;
(2)對指針來說,可以指定指針本身為const,也可以指定指針所指的數據為const,或二者同時指定為const;
(3)在一個函數聲明中,const可以修飾形參,表明它是一個輸入參數,在函數內部不能改變其值;
(4)對于類的成員函數,若指定其為const類型,則表明其是一個常函數,不能修改類的成員變量;
(5)對于類的成員函數,有時候必須指定其返回值為const類型,以使得其返回值不為“左值”。
2.關鍵字volatile有什么含意?并給出三個不同的例子。
一個定義為volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個例子:
(1)并行設備的硬件寄存器(如:狀態寄存器)
(2)一個中斷服務子程序中會訪問到的非自動變量(non-automatic variables)
(3)多線程應用中被幾個任務共享的變量
3.一個參數既可以是const還可以是volatile嗎?解釋為什么。一個指針可以是volatile 嗎?解釋為什么。
答案:
(1)是的。一個例子是只讀的狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程序不應該試圖去修改它。
(2)是的。盡管這并不很常見。一個例子是當一個中服務子程序修該一個指向一個buffer的指針時。
4.static關鍵字有什么作用?
(1)函數體內static變量的作用范圍為該函數體,不同于auto變量,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;
(2)在模塊內的static全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;
(3)在模塊內的static函數只可被這一模塊內的其它函數調用,這個函數的使用范圍被限制在聲明它的模塊內;
(4)在類中的static成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;
(5)在類中的static成員函數屬于整個類所擁有,這個函數不接收this指針,因而只能訪問類的static成員變量。
5. extern 在"c"中有什么作用:
(1)被extern "c"限定的函數或變量是extern類型的;
extern是c/c++語言中表明函數和全局變量作用范圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量可以在本模塊或其它模塊中使用。
(2)被extern "c"修飾的變量和函數是按照c語言方式編譯和連接的;
extern "c"的慣用法
(1)在c++中引用c語言中的函數和變量,在包含c語言頭文件(假設為cexample.h)時,需進行下列處理:
extern "c" { #include"cexample.h" }
《c語言面試常見問題》全文內容當前網頁未完全顯示,剩余內容請訪問下一頁查看。
而在c語言的頭文件中,對其外部函數只能指定為extern類型,c語言中不支持extern "c"聲明,在.c文件中包含了extern "c"時會出現編譯語法錯誤。
(2)在c中引用c++語言中的函數和變量時,c++的頭文件需添加extern "c",但是在c語言中不能直接引用聲明了extern "c"的該頭文件,應該僅將c文件中將c++中定義的extern "c"函數聲明為extern類型。
6. 堆和棧的區別?
管理方式:對于棧來講,是由編譯器自動管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產生memory leak。
申請大小:棧:棧是向低地址擴展的數據結構,是一塊連續的內存的區域
堆:是向高地址擴展的數據結構,是不連續的內存區域。
分配方式:堆都是動態分配的,動態分配由alloca函數進行分配
棧的動態分配由編譯器進行釋放,無需我們手工實現
7.以下函數輸出結果是
main()
{ int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);
printf("%d,%d",*(a+1),*(ptr-1));
}
答:2,5 *(a+1)就是a[1],*(ptr-1)就是a[4],執行結果是2,5
&a+1不是首地址+1,系統會認為加一個a數組的偏移,是偏移了一個數組的大小(本例是5個int)
int *ptr=(int *)(&a+1);則ptr實際是&(a[5]),也就是a+5
原因如下:&a是數組指針,其類型為int (*)[5];
而指針加1要根據指針類型加上一定的值,不同類型的指針+1之后增加的大小不同。
a是長度為5的int數組指針,所以要加5*sizeof(int),所以ptr實際是a[5],
但是prt與(&a+1)類型是不一樣的(這點很重要),所以prt-1只會減去sizeof(int*)
a,&a的地址是一樣的,但意思不一樣
a是數組首地址,也就是a[0]的地址,&a是對象(數組)首地址,
a+1是數組下一元素的地址,即a[1],&a+1是下一個對象的地址,即a[5].
8.鏈表和數組的區別在哪里?
二者都屬于一種數據結構
從邏輯結構來看
1.數組必須事先定義固定的長度(元素個數),不能適應數據動態地增減的情況。當數據增加時,可能超出原先定義的元素個數;當數據減少時,造成內存浪費;數組可以根據下標直接存取。
2.鏈表動態地進行存儲分配,可以適應數據動態地增減的情況,且可以方便地插入、刪除數據項。(數組中插入、刪除數據項時,需要移動其它數據項,非常繁瑣)鏈表必須根據next指針找到下一個元素
從內存存儲來看
1. (靜態)數組從棧中分配空間,對于程序員方便快速,但是自由度小
2.鏈表從堆中分配空間,自由度大但是申請管理比較麻煩
從上面的比較可以看出,如果需要快速訪問數據,很少或不插入和刪除元素,就應該用數組;相反,如果需要經常插入和刪除元素就需要用鏈表數據結構了。
9.結構體
struct stra { int a; float b; char c; }expa;
printf("%ld",sizeof(expa));
輸出結果為12 ?
該問題涉及編譯器的“內存對齊”問題:
現代計算機中內存空間都是按照byte(字節)劃分的,從理論上講似乎對任何類型的變量的訪問可以從任何地址開始,但實際情況是在訪問特定變量的時候經常在特定的內存地址訪問,這就需要各類型數據按照一定的規則在空間上排列,而不是順序的一個接一個的排放,這就是對齊。
對齊的作用和原因:各個硬件平臺對存儲空間的處理上有很大的不同。一些平臺對某些特定類型的數據只能從某些特定地址開始存取。其他平臺可能沒有這種情況,
但是最常見的是如果不按照適合其平臺的要求對數據存放進行對齊,會在存取效率上帶來損失。比如有些平臺每次讀都是從偶地址開始,如果一個int型(假設為32位)如果存放在偶地址開始的地方,那么一個讀周期就可以讀出,而如果存放在奇地址開始的地方,就可能會需要2個讀周期,并對兩次讀出的結果的高低
字節進行拼湊才能得到該int數據。顯然在讀取效率上下降很多。這也是空間和時間的博弈。
通常,我們寫程序的時候,不需要考慮對齊問題。編譯器會替我們選擇適合目標平臺的對齊策略。當然,我們也可以通知給編譯器傳遞預編譯指令而改變對指定數據的對齊方法。
但是,正因為我們一般不需要關心這個問題,所以因為編輯器對數據存放做了對齊,而我們不了解的話,常常會對一些問題感到迷惑。最常見的就是struct數據結構的sizeof結果,出乎意料。
對于結構體來說,按成員中所占字節最大的是float類型,占用4個字節,一共有3個成員,所以總的占用字節為:4* 3 = 12.
【c語言面試常見問題】相關文章:
c 面試常見問題11-25
c語言心得05-17
怎樣學習c++c語言編程04-28
面試 常見問題11-25
面試經典常見問題11-25
精選面試常見問題11-25
面試常見問題12-02
軟考程序員輔導:程序員C語言新人常見問題02-03
C語言跳出循環10-16