1. 程式人生 > >linux C程式設計師 經典面試題(非常經典)

linux C程式設計師 經典面試題(非常經典)



linux C程式設計師 經典面試題一


想成為嵌入式程式設計師應知道的0x10個基本問題:
前處理器(Preprocessor)


1 . 用預處理指令#define 宣告一個常數,用以表明1年中有多少秒(忽略閏年問題)
         #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
我在這想看到幾件事情:
1) #define 語法的基本知識(例如:不能以分號結束,括號的使用,等等)
2)懂得前處理器將為你計算常數表示式的值,因此,直接寫出你是如何計算一年中有多少秒而不是計算出實際的值,是更清晰而沒有代價的。
3) 意識到這個表示式將使一個16位機的整型數溢位-因此要用到長整型符號L,告訴編譯器這個常數是的長整型數。
4) 如果你在你的表示式中用到UL(表示無符號長整型),那麼你有了一個好的起點。記住,第一印象很重要。


2 . 寫一個"標準"巨集MIN ,這個巨集輸入兩個引數並返回較小的一個。
        #define MIN(A,B) ((A) <= (B) ? (A) : (B))
這個測試是為下面的目的而設的:
1) 標識#define在巨集中應用的基本知識。這是很重要的。因為在  嵌入(inline)操作符 變為標準C的一部分之前,巨集是方便產生嵌入程式碼的唯一方法,對於嵌入式系統來說,為了能達到要求的效能,嵌入程式碼經常是必須的方法。
2)三重條件操作符的知識。這個操作符存在C語言中的原因是它使得編譯器能產生比if-then-else更優化的程式碼,瞭解這個用法是很重要的。
3) 懂得在巨集中小心地把引數用括號括起來
4) 我也用這個問題開始討論巨集的副作用,例如:當你寫下面的程式碼時會發生什麼事?
        least = MIN(*p++, b);


3. 前處理器標識#error的目的是什麼?
如果你不知道答案,請看參考文獻1。這問題對區分一個正常的夥計和一個書呆子是很有用的。只有書呆子才會讀C語言課本的附錄去找出象這種問題的答案。當然如果你不是在找一個書呆子,那麼應試者最好希望自己不要知道答案。




死迴圈(Infinite loops)


4. 嵌入式系統中經常要用到無限迴圈,你怎麼樣用C編寫死迴圈呢?
這個問題用幾個解決方案。我首選的方案是:
while(1)
{}


一些程式設計師更喜歡如下方案:
for(;;)
{}


這個實現方式讓我為難,因為這個語法沒有確切表達到底怎麼回事。如果一個應試者給出這個作為方案,我將用這個作為一個機會去探究他們這樣做的基本原理。如果他們的基本答案是:"我被教著這樣做,但從沒有想到過為什麼。"這會給我留下一個壞印象。


第三個方案是用 goto
Loop:
...
goto Loop;
應試者如給出上面的方案,這說明或者他是一個組合語言程式設計師(這也許是好事)或者他是一個想進入新領域的BASIC/FORTRAN程式設計師。




資料宣告(Data declarations)


5. 用變數a給出下面的定義
a) 一個整型數(An integer)
b)一個指向整型數的指標( A pointer to an integer)
c)一個指向指標的的指標,它指向的指標是指向一個整型數( A pointer to a pointer to an intege)r
d)一個有10個整型數的陣列( An array of 10 integers)
e) 一個有10個指標的陣列,該指標是指向一個整型數的。(An array of 10 pointers to integers)
f) 一個指向有10個整型數陣列的指標( A pointer to an array of 10 integers)
g) 一個指向函式的指標,該函式有一個整型引數並返回一個整型數(A pointer to a function that takes an integer as an argument and returns an integer)
h) 一個有10個指標的陣列,該指標指向一個函式,該函式有一個整型引數並返回一個整型數( An array of ten pointers to functions that take an integer argument and return an integer )


答案是:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer


人們經常聲稱這裡有幾個問題是那種要翻一下書才能回答的問題,我同意這種說法。當我寫這篇文章時,為了確定語法的正確性,我的確查了一下書。但是當我被面試的時候,我期望被問到這個問題(或者相近的問題)。因為在被面試的這段時間裡,我確定我知道這個問題的答案。應試者如果不知道所有的答案(或至少大部分答案),那麼也就沒有為這次面試做準備,如果該面試者沒有為這次面試做準備,那麼他又能為什麼出準備呢?




Static


6. 關鍵字static的作用是什麼?
這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:
1)在函式體,一個被宣告為靜態的變數在這一函式被呼叫過程中維持其值不變。
2) 在模組內(但在函式體外),一個被宣告為靜態的變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問。它是一個本地的全域性變數。
3) 在模組內,一個被宣告為靜態的函式只可被這一模組內的其它函式呼叫。那就是,這個函式被限制在宣告它的模組的本地範圍內使用。


大多數應試者能正確回答第一部分,一部分能正確回答第二部分,同是很少的人能懂得第三部分。這是一個應試者的嚴重的缺點,因為他顯然不懂得本地化資料和程式碼範圍的好處和重要性。


Const


7.關鍵字const有什麼含意?
我只要一聽到被面試者說:"const意味著常數",我就知道我正在和一個業餘者打交道。去年Dan Saks已經在他的文章裡完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什麼和不能做什麼.如果你從沒有讀到那篇文章,只要能說出const意味著"只讀"就可以了。儘管這個答案不是完全的答案,但我接受它作為一個正確的答案。(如果你想知道更詳細的答案,仔細讀一下Saks的文章吧。)
如果應試者能正確回答這個問題,我將問他一個附加的問題:
下面的宣告都是什麼意思?


const int a;
int const a;
const int *a;
int * const a;
int const * a const;




前兩個的作用是一樣,a是一個常整型數。第三個意味著a是一個指向常整型數的指標(也就是,整型數是不可修改的,但指標可以)。第四個意思a是一個指向整型數的常指標(也就是說,指標指向的整型數是可以修改的,但指標是不可修改的)。最後一個意味著a是一個指向常整型數的常指標(也就是說,指標指向的整型數是不可修改的,同時指標也是不可修改的)。如果應試者能正確回答這些問題,那麼他就給我留下了一個好印象。順帶提一句,也許你可能會問,即使不用關鍵字 const,也還是能很容易寫出功能正確的程式,那麼我為什麼還要如此看重關鍵字const呢?我也如下的幾下理由:
1) 關鍵字const的作用是為給讀你程式碼的人傳達非常有用的資訊,實際上,宣告一個引數為常量是為了告訴了使用者這個引數的應用目的。如果你曾花很多時間清理其它人留下的垃圾,你就會很快學會感謝這點多餘的資訊。(當然,懂得用const的程式設計師很少會留下的垃圾讓別人來清理的。)
2) 通過給優化器一些附加的資訊,使用關鍵字const也許能產生更緊湊的程式碼。
3) 合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的引數,防止其被無意的程式碼修改。簡而言之,這樣可以減少bug的出現。




Volatile


