天天看點

總結---51.語義搜尋

所謂語義搜尋,是指搜尋引擎的工作不再拘泥于使用者所輸入的關鍵字,而是準确捕捉到使用者所輸入語句後面的真正意圖,并以此來進行搜尋,微軟、谷歌和Facebook目前正在做着這樣的事。

語義搜尋技術可以讓計算機了解人們資訊的概念,而非關鍵字。

2.記憶體碎片

記憶體碎片的産生:

        記憶體配置設定有靜态配置設定和動态配置設定兩種

       靜态配置設定在程式編譯連結時配置設定的大小和使用壽命就已經确定,而應用上要求作業系統可以提供給程序運作時申請和釋放任意大小記憶體的功能,這就是記憶體的動态配置設定。

        是以動态配置設定将不可避免會産生記憶體碎片的問題,那麼什麼是記憶體碎片?記憶體碎片即“碎片的記憶體”描述一個系統中所有不可用的空閑記憶體,這些碎片之是以不能被使用,是因為負責動态配置設定記憶體的配置設定算法使得這些空閑的記憶體無法使用,這一問題的發生,原因在于這些空閑記憶體以小且不連續方式出現在不同的位置。是以這個問題的或大或小取決于記憶體管理算法的實作上。

       為什麼會産生這些小且不連續的空閑記憶體碎片呢?

       實際上這些空閑記憶體碎片存在的方式有兩種:a.内部碎片 b.外部碎片 。

       内部碎片的産生:因為所有的記憶體配置設定必須起始于可被 4、8 或 16 整除(視 處理器體系結構而定)的位址或者因為MMU的分頁機制的限制,決定記憶體配置設定算法僅能把預定大小的記憶體塊配置設定給客戶。假設當某個客戶請求一個 43 位元組的記憶體塊時,因為沒有适合大小的記憶體,是以它可能會獲得 44位元組、48位元組等稍大一點的位元組,是以由所需大小四舍五入而産生的多餘空間就叫内部碎片。

      外部碎片的産生: 頻繁的配置設定與回收實體頁面會導緻大量的、連續且小的頁面塊夾雜在已配置設定的頁面中間,就會産生外部碎片。假 設有一塊一共有100個機關的連續空閑記憶體空間,範圍是0~99。如果你從中申請一塊記憶體,如10個機關,那麼申請出來的記憶體塊就為0~9區間。這時候你 繼續申請一塊記憶體,比如說5個機關大,第二塊得到的記憶體塊就應該為10~14區間。如果你把第一塊記憶體塊釋放,然後再申請一塊大于10個機關的記憶體塊,比 如說20個機關。因為剛被釋放的記憶體塊不能滿足新的請求,是以隻能從15開始配置設定出20個機關的記憶體塊。現在整個記憶體空間的狀态是0~9空閑,10~14 被占用,15~24被占用,25~99空閑。其中0~9就是一個記憶體碎片了。如果10~14一直被占用,而以後申請的空間都大于10個機關,那麼0~9就 永遠用不上了,變成外部碎片。

參考:http://blog.csdn.net/tianmo2010/article/details/7297331 

3.字元類型及數組使用的說明

關于數組使用以及其是否初始所表示的意思:

4.記憶體配置設定

  如 : int *c = (int *)malloc(N * N)

5.指針和數組的關系

參考:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html

下标總是和指針的偏移量相同。C語言中将數組的下标改寫成指針偏移量的主要原因在于指針和偏移量是底層硬體所使用的基本類型。如a[i]中的i總被 編譯器解析為偏移量,是以a[i]總是被改寫成*(a+i)的形式,a是指向數組第一個元素的指針,加上偏移量i,表示該指針向後移i個步長,然後取 a+i所在單元的内容。由此就可以解釋為什麼C語言中數組的下标可以為負,而且在我看來,C語言中不檢查數組的下标是否越界同樣跟這個有關,如下面這段程 序:

#include<stdio.h>  

int main(void)  

{  

    int a[3]={1,2,3};  

    int *p=(a+3);  

    printf("%d\n",p[-1]);  

    return 0;  

}  

程式執行結果為3,雖然下标為-1,但是被編譯器解析為偏移量,是以相當于*(p-1)。

  

總結---51.語義搜尋
總結---51.語義搜尋
總結---51.語義搜尋
總結---51.語義搜尋

  上例中把a+1的值(位址)賦給p後,p[-1]=*(p+(-1))=*(a+1-1)=*(a+0)=a[0]。

     可見,通過指針,可以使用負數下标。但有兩點要注意:

  a.如果下标是從負數開始的,那麼下标上界也要做相應的變動

  b.如果數組是動态申請的,則撤銷數組所占記憶體時要free(a)而不是free(p),因為a才真正指向數組空間的首位址。

6.一個類有基類、内部有一個其他類的成員對象,構造函數的執行順序是怎樣的。(Autodesk)

答:先執行基類的(如果基類當中有虛基類,要先執行虛基類的,其他基類則按照聲明派生類時的順序依次執行),再執行成員對象的,最後執行自己的。

7.#define DOUBLE(x) x+x (Autodesk)

i = 5*DOUBLE(10); i 是多少?正确的聲明是什麼?

答案:i 為60。正确的聲明是#define DOUBLE(x) (x+x)

