幾道面試題

2021-04-15 01:14:32 字數 3935 閱讀 1136

系統呼叫與函式的區別

從程式完成的功能來看,函式庫提供的函式通常是不需要作業系統的服務,函式是在使用者空間內執行的,除非函式涉及到i/o操作等,一般是不會切到核心態的。系統呼叫是要求作業系統為使用者提供程序,提供某種服務,通常是涉及系統的硬體資源和一些敏感的軟體資源等。    

函式庫的函式,尤其與輸入輸出相關的函式,大多必須通過linux的系統呼叫來完成。因此我們可以將函式庫的函式當成應用程式設計人員與系統呼叫程式之間的乙個中間層,通過這個中間層,我們可以用一致的介面來安全的呼叫系統呼叫。這樣程式設計師可以只要寫一次**就能夠在不同版本的linux系統間使用積壓種具體實現完全不同的系統呼叫。至於如何實現對不同的系統呼叫的相容性問題,那是函式庫開發者所關心的問題。   

從程式執行效率來看,系統呼叫的執行效率大多要比函式高,尤其是處理輸入輸出的函式。當處理的資料量比較小時,函式庫的函式執行效率可能比較好,因為函式庫的作法是將要處理的資料先存入緩衝區內,等到緩衝區裝滿了,再將資料一次寫入或者讀出。這種方式處理小量資料時效率比較高,但是在進行系統呼叫時,因為使用者程序從使用者模式進入系統核心模式,中間涉及了許多額外的任務的切換工作,這些操作稱為上下文切換,此類的額外工作會影響系統的執行效率。但是當要處理的資料量比較大時,例如當輸入輸出的資料量超過檔案系統定義的盡寸時,利用系統呼叫可獲得較高的效率。 

從程式的可移植性的角度來看,相對於系統呼叫,c語言的標準備函式庫(ansi c) 具備較高的可移植性,在不同的系統環境下,只要做很少的修改,通常情況是不需要修改的。

可重入函式概念:

主要用於多工環境中,乙個可重入的函式簡單來說就是可以被中斷的函式,也就是說,可以在這個函式執行的任何時刻中斷它,轉入os排程下去執行另外一段**,而返回控制時不會出現什麼錯誤;而不可重入的函式由於使用了一些系統資源,比如全域性變數區,中斷向量表等,所以它如果被中斷的話,可能會出現問題,這類函式是不能執行在多工環境下的。     也可以這樣理解,重入即表示重複進入,首先它意味著這個函式可以被中斷,其次意味著它除了使用自己棧上的變數以外不依賴於任何環境(包括static),這樣的函式就是purecode(純**)可重入,可以允許有該函式的多個副本在執行,由於它們使用的是分離的棧,所以不會互相干擾。如果確實需要訪問全域性變數(包括static),一定要注意實施互斥手段。可重入函式在並行執行環境中非常重要,但是一般要為訪問全域性變數付出一些效能代價。    編寫可重入函式時,若使用全域性變數,則應通過關中斷、訊號量(即p、v操作)等手段對其加以保護。 說明:若對所使用的全域性變數不加以保護,則此函式就不具有可重入性,即當多個程序呼叫此函式時,很有可能使有關全域性變數變為不可知狀態。

堆和棧的區別

乙個由c/c++編譯的程式占用的記憶體分為以下幾個部分 1、棧區(stack)

—由編譯器自動分配釋放,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。 2、堆區(heap)

—一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os** 。注意它與資料結構中的堆是兩回事,分配方式倒是類似於鍊錶,呵呵。 3、全域性區(靜態區)(static)

—,全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。 - 程式結束後有系統釋放 4、文字常量區

—常量字串就是放在這裡的。 程式結束後由系統釋放 5、程式**區

—存放函式體的二進位制**。

在什麼情況下析構函式必須是虛函式

若類中有虛函式,這個類的析構函式應該是虛的析構函式,否則會有錯假設夫類為a,子類為b,當a*   p   =   new   b();要析構p指向的物件時,若a中的析構函式不是virtual則呼叫delete   p時,不會呼叫b的析構函式,這樣在b中分配的資源就無法釋放了。你可以在a和b的析構函式中輸出看一下,或者用除錯工具跟蹤看一下

在全域性變數和全域性靜態變數有什麼區別