8. 關鍵字volatile有什麼含意?並給出三個不同的例子。
一個定義為volatile的變數是說這變數可能會被意想不到地改變,這樣,編譯器就不會去假設這個變數的值了。精確地說就是,優化器在用到這個變數時必須每次都小心地重新讀取這個變數的值,而不是使用儲存在暫存器裡的備份。下面是volatile變數的幾個例子:
1) 並行裝置的硬體暫存器(如:狀態暫存器)
2) 一箇中斷服務子程式中會訪問到的非自動變數(Non-automatic variables)
3) 多執行緒應用中被幾個任務共享的變數


回答不出這個問題的人是不會被僱傭的。我認為這是區分C程式設計師和嵌入式系統程式設計師的最基本的問題。搞嵌入式的傢伙們經常同硬體、中斷、RTOS等等打交道,所有這些都要求用到volatile變數。不懂得volatile的內容將會帶來災難。
假設被面試者正確地回答了這是問題(嗯,懷疑是否會是這樣),我將稍微深究一下,看一下這傢伙是不是直正懂得volatile完全的重要性。
1)一個引數既可以是const還可以是volatile嗎?解釋為什麼。
2); 一個指標可以是volatile 嗎?解釋為什麼。
3); 下面的函式有什麼錯誤:


int square(volatile int *ptr)
{
        return *ptr * *ptr;
}
下面是答案:
1)是的。一個例子是隻讀的狀態暫存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。
2); 是的。儘管這並不很常見。一個例子是當一箇中服務子程式修該一個指向一個buffer的指標時。
3) 這段程式碼有點變態。這段程式碼的目的是用來返指標*ptr指向值的平方,但是,由於*ptr指向一個volatile型引數,編譯器將產生類似下面的程式碼:


int square(volatile int *ptr)
{
    int a,b;
    a = *ptr;
    b = *ptr;
    return a * b;
}


由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段程式碼可能返不是你所期望的平方值!正確的程式碼如下:


long square(volatile int *ptr)
{
    int a;
    a = *ptr;
    return a * a;
}


位操作(Bit manipulation)


9. 嵌入式系統總是要使用者對變數或暫存器進行位操作。給定一個整型變數a,寫兩段程式碼,第一個設定a的bit 3,第二個清除a 的bit 3。在以上兩個操作中,要保持其它位不變。
對這個問題有三種基本的反應
1)不知道如何下手。該被面者從沒做過任何嵌入式系統的工作。
2) 用bit fields。Bit fields是被扔到C語言死角的東西,它保證你的程式碼在不同編譯器之間是不可移植的,同時也保證了的你的程式碼是不可重用的。我最近不幸看到 Infineon為其較複雜的通訊晶片寫的驅動程式,它用到了bit fields因此完全對我無用,因為我的編譯器用其它的方式來實現bit fields的。從道德講:永遠不要讓一個非嵌入式的傢伙粘實際硬體的邊。
3) 用 #defines 和 bit masks 操作。這是一個有極高可移植性的方法,是應該被用到的方法。最佳的解決方案如下:


#define BIT3 (0x1 << 3)
static int a;


void set_bit3(void)
{
    a |= BIT3;
}
void clear_bit3(void)
{
    a &= ~BIT3;
}


一些人喜歡為設定和清除值而定義一個掩碼同時定義一些說明常數,這也是可以接受的。我希望看到幾個要點:說明常數、|=和&=~操作。




訪問固定的記憶體位置(Accessing fixed memory locations)


10. 嵌入式系統經常具有要求程式設計師去訪問某特定的記憶體位置的特點。在某工程中,要求設定一絕對地址為0x67a9的整型變數的值為0xaa55。編譯器是一個純粹的ANSI編譯器。寫程式碼去完成這一任務。
這一問題測試你是否知道為了訪問一絕對地址把一個整型數強制轉換(typecast)為一指標是合法的。這一問題的實現方式隨著個人風格不同而不同。典型的類似程式碼如下:
    int *ptr;
    ptr = (int *)0x67a9;
    *ptr = 0xaa55;


 A more obscure approach is:
一個較晦澀的方法是:


    *(int * const)(0x67a9) = 0xaa55;


即使你的品味更接近第二種方案,但我建議你在面試時使用第一種方案。






中斷(Interrupts)


11. 中斷是嵌入式系統中重要的組成部分,這導致了很多編譯開發商提供一種擴充套件—讓標準C支援中斷。具代表事實是,產生了一個新的關鍵字 __interrupt。下面的程式碼就使用了__interrupt關鍵字去定義了一箇中斷服務子程式(ISR),請評論一下這段程式碼的。


__interrupt double compute_area (double radius)
{
    double area = PI * radius * radius;
    printf("\nArea = %f", area);
    return area;
}


這個函式有太多的錯誤了,以至讓人不知從何說起了:
1)ISR 不能返回一個值。如果你不懂這個,那麼你不會被僱用的。
2) ISR 不能傳遞引數。如果你沒有看到這一點,你被僱用的機會等同第一項。
3) 在許多的處理器/編譯器中,浮點一般都是不可重入的。有些處理器/編譯器需要讓額處的暫存器入棧,有些處理器/編譯器就是不允許在ISR中做浮點運算。此外,ISR應該是短而有效率的,在ISR中做浮點運算是不明智的。
4) 與第三點一脈相承,printf()經常有重入和效能上的問題。如果你丟掉了第三和第四點,我不會太為難你的。不用說,如果你能得到後兩點,那麼你的被僱用前景越來越光明瞭。




程式碼例子(Code examples)


12 . 下面的程式碼輸出是什麼,為什麼?
void foo(void)
{
    unsigned int a = 6;
    int b = -20;
    (a+b > 6) ? puts("> 6") : puts("<= 6");
}
這個問題測試你是否懂得C語言中的整數自動轉換原則,我發現有些開發者懂得極少這些東西。不管如何,這無符號整型問題的答案是輸出是 ">6"。原因是當表示式中存在有符號型別和無符號型別時所有的運算元都自動轉換為無符號型別。因此-20變成了一個非常大的正整數,所以該表示式計算出的結果大於6。這一點對於應當頻繁用到無符號資料型別的嵌入式系統來說是豐常重要的。如果你答錯了這個問題,你也就到了得不到這份工作的邊緣。


13. 評價下面的程式碼片斷:


unsigned int zero = 0;
unsigned int compzero = 0xFFFF;


對於一個int型不是16位的處理器為說,上面的程式碼是不正確的。應編寫如下:


unsigned int compzero = ~0;


這一問題真正能揭露出應試者是否懂得處理器字長的重要性。在我的經驗裡,好的嵌入式程式設計師非常準確地明白硬體的細節和它的侷限,然而PC機程式往往把硬體作為一個無法避免的煩惱。
到了這個階段,應試者或者完全垂頭喪氣了或者信心滿滿志在必得。如果顯然應試者不是很好,那麼這個測試就在這裡結束了。但如果顯然應試者做得不錯,那麼我就扔出下面的追加問題,這些問題是比較難的,我想僅僅非常優秀的應試者能做得不錯。提出這些問題,我希望更多看到應試者應付問題的方法,而不是答案。不管如何,你就當是這個娛樂吧...


