http://blog.csdn.net/h_armony/article/details/6764811html
1. 嵌入式系統中斷服務子程序(ISR) node
中斷是嵌入式系統中重要的組成部分,這致使了很 多編譯開發商提供一種擴展—讓標準C支持中斷。具表明事實是,產生了一個新的關鍵字 __interrupt。下面的代碼就使用了__interrupt關鍵字去定義了一箇中斷服務子程序(ISR),請評論一下這段代碼的。linux
__interrupt double compute_area (double radius)c++
{ double area = PI * radius * radius;程序員
printf(" Area = %f", area);web
return area;面試
}算法
1). ISR 不能返回一個值。sql
2). ISR 不能傳遞參數。shell
3). 在許多的處理器/編譯器中,浮點通常都是不可重入的。有些處理器/編譯器須要讓額處的寄存器入棧,有些處理器/編譯器就是不容許在ISR中作浮點運算。此外,ISR應該是短而有效率的,在ISR中作浮點運算是不明智的。
4). 與第三點一脈相承,printf()常常有重入和性能上的問題。
2.C語言中對位的操做,好比對a的第三位清0,第四位置1.原本應該會的,一犯暈寫反了,之後注意!
#define BIT3 (1<<3)
#define BIT4 (1<<4)
a &= ~BIT3; a |= BIT4;
3.volatile
表示這個變量會被意想不到的改變,每次用他的時候都會當心的從新讀取一遍,不適用寄存器保存的副本。
volatile表示直接存取原始地址
例:
並行設備的硬件寄存器(狀態寄存器)
在多線程運行的時候共享變量也要時時更新
一箇中斷服務子程序中訪問到的的非自動變量(定義變量時默認爲自動變量,這裏指全局變量或加修飾的變量)
4.Const:
Const char*p //p 指向的內容不能被修改
Char const *p; // p指針指向內容不能修改
Const (char*) p; //p指針不能修改,p++ 操做會出錯
Const type fun(); // 返回值類型爲一個const type類型,不能修改
Fun( const char *p); //保護指針,引用傳遞的值不被修改.
類成員函數:中 fun() const; //代表FUN不能修改爲員變量,不調用非const 成員函數.
5.要求設置一絕對地址爲0x67a9 的整型變量的值爲0xaa66
int *ptr = (int *)0x67a9;
*ptr = 0xaa66;
六、
#include "stdio.h"
int a=0;
int b;
static char c;
int main(int argc,char *argv[])
{
char d=4;
static short e;
a++;
b=100;
c=(char)++a;
e=(++d)++;
printf("a=%d, b=%d, c=%d, d= %d, e=%d",a,b,c,d,e);
return 0;
}
a) 寫出程序輸出
答案:a = 2, b = 100, c = 2, d = 6, e = 5
7a)對於整形變量A=0x12345678,請畫出在little endian及big endian的方式下在內存中是如何存儲的?
little endian big endian 恰好反過來
高地址--〉 0x12 低地址--〉 0x12
0x34 0x34
0x56 0x56
低地址--〉 0x78 高地址--〉 0x78
記憶方法:
小端模式 : 地址的增加順序與值的增加順序相同(x86爲小端模式)
大端模式 : 地址的增加順序與值的增加順序相反
b)在ARM系統中,函數調用的時候,參數是經過哪一種方式傳遞的?
參數<=4時候,經過R0~R3傳遞,>4的經過壓棧方式傳遞
8 .1請實現內存複製函數void* memcpy(void* dst, void* src, int count)。
精簡版
8.二、不使用庫函數,編寫函數int strcmp(char *source, char *dest)相等返回0,不等返回-1;
9.一、在數組定義int a[2][2]={{3},{2,3}};則a[0][1]的值爲0。(對)
9.二、
問打印出來結果是多少?
答案:1.
分析:花括號裏嵌套的是小括號而不是花括號!這裏是花括號裏面嵌套了逗號表達式!其實這個賦值就至關於int a [3][2]={ 1, 3, 5};
10.0 輸入任意字符串,打印輸出其逆序:
十一、寫一函數int fun(char *p)判斷一字符串是否爲迴文,是返回1,不是返回0,出錯返回-1
先發基本問題,再發編程問題..........
想成爲嵌入式程序員應知道的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. 嵌入式系統常常具備要求程序員去訪問某特定的內存位置的特色。在某工程中,要求設置一絕對地址爲0x 67a9的整型變量的值爲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
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.全局變量和局部變量在內存中是否有區別?若是有,是什麼區別?
全局變量儲存在靜態數據庫,局部變量在堆棧。
華為
一、局部變量可否和全局變量重名?
答:能,局部會屏蔽全局。要用全局變量,須要使用"::"
局部變量能夠與全局變量同名,在函數內引用這個變量時,會用到同名的局部變量,而不會用到全局變量。對於有些編譯器而言,在同一個函數內能夠定義多個同名的局部變量,好比在兩個循環體內都定義一個同名的局部變量,而那個局部變量的做用域就在那個循環體內。
二、如何引用一個已經定義過的全局變量?
答:extern
能夠用引用頭文件的方式,也能夠用extern關鍵字,若是用引用頭文件方式來引用某個在頭文件中聲明的全局變理,假定你將那個變寫錯了,那麼在編譯期間會報錯,若是你用extern方式引用時,假定你犯了一樣的錯誤,那麼在編譯期間不會報錯,而在鏈接期間報錯。
三、全局變量可不能夠定義在可被多個.C文件包含的頭文件中?爲何?
答:能夠,在不一樣的C文件中以static形式來聲明同名全局變量。
能夠在不一樣的C文件中聲明同名的全局變量,前提是其中只能有一個C文件中對此變量賦初值,此時鏈接不會出錯。
四、語句for( ;1 ;)有什麼問題?它是什麼意思?
答:無限循環,和while(1)相同。
五、do……while和while……do有什麼區別?
答:前一個循環一遍再判斷,後一個判斷之後再循環。
六、請寫出下列代碼的輸出內容
#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
一、static全局變量與普通的全局變量有什麼區別?static局部變量和普通局部變量有什麼區別?static函數與普通函數有什麼區別?
答:全局變量(外部變量)的說明以前再冠以static 就構成了靜態的全局變量。全局變量自己就是靜態存儲方式, 靜態全局變量固然也是靜態存儲方式。 這二者在存儲方式上並沒有不一樣。這二者的區別雖在於非靜態全局變量的做用域是整個源程序,當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。 而靜態全局變量則限制了其做用域, 即只在定義該變量的源文件內有效, 在同一源程序的其它源文件中不能使用它。因爲靜態全局變量的做用域侷限於一個源文件內,只能爲該源文件內的函數公用,所以能夠避免在其它源文件中引發錯誤。
從以上分析能夠看出, 把局部變量改變爲靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變爲靜態變量後是改變了它的做用域,限制了它的使用範圍。
static函數與普通函數做用域不一樣。僅在本文件。只在當前源文件中使用的函數應該說明爲內部函數(static),內部函數應該在當前源文件中說明和定義。對於可在當前源文件之外使用的函數,應該在一個頭文件中說明,要使用這些函數的源文件要包含這個頭文件
static全局變量與普通的全局變量有什麼區別:static全局變量只初使化一次,防止在其餘文件單元中被引用;
static局部變量和普通局部變量有什麼區別:static局部變量只被初始化一次,下一次依據上一次結果值;
static函數與普通函數有什麼區別:static函數在內存中只有一份,普通函數在每一個被調用中維持一份拷貝
二、程序的局部變量存在於(堆棧)中,全局變量存在於(靜態區)中,動態申請數據存在於( 堆)中。
三、設有如下說明和定義:
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
四、隊列和棧有什麼區別?
隊列先進先出,棧後進先出
五、寫出下列代碼的輸出內容
#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]的賦值操做是不合法的。
一、寫一個「標準」宏,這個宏輸入兩個參數並返回較小的一個。
.#define Min(X, Y) ((X)>(Y)?(Y):(X))//結尾沒有;
二、嵌入式系統中常常要用到無限循環,你怎麼用C編寫死循環。
while(1){}或者for(;;)
三、關鍵字static的做用是什麼?
定義靜態變量
四、關鍵字const有什麼含意?
表示常量不能夠修改的變量。
五、關鍵字volatile有什麼含意?並舉出三個不一樣的例子?
提示編譯器對象的值可能在編譯器未監測到的狀況下改變。
int (*s[10])(int) 表示的是什麼啊
int (*s[10])(int) 函數指針數組,每一個指針指向一個int func(int param)的函數。
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,b,1);
case’2’:t=add(a,b,2);
default:break;
}
}
5.3 閱讀下列程序或函數說明和C代碼,將應填入---(n)處的字句寫在答題紙的對應欄內
[程序說明]
本程序中的函數factor(m,fac,cp)用來計算正數m(m>2)的除自身之外的全部不一樣因子的和。該函數返回因子和,並把各因子從小到大依次存放在數組fac中,其因子個數存入在cp所指的變量中。
例如 m=16,求得的因子爲
(1,2,4,8)
因子和爲15,因子個數爲4。
程序假定正整數m的不一樣因子個數不會超過100個。
[程序]
#include
#define N 100
long factor(int m,int fac[],int*cp)
{
int c1,c2,i,k;
long s;
fac[0]=1;
for(c1=s=1,c2=N-1, i= 2 ;;)
{
k=m/i;
if( m%i == 0 )
if( i<k )
{
fac[c1++]=i ;
fac[c2--]=k;
s+=i;
}
i++;
if(i>k)break;
}
for(c2++; c2<=N-1; c2++)
{
fac[c1++] = fac[c2];
s +=fac[c2];
}
cp=c1;
return s ;
}
本試題僅用於考查C++/C程序員的基本編程技能。內容限於C++/C經常使用語法,不涉及數據結構、算法以及深奧的語法。考試成績能反映出考生的編程質量以及對C++/C的理解程度,但不能反映考生的智力和軟件開發能力。
筆試時間90分鐘。請考生認真答題,切勿輕視。
1、請填寫BOOL , float, 指針變量 與「零值」比較的 if 語句。(10分)
提示:這裏「零值」能夠是0, 0.0 , FALSE或者「空指針」。例如 int 變量 n 與「零值」比較的 if 語句爲:
if ( n == 0 )
if ( n != 0 )
以此類推。
請寫出 BOOL flag 與「零值」比較的 if 語句:
|
請寫出 float x 與「零值」比較的 if 語句:
|
請寫出 char *p 與「零值」比較的 if 語句:
|
2、如下爲Windows NT下的32位C++程序,請計算sizeof的值(10分)
char str[] = 「Hello」 ; char *p = str ; int n = 10; 請計算 sizeof (str ) =
sizeof ( p ) =
sizeof ( n ) = |
void Func ( char str[100]) { 請計算 sizeof( str ) = }
|
void *p = malloc( 100 ); 請計算 sizeof ( p ) =
|
3、簡答題(25分)
一、頭文件中的 ifndef/define/endif 幹什麼用?
二、#include <filename.h> 和 #include 「filename.h」 有什麼區別?
三、const 有什麼用途?(請至少說明兩種)
四、在C++ 程序中調用被 C編譯器編譯後的函數,爲何要加 extern 「C」聲明?
五、請簡述如下兩個for循環的優缺點
// 第一個 for (i=0; i<N; i++) { if (condition) DoSomething(); else DoOtherthing(); } |
// 第二個 if (condition) { for (i=0; i<N; i++) DoSomething(); } else { for (i=0; i<N; i++) DoOtherthing(); } |
優勢:
缺點:
|
優勢:
缺點:
|
4、有關內存的思考題(20分)
void GetMemory(char *p) { p = (char *)malloc(100); } void Test(void) { char *str = NULL; GetMemory(str); strcpy(str, "hello world"); printf(str); }
請問運行Test函數會有什麼樣的結果? 答:
|
char *GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char *str = NULL; str = GetMemory(); printf(str); }
請問運行Test函數會有什麼樣的結果? 答: |
Void GetMemory2(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); } 請問運行Test函數會有什麼樣的結果? 答:
|
void Test(void) { char *str = (char *) malloc(100); strcpy(str, 「hello」); free(str); if(str != NULL) { strcpy(str, 「world」); printf(str); } } 請問運行Test函數會有什麼樣的結果? 答:
|
5、編寫strcpy函數(10分)
已知strcpy函數的原型是
char *strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。
(1)不調用C++/C的字符串庫函數,請編寫函數 strcpy
(2)strcpy能把strSrc的內容複製到strDest,爲何還要char * 類型的返回值?
6、編寫類String的構造函數、析構函數和賦值函數(25分)
已知類String的原型爲:
class String
{
public:
String(const char *str = NULL); // 普通構造函數
String(const String &other); // 拷貝構造函數
~ String(void); // 析構函數
String & operate =(const String &other); // 賦值函數
private:
char *m_data; // 用於保存字符串
};
請編寫String的上述4個函數。
下列程序在32位linux或unix中的結果是什麼?
func(char *str)
{
printf(" %d",sizeof(str));
printf(" %d",strlen(str));
}
main()
{
char a[]="123456789";
printf(" %d",sizeof(a));
printf(" %d",strlen(a));
func(a);
}
結果: 10 9 4 9
第一題:寫出下述程序結果:
int m[][3] = {1,4,7,2,5,8,3,6,9};
int i, j, k = 2;
for (i = 0; i < 3; i++) {
printf(「%d」, m[k]);
}
結果爲地址
第二題:下列哪一個引用是不正確的?
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, *p = a;
(A) a[p-a]; (B) *(&a); (c) p; (D) *(*(a+i));
答:D
第三題:下列4個選項中,哪一個結果爲6?
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, *p = a;
(A) *p + 6; (B) *(p+6); (C) *p += 5; (D) p+5;
答: A B
一、寫一個「標準」宏MIN,這個宏輸入兩個參數並返回較小的一個。
答: #define MIN(x,y) (x)<(y)?(x):(y)
二、給定一個整型變量a,寫兩段代碼,第一個設置a的bit 3,第二個清除a 的bit 3。在以上兩個操做中,要保持其它位不變。
答: int a = 2;
int i ;
i = 1 <<2;
a = a | i;
三、在某工程中,要求設置一絕對地址爲0x67a9的整型變量的值爲0xaa66。寫代碼去完成這一任務。
答: int *p = 0x67a9;
*p = 0xaa66;
聽說是emc公司的。
問這段程序執行之後不算main所在進程自己,一共建立了多少進程。
int main(int argc, char* argv[])
{
fork();
fork() && fork() || fork();
fork();
return 0;
}
----------------------標準分割線-----------------------------
這道題至少考了三個基礎的知識點。
1.運算符的默認優先級。
2.fork
3.C/C++裏面的短路計算(Short-circuit evaluation)
1 讀程序段,回答問題
int main(int argc,char *argv[])
{
int c=9,d=0;
c=c++%5;
d=c;
printf("d=%d\n",d);
return 0;
}
a) 寫出程序輸出
b) 在一個可移植的系統中這種表達式是否存在風險?why?
#include "stdio.h"
int a=0;
int b;
static char c;
int main(int argc,char *argv[])
{
char d=4;
static short e;
a++;
b=100;
c=(char)++a;
e=(++d)++;
printf("a=%d, b=%d, c=%d, d= %d, e=%d",a,b,c,d,e);
return 0;
}
a) 寫出程序輸出
b) 編譯器若是安排各個變量(a,b,c,d)在內存中的佈局(eg. stack,heap,data section,bss section),最好用圖形方式描述。
2 中斷是嵌入式系統中重要的組成部分,這致使了許多編譯開發商提供一種擴展:讓標準C支持中斷,產生了一個新的關鍵字__interrupt。下面的代碼就使用了__interrupt關鍵字去定義了一箇中斷服務子程序(ISR),請評論如下這段代碼。
__interrupt double compute_area(double radius)
{
double area = PI * radius *radius;
printf("nArea = %f", area);
return area;
}
3 C/C++基礎知識問題
a) 關鍵字volatile在編譯時有什麼含義?並給出三個不一樣使用場景的例子(能夠僞代碼或者文字描述)。
b) C語言中static關鍵字的具體做用有哪些 ?
c) 請問下面三種變量聲明有何區別?請給出具體含義
int const *p;
int* const p;
int const* const p;
4 嵌入式系統相關問題
a) 對於整形變量A=0x12345678,請畫出在little endian及big endian的方式下在內存中是如何存儲的。
b) 在ARM系統中,函數調用的時候,參數是經過哪一種方式傳遞的?
c) 中斷(interrupt,如鍵盤中斷)與異常(exception,如除零異常)有何區別?
5 設週期性任務P1,P2,P3的週期爲T1,T2,T3分別爲100,150,400;執行時間分別爲20,40,100。請設計一種調度算法進行任務調度,知足任務執行週期及任務週期。
6 優先級反轉問題在嵌入式系統中是一中嚴重的問題,必須給與足夠重視。
a) 首先請解釋優先級反轉問題
b) 不少RTOS提供優先級繼承策略(Priority inheritance)和優先級天花板策略(Priority ceilings)用來解決優先級反轉問題,請討論這兩種策略。
這一事實發生時,才擡升低優先級任務的優先級。
1 讀程序段,回答問題
int main(int argc,char *argv[])
{
int c=9,d=0;
c=c++%5;
d=c;
printf("d=%d\n",d);
return 0;
}
a) 寫出程序輸出
5
b) 在一個可移植的系統中這種表達式是否存在風險?why?
#include "stdio.h"
int a=0;
int b;
static char c;
int main(int argc,char *argv[])
{
char d=4;
static short e;
a++;
b=100;
c=(char)++a;
e=(++d)++;
printf("a=%d, b=%d, c=%d, d= %d, e=%d",a,b,c,d,e);
return 0;
}
a) 寫出程序輸出
之前學過c++,這個是能夠的 e=(++d)++;
如今才發如今c中,這是不行的
a=2, b=100, c=2, d= 6, e=5
b) 編譯器若是安排各個變量(a,b,c,d)在內存中的佈局(eg. stack,heap,data section,bss section),最好用圖形方式描述。
data section: a
bss section: b,c,e
stack d
在採用段式內存管理的架構中,數據段(data segment)一般是指用來存放程序中已初始化的全局變量的一塊內存區域。數據段屬於靜態內存分配。
在採用段式內存管理的架構中,BSS段(bss segment)一般是指用來存放程序中未初始化的全局變量的一塊內存區域。BSS是英文Block Started by Symbol的簡稱。BSS段屬於靜態內存分配。
4 嵌入式系統相關問題
a) 對於整形變量A=0x12345678,請畫出在little endian及big endian的方式下在內存中是如何存儲的。
low - > high
little endian 0x78 0x56 0x34 0x12
big endian 0x12 0x34 0x56 0x78
b) 在ARM系統中,函數調用的時候,參數是經過哪一種方式傳遞的?
在arm彙編中,若是不超過4個參數時,是經過r0 -r3寄存器來傳遞參數,>4的經過壓棧方式傳遞 。
c) 中斷(interrupt,如鍵盤中斷)與異常(exception,如除零異常)有何區別?
在《Linux內核設計與實現》一書中,說道:
異常 :在產生時必須考慮與處理器的時鐘同步,實踐上,異常也稱爲同步中斷。在處理器執行到因爲編程失誤而致使的錯誤指令時,或者在執行期間出現特殊狀況(如缺頁),必須靠內核處理的時候,處理器就會產生一個異常。
中斷可分爲同步(synchronous)中斷和異步(asynchronous)中斷:
1. 同步中斷是當指令執行時由 CPU 控制單元產生,之因此稱爲同步,是由於只有在一條指令執行完畢後 CPU 纔會發出中斷,而不是發生在代碼指令執行期間,好比系統調用。
2. 異步中斷是指由其餘硬件設備依照 CPU 時鐘信號隨機產生,即意味着中斷可以在指令之間發生,例如鍵盤中斷。
所謂中斷應該是指外部硬件產生的一個電信號,從cpu的中斷引腳進入,打斷cpu當前的運行;
所謂異常,是指軟件運行中發生了一些必須做出處理的事件,cpu自動產生一個陷入來打斷當前運行,轉入異常處理流程。
6 優先級反轉問題在嵌入式系統中是一中嚴重的問題,必須給與足夠重視。
a) 首先請解釋優先級反轉問題
高優先級任務須要等待低優先級任務釋放資源,而低優先級任務又正在等待中等優先級任務的現象叫作優先級反轉
b) 不少RTOS提供優先級繼承策略(Priority inheritance)和優先級天花板策略(Priority ceilings)用來解決優先級反轉問題,請討論這兩種策略。
優先級繼承策略(Priority inheritance):最低優先級任務繼承現有被阻塞任務的最高優先級做爲其優先級,任務退出臨界區,恢
復初始優先級。
優先級天花板策略(Priority ceilings):控制訪問臨界資源的信號量的優先級天花板。
優先級繼承策略對任務執行流程的影響相對教小,由於只有當高優先級任務申請已被低優先級任務佔有的臨界資源
這一事實發生時,才擡升低優先級任務的優先級。
1.via的考題一道
這個程序設計的思想是這樣的: 爲了測試32位機上的浮點數的運算精度,做以下考慮: 當1.5 == 1時(二進制1.1==1)精度爲1個小數位 當1.25 == 1時(二進制1.01==1)精度爲2個小數位 繼續判斷測試,直到二者相等,從而獲得精度。 因此程序代碼以下: int main() { int nCount; float number1,number2; nCount = 0; number1 = 1.0; number2 = 1.0 while( number1 + number2 != number1 ){ nCount++; number2 /= 2.0; } printf( "%d bits accruacy.\n", nCount ); } 問題是,結果爲多少? 經測試得64或者53或者24(稍加改動)。。。 得53和24已基本得出答案,主要是ieee 754標準中規定單雙精度數字的底數 指數 符號位所置。。。64的目前尚未得出結論。。。 2.改錯題 void mymul(double *p) { *p *= 2.0; } int main(int argc, char *argv[]) { float f = 6.0; mymul((double *) &f); printf("now f = %f\n", f); return 0; } 直接運行,結果爲6.00000 這個題目很簡單,能夠有不少種改法,如:a.把float f=6.0;改成double f=6.0;睛面的mymul句不要強制類型轉化 b.把全部的數都當成float型來處理 等等 但往細的方面想,float型默認4字節,double型默認8字節,雖然在vc6下能勉強運行(運行時報出調試窗口),但單步跟蹤發如今mymul()中並無獲得正確執行,而是:Access Violation,這個錯誤經常在計算機用戶運行的程序試圖存取未被指定使用的存儲區時遇到中,可見mymyl()這個函數並無獲得正確的執行。。。一樣,用gcc來直接編譯上述程序,雖然沒有報錯,但結果仍然爲6.00000,可能gcc也是在執行mymul()時沒有正確執行(不過我沒拿gdb來跟蹤看)
如下內容是補充,主要是一些基礎的知識
3.二維數組空間的動態申請 a.簡單的,已經有一維,如 char (*c)[5]; c=new char[n][5];//n爲已定義的行數 b.二維的 int **p; p=new int*[m_row];//建立行指針 for(int i=0;i<m_row;i++)//爲每一行分配空間 p[i]=new int[m_cols]; 寫到某一個函數中: void getmemory(int ** &p,int m_row,int m_cols) { p=new int*[m_row];//建立行指針 for(int i=0;i<m_row;i++)//爲每一行分配空間 p[i]=new int[m_cols]; } 釋放空間: void deletememory(int **&p,int m_row) { //釋放每一行所分配的空間 for(int i=0;i<m_row;i++) delete [] x[i]; //釋放行指針 delete [] x; x=0; } |
1、基本題
一、頭文件中的 ifndef/define/endif 幹什麼用?
答:防止多重編譯,重複引用該頭文件。#ifndef和#endif是配套使用的條件編譯指令,若#ifndef後的宏沒有定義則編譯#idndef---#endif之間的代碼,不然不編譯。
二、#include<> 和 #include 「」 有什麼區別?
答:<>這種方式用於標準或系統提供的頭文件,到保存系統標準頭文件的目錄下尋找。
而「」則一般是展開本身定義的頭文件,編譯器先查找當前目錄,在查找標準目錄。
三、在C++ 程序中調用被 C編譯器編譯後的函數,爲何要加 extern 「C」聲明?
答:C和C++的編譯器對函數名的修飾不一樣,爲了保證在C\C++中編寫的函數可以相互調用,須要加這個連接提示符。
在C++調用時,加上這個告訴C++編譯器不要對函數名再進行修飾。
(這個後面單獨補充,應該在C和C++的混合編程中會常用)。
2、有關內存的思考題
一、
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
請問運行Test函數會有什麼樣的結果?
答:出現段錯誤。涉及到函數的參數傳遞,要想改變str指向的內容,須要把指向str指針的指針傳遞給函數。
(修改的方法跟上次總結的同樣)。
二、
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
請問運行Test函數會有什麼樣的結果?
答:打印出亂碼。由於hello world是字符串常量。保存在靜態存儲區,而定義的字符數組則是局部變量,保存在棧中,進行賦值操做,至關於hello world在棧中也保存了一份,而在函數返回時,棧空間該內存就被釋放了,因此str指向該內存打印出的是亂碼。解決方法是在局部變量前加static關 鍵字,使其維持到程序結束再進行釋放。
三、
Void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
請問運行Test函數會有什麼樣的結果?
答:可以正確輸出結果。可是應該函數體內增長對malloc函數返回指針的判斷。
四、
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, 「hello」);
free(str);
if(str != NULL)
{
strcpy(str, 「world」);
printf(str);
}
}
請問運行Test函數會有什麼樣的結果?
答:輸出world。Free函數的使用將str指針指向的內存塊釋放了,在沒有對str指針進行附空的狀況下,str成了野指針,野指針的指向是不明確的,應該避免使用。
五、本身寫一個函數,實現strcpy的功能
(strcpy函數實現字符串的拷貝,使用指針操做最爲簡便)
Char* mystrcpy(char *dest,const char *src)//最好在這邊加const限定符,意義很明顯
{
//注意進行入口參數檢查
If(dest == NULL || src ==NULL)
{
Printf(「Invalid arguments\n」);
Return NULL;
}
Char *temp = dest;//定義一箇中間指針變量
While(*src!=’\0’)
{
*temp = *src;
Temp++;
Src++;
}
*temp=’\0’;
Return dest;
}
六、分別給出BOOL,int,float,指針變量 與「零值」比較的 if 語句(假設變量名爲var)
答:bool類型,任何非零值都是真,記作TRUE,零值記作假,FLAUSE。與零值比較一般使用if(var)和if(!var)。
Int型與零值比較很簡單,if(var==0)和if(var!=0).
Flaot型變量。應該注意精度限制。它和double變量同樣,不能使用「==」或者「!=」,正確的使用是const float EPSINON=0.00001;if(var>=-EPSINON)&&(var<=EPSION)
指針變量,if(p==NULL)和if(p!=NULL).
七、編寫一個函數,做用是把一個char組成的字符串循環右移n個。好比原來是「abcdefghi」若是n=2,移位後應該是「hiabcdefg」
答:
Char *fun(char *src,int steps)
{
If(src==NULL)
{
Return NULL;
}
Int n = strlen(src)-steps;
Char tmp[20];
Strcpy(tmp,src+n);
Strcpy(tmp+steps,src);
*(tmp+strlen(src)=’\0’);
Strcpy(src,tmp);
}
八、下面的聲明都是什麼意思?
const int a; 聲明一個整形常量
int const a; 聲明一個整形常量
const int *a; 同int const *a,表示聲明指針指向的變量是常量,不能經過*a來修改其值
int * const a; 代表,a是常量,代表指針指向固定不變
int const * a const;代表,指針a是常指針,指向一個常量
3、有關類的
一、爲何須要拷貝構造函數?
答:對於類對象,相同類型的類對象是經過拷貝構造函數完成複製的。
二、類成員函數的重載、覆蓋和隱藏的區別?
答:重載:相同的範圍在同一個類中,函數名相同,參數不一樣,virtual關鍵字可省略
覆蓋:不一樣的範圍(分佈基於派生類和基類),函數名相同,參數相同,基類中必定要有virtual關鍵字。
隱藏:是指派生類的函數屏蔽了和他同名的基類函數。隱藏的規則:(1)派生類的函數與基類的函數同名,可是參數不一樣。基類的函數將被隱藏,此時無論有無關鍵字(注意別與重載混淆)。
(2)派生類的函數與基類的函數同名,而且參數也相同,可是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)
4、網絡
一、TCP和UDP的區別
答:略,這個後面再補充。
二、簡述TCP的三段握手
5、LINUX下線程、進程、同步對象
一、建立進程的函數是?建立線程的函數是?
答:略
二、進程間通信機制有哪些?
答:linux下使用的進程間通訊的方式主要有:管道和有名管道,信號,消息隊列,共享內存,信號量,套接字。
三、線程同步對象有哪些?
答:略
6、其餘
一、LINUX下查看進程的命令?查看系統資源使用狀況的命令?netstat是做什麼用的?
答:linux下查看進程的命令,ps命令
使用free-m命令
Netstat命令是查看網絡鏈接的詳細狀態的命令
關鍵是中間一條的結果斷定:
fork() && fork() || fork();
func1 && func2 的執行規則是,若是 func1爲0,則不執行 func2。(由於func2的結果不影響最後結果)
相似的,func1 || func2 的執行規則是,若是func1 爲非0,則不執行func2。
結合上兩條能夠推算出 "fork() && fork() || fork()" 能夠建立5個進程。
最開始和最後的兩個fork()都只是簡單乘2,因此結果是 2*5*2 = 20。