變數可以分為:全域性變數、靜態全域性變數、靜態區域性變數和區域性變數。        按儲存區域分,全域性變數、靜態全域性變數和靜態區域性變數都存放在記憶體的靜態儲存區域,區域性變數存放在記憶體的棧區。         按作用域分,全域性變數在整個工程檔案內都有效;靜態全域性變數只在定義它的檔案內有效;靜態區域性變數只在定義它的函式內有效,只是程式僅分配一次記憶體,函式返回後,該變數不會消失;區域性變數在定義它的函式內有效,但是函式返回後失效。        全域性變數和靜態變數如果沒有手工初始化,則由編譯器初始化為0。區域性變數的值不可知。           靜態全域性變數,只本檔案可以用。     全域性變數是沒有定義儲存型別的外部變數,其作用域是從定義點到程式結束.省略了儲存型別符,系統將預設為是自動型.      靜態全域性變數是定義儲存型別為靜態型的外部變數,其作用域是從定義點到程式結束,所不同的是儲存型別決定了儲存地點,靜態型變數是存放在記憶體的資料區中的,它們在程式開始執行前就分配了固定的位元組,在程式執行過程中被分配的位元組大小是不改變的.只有程式執行結束後,才釋放所占用的記憶體.   自動型變數存放在堆疊區中.堆疊區也是記憶體中一部分,該部分內存在程式執行中是重複使用的.

宣告變數與定義變數有什麼區別

宣告是向編譯器介紹名字--識別符號。它告訴編譯器

「這個函式或變數在某處可找到,它的模樣象什麼

」。而定義是說:

「在這裡建立變數」或

「在這裡建立函式

」。它為名字分配儲存空間。無論定義的是函式還是變數,編譯器都要為它們在定義點分配儲存空間。對於變數,編譯器確定變數的大小,然後在記憶體中開闢空間來儲存其資料,對於函式,編譯器會生成**,這些**最終也要占用一定的記憶體。     在c和c++中,可以在不同的地方宣告相同的變數和函式,但只能有乙個定義(有時這稱為odr,單一定義規則)。。。     定義也可以是宣告,如果有int   x;,之前編譯器未發現識別符號x,編譯器則把這一識別符號看成是定義並立即為它分配儲存空間。     。。。。。     對

「變數宣告

」的解釋向來模糊且自相矛盾。。。     函式宣告包括函式型別、函式名、引數列表和乙個分號,這些資訊足以編譯器認出它是乙個函式宣告並可識別出這個函式的外部特徵。由此推斷,變數宣告應是型別標識後面跟乙個識別符號。如int   a;但這產生了乙個矛盾,這段**有足夠的資訊讓編譯器為之分配儲存空間,而且編譯器也確實給之分配了儲存空間。要解決這個問題,對於c和c++需要乙個關鍵字來說明

「這是乙個宣告,它的定義在別的地方

」,這個關鍵字就是extern,它表示變數是在檔案以外定義的,或在檔案後面定義的。     在變數定義前加extern表示宣告乙個變數但不定義它,如:     extern   int   a;     extern也可用於函式宣告,如:     extern   int   func1(int   length,int   width);     但由於沒有函式體,編譯器必把它當成宣告而非定義,extern對於函式來說是多餘的、可選的。c語言的設計者並不要求函式宣告使用extern,這可能有些令人遺憾,如果函式宣告也要求用extern,那麼形式上與變數宣告更加一致了,從而減少了混亂(但這就需要更多的輸入,這也許能解釋為什麼不要求函式宣告使用extern的原因)。。。 

什麼是位元組對齊,為什麼要對齊?

現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定型別變數的時候經常在特定的記憶體位址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。

對齊的作用和原因:各個硬體平台對儲存空間的處理上有很大的不同。一些平台對某些特定型別的資料只能從某些特定位址開始訪問。比如有些架構的cpu在訪問乙個沒有進行對齊的變數的時候會發生錯誤,那麼在這種架構下程式設計必須保證位元組對齊.其他平台可能沒有這種情況,但是最常見的是如果不按照適合其平台要求對 資料存放進行對齊,會在訪問效率上帶來損失。比如有些平台每次讀都是從偶位址開始,如果乙個int型(假設為32位系統)如果存放在偶位址開始的地方,那麼乙個讀週期就可以讀出這32bit,而如果存放在奇位址開始的地方,就需要2個讀週期,並對兩次讀出的結果的高低位元組進行拼湊才能得到該32bit數 據。顯然在讀取效率上下降很多。

幾道面試題

1 下列程式片段執行時間排序 1 for uint i 0 i 1024 i char url char malloc 4096 memset url,0x0,4096 free url 2 for uint i 0 i 1024 i 3 char url char malloc 4096 for ...

幾道面試題

q 您在什麼情況下會用到虛方法?它與介面有什麼不同?q override與過載有什麼區別?q 值型別與引用型別有什麼區別?q 怎樣理解靜態變數?q 向伺服器傳送請求有幾種方式?q datareader與dataset有什麼區別?q 用.net做b s結構的系統,您是用幾層結構來開發,每一層之間的關係...

幾道面試題

1 hashtable和hashmap的區別?hashtable 執行緒安全,效率低。不允許null鍵和null值 hashmap 執行緒不安全,效率高。允許null鍵和null值 2 list,set,map等介面是否都繼承子map介面?list,set不是繼承自map介面,它們繼承自collec...