動態記憶體分配(Dynamic memory allocation)


14. 儘管不像非嵌入式計算機那麼常見,嵌入式系統還是有從堆(heap)中動態分配記憶體的過程的。那麼嵌入式系統中,動態分配記憶體可能發生的問題是什麼?
這裡,我期望應試者能提到記憶體碎片,碎片收集的問題,變數的持行時間等等。這個主題已經在ESP雜誌中被廣泛地討論過了(主要是 P.J. Plauger, 他的解釋遠遠超過我這裡能提到的任何解釋),所有回過頭看一下這些雜誌吧!讓應試者進入一種虛假的安全感覺後,我拿出這麼一個小節目:
下面的程式碼片段的輸出是什麼,為什麼?


char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
    puts("Got a null pointer");
else
    puts("Got a valid pointer");


這是一個有趣的問題。最近在我的一個同事不經意把0值傳給了函式malloc,得到了一個合法的指標之後,我才想到這個問題。這就是上面的程式碼,該程式碼的輸出是"Got a valid pointer"。我用這個來開始討論這樣的一問題,看看被面試者是否想到庫例程這樣做是正確。得到正確的答案固然重要,但解決問題的方法和你做決定的基本原理更重要些。


Typedef
 
15 Typedef 在C語言中頻繁用以宣告一個已經存在的資料型別的同義字。也可以用前處理器做類似的事。例如,思考一下下面的例子:


#define dPS struct s *
typedef struct s * tPS;


以上兩種情況的意圖都是要定義dPS 和 tPS 作為一個指向結構s指標。哪種方法更好呢?(如果有的話)為什麼?
這是一個非常微妙的問題,任何人答對這個問題(正當的原因)是應當被恭喜的。答案是:typedef更好。思考下面的例子:


dPS p1,p2;
tPS p3,p4;


第一個擴充套件為


struct s * p1, p2;
.
上面的程式碼定義p1為一個指向結構的指,p2為一個實際的結構,這也許不是你想要的。第二個例子正確地定義了p3 和p4 兩個指標。晦澀的語法


16 . C語言同意一些令人震驚的結構,下面的結構是合法的嗎,如果是它做些什麼?


int a = 5, b = 7, c;
c = a+++b;


這個問題將做為這個測驗的一個愉快的結尾。不管你相不相信,上面的例子是完全合乎語法的。問題是編譯器如何處理它?水平不高的編譯作者實際上會爭論這個問題,根據最處理原則,編譯器應當能處理儘可能所有合法的用法。因此,上面的程式碼被處理成:


c = a++ + b;


因此, 這段程式碼持行後a = 6, b = 7, c = 12。
如果你知道答案,或猜出正確答案,做得好。如果你不知道答案,我也不把這個當作問題。我發現這個問題的最大好處是這是一個關於程式碼編寫風格,程式碼的可讀性,程式碼的可修改性的好的話題。




華為筆試題
1.寫出判斷ABCD四個表示式的是否正確, 若正確, 寫出經過表示式中 a的值(3分)
int a = 4;
(A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++);
a = ?
答:C錯誤,左側不是一個有效變數,不能賦值,可改為(++a) += a;
改後答案依次為9,10,10,11(經測發現,在linux中 c d選項都是錯的 (++a) (a++)都不能是左值)



2.某32位系統下, C++程式,請計算sizeof 的值(5分).
char str[] = “http://www.ibegroup.com/”
char *p = str ;
int n = 10;
請計算
sizeof (str ) = ?(1)
sizeof ( p ) = ?(2)
sizeof ( n ) = ?(3)
void Foo ( char str[100]){
請計算
sizeof( str ) = ?(4)
}
void *p = malloc( 100 );
請計算
sizeof ( p ) = ?(5)
答:(1)17 (2)4 (3) 4 (4)4 (5)4


3. 回答下面的問題. (4分)
(1).標頭檔案中的 ifndef/define/endif 幹什麼用?預處理
答:防止標頭檔案被重複引用
(2). #i nclude 和 #i nclude “filename.h” 有什麼區別?
答:前者用來包含開發環境提供的庫標頭檔案,後者用來包含自己編寫的標頭檔案。
(3).在C++ 程式中呼叫被 C 編譯器編譯後的函式,為什麼要加 extern “C”宣告?
答:函式和變數被C++編譯後在符號庫中的名字與C語言的不同,被extern "C"修飾的變
量和函式是按照C語言方式編譯和連線的。由於編譯後的名字不同,C++程式不能直接調
用C 函式。C++提供了一個C 連線交換指定符號extern“C”來解決這個問題。
(4). switch()中不允許的資料型別是?
答:實型


4. 回答下面的問題(6分)
(1).Void GetMemory(char **p, int num){
*p = (char *)malloc(num);
}
void Test(void){
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
請問執行Test 函式會有什麼樣的結果?
答:輸出“hello”
(2). void Test(void){
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL){
strcpy(str, “world”);
printf(str);
}
}
請問執行Test 函式會有什麼樣的結果?
答:輸出“world”
(3). char *GetMemory(void){
char p[] = "hello world";
return p;
}
void Test(void){
char *str = NULL;
str = GetMemory();
printf(str);
}
請問執行Test 函式會有什麼樣的結果?
答:無效的指標,輸出不確定


5. 編寫strcat函式(6分)
已知strcat函式的原型是char *strcat (char *strDest, const char *strSrc);
其中strDest 是目的字串,strSrc 是源字串。
(1)不呼叫C++/C 的字串庫函式,請編寫函式 strcat
答:
VC原始碼:
char * __cdecl strcat (char * dst, const char * src)
{
char * cp = dst;
while( *cp )
cp++;
while( *cp++ = *src++ ) ;
return( dst );
}
(2)strcat能把strSrc 的內容連線到strDest,為什麼還要char * 型別的返回值?
答:方便賦值給其他變數


6.MFC中CString是型別安全類麼?
答:不是,其它資料型別轉換到CString可以使用CString的成員函式Format來轉換


7.C++中為什麼用模板類。
答:(1)可用來建立動態增長和減小的資料結構
(2)它是型別無關的,因此具有很高的可複用性。
(3)它在編譯時而不是執行時檢查資料型別,保證了型別安全
(4)它是平臺無關的,可移植性
(5)可用於基本資料型別


8.CSingleLock是幹什麼的。
答:同步多個執行緒對一個數據類的同時訪問


9.NEWTEXTMETRIC 是什麼。
答:物理字型結構,用來設定字型的高寬大小


10.程式什麼時候應該使用執行緒,什麼時候單執行緒效率高。
答:1.耗時的操作使用執行緒,提高應用程式響應
2.並行操作時使用執行緒,如C/S架構的伺服器端併發執行緒響應使用者的請求。
3.多CPU系統中,使用執行緒提高CPU利用率
4.改善程式結構。一個既長又複雜的程序可以考慮分為多個執行緒,成為幾個獨立或半獨
立的執行部分,這樣的程式會利於理解和修改。
其他情況都使用單執行緒。