8.用運算符sizeof 可以計算出數組的容量(位元組數)。sizeof(p),p 為指針得到的是一個指針變量的位元組數,而不是p 所指的記憶體容量。C++/C 語言沒有辦法知道指針所指的記憶體容量,除非在申請記憶體時記住它。注意當數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針。

char a[] = "hello world";

char *p = a;

cout<< sizeof(a) << endl; // 12 位元組

cout<< sizeof(p) << endl; // 4 位元組

計算數組和指針的記憶體容量

void Func(char a[100])

{

cout<< sizeof(a) << endl; // 4 位元組而不是100 位元組

}

9. 用變量a給出下面的定義

a) 一個整型數(An integer)

b) 一個指向整型數的指針(A pointer to an integer)

c) 一個指向指針的的指針,它指向的指針是指向一個整型數(A pointer to a pointer to an integer)

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

10.關鍵字static的作用是什麼?

 這個簡單的問題很少有人能回答完全。在C語言中,關鍵字static有三個明顯的作用:

1). 在函數體,一個被聲明為靜态的變量在這一函數被調用過程中維持其值不變。

2). 在子產品内(但在函數體外),一個被聲明為靜态的變量可以被子產品内所用函數通路,但不能被子產品外其它函數通路。它是一個本地的全局變量。

3). 在子產品内,一個被聲明為靜态的函數隻可被這一子產品内的其它函數調用。那就是,這個函數被限制在聲明它的子產品的本地範圍内使用。

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

11.關鍵字const是什麼含意?

<<effective C++>>上有個好記的方法:const在*号左邊修飾的是指針所指的内容;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的出現。

12.關鍵字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 a,b;

a = *ptr;

b = *ptr;

return a * b;

由于*ptr的值可能被意想不到地該變,是以a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正确的代碼如下:

long square(volatile int *ptr)

int a;

return a * a;

13.下面的代碼輸出是什麼,為什麼?

void foo(void)

     unsigned int a = 6;

     int b = -20;

     (a+b > 6) puts("> 6") : puts("<= 6");

這個問題測試你是否懂得C語言中的整數自動轉換原則,我發現有些開發者懂得極少這些東西。不管如何,這無符号整型問題的答案是輸出是">6"。原因是當表達式中存在有符号類型和無符号類型時所有的操作數都自動轉換為無符号類型。是以-20變成了一個非常大的正整數,是以該表達式計算出的結果大于6。這一點對于應當頻繁用到無符号資料類型的嵌入式系統來說是豐常重要的。如果你答錯了這個問題,你也就到了得不到這份工作的邊緣。

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

int a = 5, b = 7, c;

c = a+++b;

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

c = a++ + b;

是以, 這段代碼持行後a = 6, b = 7, c = 12。

15.下面這段代碼的輸出是多少(在32位機上).

    char *p;

    char *q[20];

    char *m[20][20];

    int (*n)[10];

    struct MyStruct

char dda; 

double dda1; 

int type ;

}; 

MyStruct k;

 printf("%d %d %d %d",sizeof(p),sizeof(q),sizeof(m),sizeof(n),sizeof(k));

答案:4,80,1600,4,24

           n是指向一維數組的指針變量;k中不要忘了考慮對齊問題,這裡dda為4個位元組。

16.(1)

char a[2][2][3]={{{1,6,3},{5,4,15}},{{3,5,33},{23,12,7}} };

for(int i=0;i<12;i++)

printf("%d ",_______);

在空格處填上合适的語句,順序列印出a中的數字

答案:a[i/6][(i/3)%2][i%3]; 這道題目是多元數組的輸出問題,這裡要考慮的是每維數字的取值順序問題:第一維,前六次循環都取0,後六次取1,于是i/6可以滿足要求;第二維,前3次 為0,再3次為1,再3次為0,再3次為1,用量化的思想,i/3把12個數字分為4組每組3個,量化為0、1、2、3,為要得到0、1、0、1我們這裡 就需要對(0、1、2、3)%2=(0、1、0、1),于是(i/3)%2;最後一維我們需要的是(0、1、2;0、1、2;0、1、2;0、1、2;) 我們就i%3。

 (2)

char **p, a[16][8];  

問:p=a是否會導緻程式在以後出現問題?為什麼?

答案:這個不會導緻出現問題,但是要注意p的使用,如a[1][2] 等價的為 *(*(p+1)+2)而不是*(p+11),

17.《c++ primer》P115  

char ca[] = {'C' , '+' , '+'};  //not null-terminated  

cout<<strlen(ca)<<endl;  

在這個例題中,ca是一個沒有null結束符的字元數組,則計算的結果不可預料。

标準庫函數strlen總是假定其參數字元串以null字元結束,當調用标準庫函數時,系統将會從實參ca指向的記憶體空間開始一直搜尋結束符,直到恰好遇到null為止。

strlen傳回這一段記憶體空間中總共有多少個字元,無論如何這個數值不可能是正确的。

18.

int a = 1 , b = 0;  

MAX(a++ , b);    //a被增值2次  

MAX(a++ , b + 10); //a被增值1次  

MAX(a++ , b)的值為2,同時a的值為3;

MAX(a++ , b + 10)的值為10,同時a的值為2

本文轉自夏雪冬日部落格園部落格,原文連結:http://www.cnblogs.com/heyonggang/p/3381994.html,如需轉載請自行聯系原作者

繼續閱讀