11.Windows是核心級執行緒麼。
答:見下一題


12.Linux有核心級執行緒麼。
答:執行緒通常被定義為一個程序中程式碼的不同執行路線。從實現方式上劃分,執行緒有兩
種類型:“使用者級執行緒”和“核心級執行緒”。使用者執行緒指不需要核心支援而在使用者程式
中實現的執行緒,其不依賴於作業系統核心,應用程序利用執行緒庫提供建立、同步、排程
和管理執行緒的函式來控制使用者執行緒。這種執行緒甚至在象 DOS 這樣的作業系統中也可實現
,但執行緒的排程需要使用者程式完成,這有些類似 Windows 3.x 的協作式多工。另外一
種則需要核心的參與,由核心完成執行緒的排程。其依賴於作業系統核心,由核心的內部
需求進行建立和撤銷,這兩種模型各有其好處和缺點。使用者執行緒不需要額外的核心開支
,並且使用者態執行緒的實現方式可以被定製或修改以適應特殊應用的要求,但是當一個線
程因 I/O 而處於等待狀態時,整個程序就會被排程程式切換為等待狀態,其他執行緒得不
到執行的機會;而核心執行緒則沒有各個限制,有利於發揮多處理器的併發優勢,但卻佔
用了更多的系統開支。
Windows NT和OS/2支援核心執行緒。Linux 支援核心級的多執行緒


13.C++中什麼資料分配在棧或堆中,New分配資料是在近堆還是遠堆中?
答:棧: 存放區域性變數,函式呼叫引數,函式返回值,函式返回地址。由系統管理
堆: 程式執行時動態申請,new 和 malloc申請的記憶體就在堆上


14.使用執行緒是如何防止出現大的波峰。
答:意思是如何防止同時產生大量的執行緒,方法是使用執行緒池,執行緒池具有可以同時提
高排程效率和限制資源使用的好處,執行緒池中的執行緒達到最大數時,其他執行緒就會排隊
等候。


15函式模板與類模板有什麼區別?
答:函式模板的例項化是由編譯程式在處理函式呼叫時自動完成的,而類模板的例項化
必須由程式設計師在程式中顯式地指定。


16一般資料庫若出現日誌滿了,會出現什麼情況,是否還能使用?
答:只能執行查詢等讀操作,不能執行更改,備份等寫操作,原因是任何寫操作都要記
錄日誌。也就是說基本上處於不能使用的狀態。


17 SQL Server是否支援行級鎖,有什麼好處?
答:支援,設立封鎖機制主要是為了對併發操作進行控制,對干擾進行封鎖,保證資料
的一致性和準確性,行級封鎖確保在使用者取得被更新的行到該行進行更新這段時間內不
被其它使用者所修改。因而行級鎖即可保證資料的一致性又能提高資料操作的迸發性。


18如果資料庫滿了會出現什麼情況,是否還能使用?
答:見16


19 關於記憶體對齊的問題以及sizof()的輸出
答:編譯器自動對齊的原因:為了提高程式的效能,資料結構(尤其是棧)應該儘可能
地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問
;然而,對齊的記憶體訪問僅需要一次訪問。


20 int i=10, j=10, k=3; k*=i+j; k最後的值是?
答:60,此題考察優先順序,實際寫成: k*=(i+j);,賦值運算子優先順序最低


21.對資料庫的一張表進行操作,同時要對另一張表進行操作,如何實現?
答:將操作多個表的操作放入到事務中進行處理


22.TCP/IP 建立連線的過程?(3-way shake)
答:在TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線。
  第一次握手:建立連線時,客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SEND狀
態,等待伺服器確認;
第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個
SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;
  第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1)
,此包傳送完畢,客戶端和伺服器進入ESTABLISHED狀態,完成三次握手。


23.ICMP是什麼協議,處於哪一層?
答:Internet控制報文協議,處於網路層(IP層)


24.觸發器怎麼工作的?
答:觸發器主要是通過事件進行觸發而被執行的,當對某一表進行諸如UPDATE、 INSERT
、 DELETE 這些操作時,資料庫就會自動執行觸發器所定義的SQL 語句,從而確保對數
據的處理必須符合由這些SQL 語句所定義的規則。


25.winsock建立連線的主要實現步驟?
答:伺服器端:socker()建立套接字,繫結(bind)並監聽(listen),用accept()
等待客戶端連線。
客戶端:socker()建立套接字,連線(connect)伺服器,連線上後使用send()和recv(
),在套接字上寫讀資料,直至資料交換完畢,closesocket()關閉套接字。
伺服器端:accept()發現有客戶端連線,建立一個新的套接字,自身重新開始等待連
接。該新產生的套接字使用send()和recv()寫讀資料,直至資料交換完畢,closesock
et()關閉套接字。


26.動態連線庫的兩種方式?
答:呼叫一個DLL中的函式有兩種方法:
1.載入時動態連結(load-time dynamic linking),模組非常明確呼叫某個匯出函式
,使得他們就像本地函式一樣。這需要連結時連結那些函式所在DLL的匯入庫,匯入庫向
系統提供了載入DLL時所需的資訊及DLL函式定位。
2.執行時動態連結(run-time dynamic linking),執行時可以通過LoadLibrary或Loa
dLibraryEx函式載入DLL。DLL載入後,模組可以通過呼叫GetProcAddress獲取DLL函式的
出口地址,然後就可以通過返回的函式指標呼叫DLL函數了。如此即可避免匯入庫檔案了



27.IP組播有那些好處?
答:Internet上產生的許多新的應用,特別是高頻寬的多媒體應用,帶來了頻寬的急劇
消耗和網路擁擠問題。組播是一種允許一個或多個傳送者(組播源)傳送單一的資料包
到多個接收者(一次的,同時的)的網路技術。組播可以大大的節省網路頻寬,因為無
論有多少個目標地址,在整個網路的任何一條鏈路上只傳送單一的資料包。所以說組播
技術的核心就是針對如何節約網路資源的前提下保證服務質量。




1.static有什麼用途?(請至少說明兩種)
    1)在函式體,一個被宣告為靜態的變數在這一函式被呼叫過程中維持其值不變。
    2) 在模組內(但在函式體外),一個被宣告為靜態的變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問。它是一個本地的全域性變數。
    3) 在模組內,一個被宣告為靜態的函式只可被這一模組內的其它函式呼叫。那就是,這個函式被限制在宣告它的模組的本地範圍內使用


2.引用與指標有什麼區別?
    1) 引用必須被初始化,指標不必。
    2) 引用初始化以後不能被改變,指標可以改變所指的物件。
    3) 不存在指向空值的引用,但是存在指向空值的指標。


3.描述實時系統的基本特性
       在特定時間內完成特定的任務,實時性與可靠性。


4.全域性變數和區域性變數在記憶體中是否有區別?如果有,是什麼區別?
      全域性變數儲存在靜態資料庫,區域性變數在堆疊。




華為
1、區域性變數能否和全域性變數重名?
     答:能,區域性會遮蔽全域性。要用全域性變數,需要使用"::"
區域性變數可以與全域性變數同名,在函式內引用這個變數時,會用到同名的區域性變數,而不會用到全域性變數。對於有些編譯器而言,在同一個函式內可以定義多個同名的區域性變數,比如在兩個迴圈體內都定義一個同名的區域性變數,而那個區域性變數的作用域就在那個迴圈體內。


2、如何引用一個已經定義過的全域性變數?
     答:extern
     可以用引用標頭檔案的方式,也可以用extern關鍵字,如果用引用標頭檔案方式來引用某個在標頭檔案中宣告的全域性變理,假定你將那個變寫錯了,那麼在編譯期間會報錯,如果你用extern方式引用時,假定你犯了同樣的錯誤,那麼在編譯期間不會報錯,而在連線期間報錯。


3、全域性變數可不可以定義在可被多個.C檔案包含的標頭檔案中?為什麼?
    答:可以,在不同的C檔案中以static形式來宣告同名全域性變數。
    可以在不同的C檔案中宣告同名的全域性變數,前提是其中只能有一個C檔案中對此變數賦初值,此時連線不會出錯。


4、語句for( ;1 ;)有什麼問題?它是什麼意思?
    答:無限迴圈,和while(1)相同。


5、do……while和while……do有什麼區別?
    答:前一個迴圈一遍再判斷,後一個判斷以後再迴圈。


6、請寫出下列程式碼的輸出內容
#i nclude<stdio.h>
main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
答:10,12,120




1、static全域性變數與普通的全域性變數有什麼區別?static區域性變數和普通區域性變數有什麼區別?static函式與普通函式有什麼區別?
    答:全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式, 靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。這兩者的區別雖在於非靜態全域性變數的作用域是整個源程式,當一個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。而靜態全域性變數則限制了其作用域, 即只在定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於一個原始檔內,只能為該原始檔內的函式公用,因此可以避免在其它原始檔中引起錯誤。
    從以上分析可以看出,把區域性變數改變為靜態變數後是改變了它的儲存方式即改變了它的生存期。把全域性變數改變為靜態變數後是改變了它的作用域,限制了它的使用範圍。
    static函式與普通函式作用域不同。僅在本檔案。只在當前原始檔中使用的函式應該說明為內部函式(static),內部函式應該在當前原始檔中說明和定義。對於可在當前原始檔以外使用的函式,應該在一個頭檔案中說明,要使用這些函式的原始檔要包含這個標頭檔案
    static全域性變數與普通的全域性變數有什麼區別:static全域性變數只初使化一次,防止在其他檔案單元中被引用;
    static區域性變數和普通區域性變數有什麼區別:static區域性變數只被初始化一次,下一次依據上一次結果值;
    static函式與普通函式有什麼區別:static函式在記憶體中只有一份,普通函式在每個被呼叫中維持一份拷貝


2、程式的區域性變數存在於(堆疊)中,全域性變數存在於(靜態區)中,動態申請資料存在於(堆)中。


3、設有以下說明和定義:
typedef union {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
則語句 printf("%d",sizeof(struct date)+sizeof(max));的執行結果是:___52____
    答:DATE是一個union, 變數公用空間. 裡面最大的變數型別是int[5], 佔用20個位元組. 所以它的大小是20
data是一個struct, 每個變數分開佔用空間. 依次為int4 + DATE20 + double8 = 32.
所以結果是 20 + 32 = 52.
當然...在某些16位編輯器下, int可能是2位元組,那麼結果是 int2 + DATE10 + double8 = 20


4、佇列和棧有什麼區別?
    佇列先進先出,棧後進先出


5、寫出下列程式碼的輸出內容
#i nclude<stdio.h>
int inc(int a)
{
return(++a);
}
int multi(int*a,int*b,int*c)
{
return(*c=*a**b);
}
typedef int(FUNC1)(int in);
typedef int(FUNC2) (int*,int*,int*);


void show(FUNC2 fun,int arg1, int*arg2)
{
INCp=&inc;
int temp =p(arg1);
fun(&temp,&arg1, arg2);
printf("%d\n",*arg2);
}


main()
{
int a;
show(multi,10,&a);
return 0;
}
答:110






微軟亞洲技術中心的面試題!!!
1.程序和執行緒的差別。
執行緒是指程序內的一個執行單元,也是程序內的可排程實體.
與程序的區別:
(1)排程:執行緒作為排程和分配的基本單位,程序作為擁有資源的基本單位
(2)併發性:不僅程序之間可以併發執行,同一個程序的多個執行緒之間也可併發執行
(3)擁有資源:程序是擁有資源的一個獨立單位,執行緒不擁有系統資源,但可以訪問隸屬於程序的資源.
(4)系統開銷:在建立或撤消程序時,由於系統都要為之分配和回收資源,導致系統的開銷明顯大於建立或撤消執行緒時的開銷。
2.測試方法
人工測試:個人複查、抽查和會審
機器測試:黑盒測試和白盒測試


2.Heap與stack的差別。
Heap是堆,stack是棧。
Stack的空間由作業系統自動分配/釋放,Heap上的空間手動分配/釋放。
Stack空間有限,Heap是很大的自由儲存區
C中的malloc函式分配的記憶體空間即在堆上,C++中對應的是new操作符。
程式在編譯期對變數和函式分配記憶體都在棧上進行,且程式執行過程中函式呼叫時引數的傳遞也在棧上進行
3.Windows下的記憶體是如何管理的?
4.介紹.Net和.Net的安全性。
5.客戶端如何訪問.Net元件實現Web Service?
6.C/C++編譯器中虛表是如何完成的?
7.談談COM的執行緒模型。然後討論程序內/外元件的差別。
8.談談IA32下的分頁機制
小頁(4K)兩級分頁模式,大頁( 4M)一級
9.給兩個變數,如何找出一個帶環單鏈表中是什麼地方出現環的?
一個遞增一,一個遞增二,他們指向同一個接點時就是環出現的地方
10.在IA32中一共有多少種辦法從使用者態跳到核心態?
通過呼叫門,從ring3到ring0,中斷從ring3到ring0,進入vm86等等
11.如果只想讓程式有一個例項執行,不能執行兩個。像winamp一樣,只能開一個視窗,怎樣實現?
用記憶體對映或全域性原子(互斥變數)、查詢視窗控制代碼..
FindWindow,互斥,寫標誌到檔案或登錄檔,共享記憶體。.  
12.如何擷取鍵盤的響應,讓所有的‘a’變成‘b’?
鍵盤鉤子SetWindowsHookEx
 13.Apartment在COM中有什麼用?為什麼要引入?
 14.儲存過程是什麼?有什麼用?有什麼優點?
我的理解就是一堆sql的集合,可以建立非常複雜的查詢,編譯執行,所以執行一次後,以後再執行速度比單獨執行SQL快很多
 15.Template有什麼特點?什麼時候用?
16.談談Windows DNA結構的特點和優點。




網路程式設計中設計併發伺服器,使用多程序 與 多執行緒,請問有什麼區別?
1,程序:子程序是父程序的複製品。子程序獲得父程序資料空間、堆和棧的複製品。
2,執行緒:相對與程序而言,執行緒是一個更加接近與執行體的概念,它可以與同進程的其他執行緒共享資料,但擁有自己的棧空間,擁有獨立的執行序列。
兩者都可以提高程式的併發度,提高程式執行效率和響應時間。
執行緒和程序在使用上各有優缺點:執行緒執行開銷小,但不利於資源管理和保護;而程序正相反。同時,執行緒適合於在SMP機器上執行,而程序則可以跨機器遷移。






思科
1. 用巨集定義寫出swap(x,y)
#define swap(x, y)\
x = x + y;\
y = x - y;\
x = x - y;
2.陣列a[N],存放了1至N-1個數,其中某個數重複一次。寫一個函式,找出被重複的數字.時間複雜度必須為o(N)函式原型:
int do_dup(int a[],int N)
3 一語句實現x是否為2的若干次冪的判斷
int i = 512;
cout << boolalpha << ((i & (i - 1)) ? false : true) << endl;
4.unsigned int intvert(unsigned int x,int p,int n)實現對x的進行轉換,p為起始轉化位,n為需要轉換的長度,假設起始點在右邊.如x=0b0001 0001,p=4,n=3轉換後x=0b0110 0001
unsigned int intvert(unsigned int x,int p,int n){
unsigned int _t = 0;
unsigned int _a = 1;
for(int i = 0; i < n; ++i){
_t |= _a;
_a = _a << 1;
}
_t = _t << p;
x ^= _t;
return x;
}




慧通:
什麼是預編譯
何時需要預編譯:
1、總是使用不經常改動的大型程式碼體。
2、程式由多個模組組成,所有模組都使用一組標準的包含檔案和相同的編譯選項。在這種情況下,可以將所有包含檔案預編譯為一個預編譯頭。
char * const p;
char const * p
const char *p


上述三個有什麼區別?
char * const p; //常量指標,p的值不可以修改
char const * p;//指向常量的指標,指向的常量值不可以改
const char *p; //和char const *p


char str1[] = "abc";
char str2[] = "abc";


const char str3[] = "abc";
const char str4[] = "abc";


const char *str5 = "abc";
const char *str6 = "abc";


char *str7 = "abc";
char *str8 = "abc";




cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;


結果是:0 0 1 1
解答:str1,str2,str3,str4是陣列變數,它們有各自的記憶體空間;
而str5,str6,str7,str8是指標,它們指向相同的常量區域。




12. 以下程式碼中的兩個sizeof用法有問題嗎?[C易]
void UpperCase( char str[] ) // 將 str 中的小寫字母轉換成大寫字母
{
    for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
        if( 'a'<=str[i] && str[i]<='z' )
            str[i] -= ('a'-'A' );
}
char str[] = "aBcDe";
cout << "str字元長度為: " << sizeof(str)/sizeof(str[0]) << endl;
UpperCase( str );
cout << str << endl;


答:函式內的sizeof有問題。根據語法,sizeof如用於陣列,只能測出靜態陣列的大小,無法檢測動態分配的或外部陣列大小。函式外的str是一個靜態定義的陣列,因此其大小為6,函式內的str實際只是一個指向字串的指標,沒有任何額外的與陣列相關的資訊,因此sizeof作用於上只將其當指標看,一個指標為4個位元組,因此返回4。


一個32位的機器,該機器的指標是多少位
指標是多少位只要看地址匯流排的位數就行了。80386以後的機子都是32的資料匯流排。所以指標的位數就是4個位元組了。


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].






1.請問以下程式碼有什麼問題:
int  main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}
沒有為str分配記憶體空間,將會發生異常
問題出在將一個字串複製進一個字元變數指標所指地址。雖然可以正確輸出結果,但因為越界進行內在讀寫而導致程式崩潰。


char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);
有什麼錯?
"AAA"是字串常量。s是指標,指向這個字串常量,所以宣告s的時候就有問題。
cosnt char* s="AAA";
然後又因為是常量,所以對是s[0]的賦值操作是不合法的。


1、寫一個“標準”巨集,這個巨集輸入兩個引數並返回較小的一個。
.#define Min(X, Y) ((X)>(Y)?(Y):(X))//結尾沒有;
2、嵌入式系統中經常要用到無限迴圈,你怎麼用C編寫死迴圈。
while(1){}或者for(;;)
3、關鍵字static的作用是什麼?
定義靜態變數
4、關鍵字const有什麼含意?
表示常量不可以修改的變數。
5、關鍵字volatile有什麼含意?並舉出三個不同的例子?
提示編譯器物件的值可能在編譯器未監測到的情況下改變。




int (*s[10])(int) 表示的是什麼啊
int (*s[10])(int) 函式指標陣列,每個指標指向一個int func(int param)的函式。


1.有以下表達式:
int a=248; b=4Aa = a - b;
or
a = a^b;// 只能對int,char..
b = a^b;
a = a^b;
or
a ^= b ^= a;








1.有以下表達式:
int a=248; b=4;int const c=21;const int *d=&a;
int *const e=&b;int const *f const =&a;
請問下列表達式哪些會被編譯器禁止?為什麼?
*c=32;d=&b;*d=43;e=34;e=&a;f=0x 321f;
*c 這是個什麼東東,禁止
*d 說了是const, 禁止
e = &a 說了是const 禁止
const *f const =&a; 禁止
2.交換兩個變數的值,不使用第三個變數。即a=3,b=5,交換之後a=5,b=3;
有兩種解法, 一種用算術演算法, 一種用^(異或)
a = a + b;
b = a - b;
a = a - b;
or
a = a^b;// 只能對int,char..
b = a^b;
a = a^b;
or
a ^= b ^= a;
3.c和c++中的struct有什麼不同?
c和c++中struct的主要區別是c中的struct不可以含有成員函式,而c++中的struct可以。c++中struct和class的主要區別在於預設的存取許可權不同,struct預設為public,而class預設為private
4.#i nclude <stdio.h>
  #i nclude <stdlib.h>
  void getmemory(char *p)
  {
    p=(char *) malloc(100);
    strcpy(p,"hello world");
  }
  int main( )
  {
    char *str=NULL;
    getmemory(str);
    printf("%s/n",str);
    free(str);
    return 0;
   }
程式崩潰,getmemory中的malloc 不能返回動態記憶體, free()對str操作很危險
5.char szstr[10];
  strcpy(szstr,"0123456789");
  產生什麼結果?為什麼?
  長度不一樣,會造成非法的OS
6.列舉幾種程序的同步機制,並比較其優缺點。
   原子操作
訊號量機制
   自旋鎖
   管程,會合,分散式系統


7.程序之間通訊的途徑
共享儲存系統
訊息傳遞系統
管道:以檔案系統為基礎
11.程序死鎖的原因
資源競爭及程序推進順序非法
12.死鎖的4個必要條件
互斥、請求保持、不可剝奪、環路
13.死鎖的處理
鴕鳥策略、預防策略、避免策略、檢測與解除死鎖
15.   作業系統中程序排程策略有哪幾種?
FCFS(先來先服務),優先順序,時間片輪轉,多級反饋
8.類的靜態成員和非靜態成員有何區別?
類的靜態成員每個類只有一個,非靜態成員每個物件一個
9.純虛擬函式如何定義?使用時應注意什麼?
virtual void f()=0;
是介面,子類必須要實現
10.陣列和連結串列的區別
陣列:資料順序儲存,固定大小
連表:資料可以隨機儲存,大小可動態改變


12.ISO的七層模型是什麼?tcp/udp是屬於哪一層?tcp/udp有何優缺點?
應用層
表示層
會話層
運輸層
網路層
物理鏈路層
物理層
tcp /udp屬於運輸層
TCP 服務提供了資料流傳輸、可靠性、有效流控制、全雙工操作和多路複用技術等。
與 TCP 不同, UDP 並不提供對 IP 協議的可靠機制、流控制以及錯誤恢復功能等。由於 UDP 比較簡單, UDP 頭包含很少的位元組,比 TCP 負載消耗少。
tcp: 提供穩定的傳輸服務,有流量控制,缺點是包頭大,冗餘性不好
udp: 不提供穩定的服務,包頭小,開銷小  






1:(void *)ptr 和 (*(void**))ptr的結果是否相同?其中ptr為同一個指標
.(void *)ptr 和 (*(void**))ptr值是相同的
2:int main()
   {
    int x=3;
    printf("%d",x);
    return 1;
  
   }
問函式既然不會被其它函式呼叫,為什麼要返回1?
mian中,c標準認為0表示成功,非0表示錯誤。具體的值是某中具體出錯資訊




1,要對絕對地址0x100000賦值,我們可以用
(unsigned int*)0x100000 = 1234;
那麼要是想讓程式跳轉到絕對地址是0x100000去執行,應該怎麼做?
*((void (*)( ))0x100000 ) ( );
首先要將0x100000強制轉換成函式指標,即:
(void (*)())0x100000
然後再呼叫它:
*((void (*)())0x100000)();
用typedef可以看得更直觀些:
typedef void(*)() voidFuncPtr;
*((voidFuncPtr)0x100000)();
2,已知一個數組table,用一個巨集定義,求出資料的元素個數
#define NTBL
#define NTBL (sizeof(table)/sizeof(table[0]))


面試題: 執行緒與程序的區別和聯絡? 執行緒是否具有相同的堆疊? dll是否有獨立的堆疊?
程序是死的,只是一些資源的集合,真正的程式執行都是執行緒來完成的,程式啟動的時候作業系統就幫你建立了一個主執行緒。


每個執行緒有自己的堆疊。
DLL中有沒有獨立的堆疊,這個問題不好回答,或者說這個問題本身是否有問題。因為DLL中的程式碼是被某些執行緒所執行,只有執行緒擁有堆疊,如果DLL中的程式碼是EXE中的執行緒所呼叫,那麼這個時候是不是說這個DLL沒有自己獨立的堆疊?如果DLL中的程式碼是由DLL自己建立的執行緒所執行,那麼是不是說DLL有獨立的堆疊?


以上講的是堆疊,如果對於堆來說,每個DLL有自己的堆,所以如果是從DLL中動態分配的記憶體,最好是從DLL中刪除,如果你從DLL中分配記憶體,然後在EXE中,或者另外一個DLL中刪除,很有可能導致程式崩潰




unsigned short A = 10;
printf("~A = %u\n", ~A);


char c=128;
printf("c=%d\n",c);


輸出多少?並分析過程
第一題,~A =0xfffffff5,int值 為-11,但輸出的是uint。所以輸出4294967285
第二題,c=0x10,輸出的是int,最高位為1,是負數,所以它的值就是0x00的補碼就是128,所以輸出-128。
這兩道題都是在考察二進位制向int或uint轉換時的最高位處理。


分析下面的程式:
void GetMemory(char **p,int num)
{
    *p=(char *)malloc(num);
   
}       
int main()
{
    char *str=NULL;
   
    GetMemory(&str,100);
   
    strcpy(str,"hello");
   
    free(str);
   
    if(str!=NULL)
    {
        strcpy(str,"world");
    }   
       
    printf("\n str is %s",str);
    getchar();
}   
問輸出結果是什麼?希望大家能說說原因,先謝謝了
輸出str is world。
free 只是釋放的str指向的記憶體空間,它本身的值還是存在的.
所以free之後,有一個好的習慣就是將str=NULL.
此時str指向空間的記憶體已被回收,如果輸出語句之前還存在分配空間的操作的話,這段儲存空間是可能被重新分配給其他變數的,
儘管這段程式確實是存在大大的問題(上面各位已經說得很清楚了),但是通常會打印出world來。
這是因為,程序中的記憶體管理一般不是由作業系統完成的,而是由庫函式自己完成的。
當你malloc一塊記憶體的時候,管理庫向作業系統申請一塊空間(可能會比你申請的大一些),然後在這塊空間中記錄一些管理資訊(一般是在你申請的記憶體前面一點),並將可用記憶體的地址返回。但是釋放記憶體的時候,管理庫通常都不會將記憶體還給作業系統,因此你是可以繼續訪問這塊地址的,只不過。。。。。。。。樓上都說過了,最好別這麼幹。






港灣興業工程師入職面試題


 


1.第一部分C語言和資料結構(每題2分,共20分)


1.1
二叉樹的前序,中序和後序遍歷法最適合採用(1)-----來實現。
查詢樹中,由根結點到所有其他結點的路徑長度總和稱為(2)------。
而上述路徑長度總和達到最小的樹稱為(3)------,它一定是(4)------。
在關於樹的幾個敘述中,只有(5)------是正確的。


(1)A遞迴程式     B迭代程式      C佇列操作      D棧操作
(2)A路徑和       B內部路徑長度  C總深度        D深度和
(3)A   B-樹       B  B+樹        C豐滿樹        D穿線樹
(4)A   B-樹       B 平衡樹       C非平衡樹      D穿線樹
(5)A.用指標方式儲存有n個結點的二叉樹,至少要n+1個指標。
    B.m階B-樹中,每個非椰子結點的後件個數大於或等於[m/2]。
    C.m階B-樹中,具有K個後件的結點,必含有K-1個鍵值。
    D.平衡樹一定是豐滿樹。


 


1.2
設有說明語句:
      enum color{red,yellow,blue,white};
那麼yellow的值為(   )
A .1        B.2             C.YELLOW     Dyellow


 
1.3
i=4,那麼語句
   j=i+++1
執行後的結果應該是(    )
A.i=4,j=6   B.i=5,j=5   C.i=5,j=6   D.i=6,j=6


1.4
設a,b為整型數,且a=2,b=4,則表示式(a/b?b+a:b-a)的值為( C  )
A . 0.5    B. 6      C. 2   D 此表示式錯誤


1.5
對於說明語句
  int*p,array[10];
後續程式中不容許出現的語句是(  C )
A.p=array   B.*p=array[0]      C.p=&array    D.p=&array[0]


1.6
設n=10,i=4,則賦值運算
   n%=i+1
執行後n的值為(    )
A.0        B.1         C.2       D.3


2.第二部分  邏輯題(每題2分,共20分)


2.1
在中國東北有這樣兩個村落,趙村所有的村民都是白天祭祀祖先,而李莊的人都是晚上祭祀祖先,能肯定的沒人在白天和晚上都祭祀祖先的。我們也知道趙李明是晚上祭祀祖先的人,那麼以下哪個選項是正確的( B  )


A.趙李明是趙村的人。
B.趙李明不是趙村的人。
C.趙李明是李莊的人。
D.趙李明不是李莊的人。
E.趙李明既不是趙村的人,也不是李莊的人。




2.2
相傳在古時候某國的國民都分別居住在兩個怪城裡,一座“真城”,一座“假城”。凡真城的人個個都說真話,而假城的人個個都說假話。一位知道情況的外國遊客來到其中一個城市,他只問了一個問題就知道自己來到是哪個城了。下面哪個話最恰當(E  )


A.你是真城人嗎?
B.你是假城人嗎?
C.你是說真話的人嗎?
D.你是說假話的人嗎?
E.你是這個城市的人嗎?


2.3
設“並非無奸不商”為真,則下面哪個選項一定為真。( D   )


A.所有商人都是奸商。
B.所有商人都不是奸商。
C.並非所有商人不是奸商。
D.並非所有商人是奸商。
E.有的商人不是奸商。


2.4
The works of philosophers K,R,S,and W will be discussed in a series of four seminars.Each seminar in the series will be on exactly one of these philosophers, and no philosopher will be the focus of more than one of the seminers.The order in which these seminars can be conducted is constrained by the following conditions:


The seminar on W must be either the first or the last in the series.
The seminar on R must be conducted at some time before the seminar on S or at some time before the seminar on W but not before both.
The seminar on K cannot be the one immediately following the seminar on S.


(1)Which of the following could be the order in whith the four seminars are conducted?B


A. K,R,S,W
B. S,R,K,W
C. S,R,W,K
D. W,R,S,K
E. W,S,R,K


(2)If the frist seminar is on W,which of the following must be true?( D  )


A. The seminar on R is immediately after the seminar on W.
B. The seminar on S is immediately after the seminar on R.
C. The seminar on K is conducted at some time after the seminar on R.
D. The seminar on R is conducted at some time after the seminar on K.
E. The seminar on S is conducted at some time after the seminar on K.




(3)If the seminar on S is conducted at some time before the seminar on K,which of the following must be true?(  B )


A. The first seminar is on W.
B. The second seminar is on R.
C. The second seminar is on S.
D. The third seminar is on R.
E. The forth seminar is on K.


(4) If the seminar on K is the first seminar in the series,whith of the following must be true?(  BE  )


A. The second seminar is on R.
B. The second seminar is on S.
C. The seminar on K is immediately before the seminar on R.
D. The seminar on S is conducted at some time after the seminar on R.
E. The seminar on W is conducted at some time before the seminar on R.




(5)Which of the following can be true of the seminar series?( D )


A.The last seminar is on K.
B.The third seminar is on S.
C.The first seminar is on S and the third seminar is on R.
D.The seminar on S is conducted at some time before the seminar on K.
E.The seminar on W is immediately after the seminar on S.


(6)If the seminar on S is not the last seminar in the series,which of the following must be true?( E )


A.The first seminar is on K.
B.The first seminar is on S.
C.The second seminar is on K.
D.The second seminar is on R.
E.The last seminar is on W.


 


2.5
小趙比小錢個子高:小孫不小李個子高:小李個子不如小周高:小錢和小周個子正好一樣高。如果上述這些陳述都是對的,那麼,下列那項也是對的?(  )




A. 小孫比小周個子高。
B. 小孫比小趙個子高。
C. 小錢比小孫個子矮。
D. 小趙比小李個子高。
E.  小錢比小李個子矮。


3.第三部分  作業系統(每題2分,共20分)


3.1


計算機指令系統往往具有多種定址方式。運算元就是指令的一部分稱為--(1)定址,運算元地址在指令中稱為--(2)定址。當運算元地址在暫存器中,就採用--(3)定址方式。假設基址暫存器的內容為2000H,變址積存器的內容為03A0H,指令的地址碼部分為3FH,當前正在執行的指令所在地址為 2B00H。若採用相對定址方式,則資料實際地址為--(4),若採用變址定址,並考慮基址,資料的實際地址為--(5)。


C(1)A 直接      B 運算器      C 立即數      D 指令
A(2)A 直接      B 間接        C 堆疊        D記憶體
C(3)A 直接      B 暫存器      C 暫存器間址  D變址
C(4)A 23A0H     B  4B00H      C 2B3FH     D 2EA0H
B(5)A 23DFH     B 4B3FH        C23A0H     D203FH


3.2.
作業系統中,可以並行工作的基本單位是--(1),--(1)也是核心排程及資源分配的基本單位,它是由--(2)組成的,它與程式的重要區別之一是--(3)。當因資源競爭可能會引起死鎖時,可以有兩種策略對付;--(4)和--(5)。其中--(4)付出的代價較高。
C(1)A.作業      B.函式       C.程序      D.過程
C(2)  B.程式,資料和PCB。  B.程式,資料和識別符號  C.程式,識別符號和PCB  D.資料,識別符號和PCB。
B(3) A.程式有狀態,而它沒有。B它有狀態,而程式沒有。C 程式可佔有資源,而它不可。D.它能佔有資源,而程式不能。
AC(4),(5) .A.死鎖的避免和預防。B修改控制字。C 死鎖的檢測和修復。D撤消鎖。E 改寫Config檔案。F 重新啟動。




4.第四部分 TCP/IP(每題兩分,共10分)


4.1
國際標準化組織OSI基本參考模型有--(1)層。IP,TCP和EHTERNET分別是對應於該模型中的--(2),--(3)和--(4)的協議。在因特網協議組中,與TCP在同一層的協議還有--(5)。


C(1)A 5      B 6        C7          D8
A(2)A網路層 B運輸層    C會話層     D媒體訪問控制層
B(3)A網路層 B運輸層    C會話層     D媒體訪問控制層
D(4)A應用層 B物理層    C表示層     D資料鏈路層
A(5)A  UDP  B   NCP    C ARP        D ICMP


 


5. 第五部分  改錯和程式設計


5.1   請指出下列程式中的錯誤並改正
從記憶體地址為0x80000000順序讀取256個字元,存入動態分配的記憶體中


main( )
{
 char*p1,p2=(char*)0x80000000;
 int num=256;
unsigned char i;
 *p1=malloc(num);
 if(p1=NULL)exit(-1);
 for(i=0;i<num;i++){
   *p1++=*++p2;
}
}


5.2   請指出下列程式中的錯誤並改正


根據命令列引數的第1個字元,呼叫巨集,實現變數先左移後相加。


  #define add(x,y,z)
        { \
         x<<z+y;\
        }
main(int argc,char argv[])
{
 int a=10,b=5,t;
 switch(argv[1][0])
{
   case’1’:t=add(a