Cracking Digital VLSI Verification Interview 第三章

Programming Basics

Basic Programming Concepts

[68] 在任何一種編程語言中,靜態(static)變量和自動(automatic)變量,局部(local)變量和全局(global)變量之間有什麼區別?

區分這些名詞須要兩個概念,做用域(scope)和存儲持續時間(storage duration),前者定義了在何處能夠訪問變量,後者定義了在什麼時候能夠訪問變量。linux

  • 按照變量的做用域能夠區分局部(local)和全局(global)變量。局部變量的做用範圍有限,盡在聲明它們的代碼塊中可見。而全局變量在聲明後在程序的任何位置均可見。
  • 存儲持續時間能夠區分自動(automatic)變量和靜態(static)變量。靜態變量的生命周其一直持續到程序結束,所以能夠始終訪問。自動變量具備有限的生命週期,只能持續到程序離開定義的塊或者做用域爲止。

例如:在如下的systemverilog代碼中,global_int被聲明爲類成員,而且在整個類中具備全局做用域,而當取消引用該類的對象時,其生命期結束。global_static變量被聲明爲靜態變量並具備全局做用域整個類以及整個程序的生命週期,即便取消引用類的對象也存在。sum變量對於函數compute()是局部的,而且僅在函數內部可見,而且僅在compute執行時存在, count變量在函數compute()中是局部變量,僅在函數範圍內可見,但因爲它是靜態的,所以即便在屢次執行函數compute()以後,它也只有單個副本並保留該值.ios

class test_class;
    int global_int; //automatic by default
    static global_static; //global static variable
    
    void function compute()
        begin
            static int count; //local static variable
            local int sum; //local automatic variable
            sum = sum +1;
            count = count +sum;
        end
    endfunction
    
endclass

[69] 什麼是內聯(inline)函數?

內聯函數時調用時會進行展開內聯的函數,即編譯器會將函數調用替換爲相應函數代碼。若是函數很是小而且在多個地方使用,使用內聯函數會更有優點。這麼作會提升運行速度,沒有調用函數和從函數返回的開銷。程序員

例如:在C語言中,定義一個名爲max的內聯函數,在main內部的每次調用都會經過替換代碼實現,而不是函數調用實現。正則表達式

inline int max(int a, int b) {
    return a > b ? a : b;
} 

main () {
    int a1,a2,a3,b1,b2,b3;
    int c1,c2,c3;
    c1 = max(a1,b1);
    c2 = max(a2,b2);
    c3 = max(a3,b3);
}

[70] 什麼是正則表達式?

正則表達式是特殊的字符序列,可使用特殊的語法幫助用戶匹配或查找其餘字符串(或字符串集)。 它是用於字符串內模式匹配的最強大的概念之一,普遍用於Perl,Python,Tcl等語言。算法

[71] 堆和棧的區別是什麼?

棧是內存的一塊特殊區域,用於存儲由函數建立的臨時變量。每次函數聲明一個新的自動變量時,它將被壓入棧,而且每次函數退出時,會刪除壓入棧的全部變量。全部局部變量都使用棧進行存儲,而且時自動管理的,也有大小限制。若是棧的空間不足,則會出現棧溢出錯誤。shell

堆則是須要管理的內存區域,程序員須要分配和釋放內存,某些語言中是自動完成的。堆一般用於存儲靜態變量和對象。與棧相比,堆略慢,而且是經過指針應用的,而且能夠在任何位置應用堆的變量。堆的大小也是能夠更改的,當可用內存是不連續的塊時,堆可能會出現碎片問題。編程

[72] a++和++a的區別是?

++a首先「a」自增,而後返回引用「a」的值。 所以,若是將「++ a」分配給變量,則將使用遞增值「a」。數組

a++首先返回值「a」(當前值爲「a」),而後「a」自增。所以,若是將「a ++」分配給變量,則將在分配中使用舊值「a」。緩存

[73] 什麼是內存泄漏?

當咱們動態分配內存但以某種方式失去到達該內存的方式時,這稱爲內存泄漏。 在某些編程語言(如C ++)中,應釋放(經過調用析構函數)完成的每一個內存分配(例如,建立對象),不然,這些內存將泄漏且再也不可用。 在某些其餘語言(例如SystemVerilog,Java等)中,語言內部機制負責清理內存,而且內存泄漏的可能性較小。

[74] 編譯器和解釋器的區別是什麼?

機器(例如計算機)理解代碼是經過二進制的,機器能夠理解的二進制代碼稱之爲「機器碼」。程序員一般使用高級編程語言(C,C++,Perl,Python)變寫計算機程序或者代碼。編譯器和解釋器就是將這些源代碼轉換爲機器代碼的程序。

編譯器 解釋器
掃描整個程序並將整個源代碼轉換爲機器代碼 一次掃描並轉化一行源代碼
須要大量的時間去分析源代碼 只須要少許時間用於分析源代碼
輸出機器專用的二進制碼 輸出代碼是某種中間代碼,由另外一個程序解釋
執行速度更快(計算機硬件運行) 執行更慢(由另外一個程序執行)
掃描整個程序後報告錯誤 一直運行,直到遇到第一個錯誤,而且中止程序

[75] 靜態語言和動態語言的區別是什麼?

靜態語言:靜態語言是一種在編譯時固定類型的語言。 這意味着您須要在使用它們以前聲明全部變量及其數據類型。 例如:Java,C和SystemVerilog是靜態類型的語言。

動態語言:動態語言是一種在執行時肯定類型的語言。這與靜態類型的語言相反。 例如:VBScript和Python是動態類型的,所以在使用以前不須要聲明全部變量及其數據類型。 他們會在首次爲變量分配值時弄清楚變量的類型。

[76] 下面關於棧的觀點哪一個是錯的?

  1. 棧只能push或者pop
  2. 可使用棧實現FIFO
  3. 棧對於嵌套循環,子程序調用頗有用
  4. 隊長堆算術表達式計算有用

選項2是錯的,棧是LIFO而非FIFO,先入後出。

[77] Perl中「use」和「require」的主要區別是?

  • use在編譯時起做用,require在運行時起做用
  • use隱式調用了將要加載的模塊,require則沒有
  • use引入的名稱不須要後綴名,而require須要
  • use引入模塊的同時,也引入了模塊的子模塊。而require則不能引入,要再從新聲明

[78] 靜態內存分配和動態內存分配有什麼區別?

靜態內存分配 動態內存分配
內存在編譯時分配 內存在運行時分配
內存被分配到棧上或者程序的其餘部分 內存分配到堆上
不須要釋放內存,靜態變量的生命週期就是程序的生命週期 須要及時釋放內存
固定大小,一旦分配之後內存大小就不能改變 可以改變大小
執行更加快 執行更加慢

[79] 什麼是編譯預處理命令?

在代碼中,預處理器指令是以#開頭的行。它們充當預處理程序的指令,預處理程序在代碼編譯開始以前檢查代碼。其結果就是替換了源代碼中的某些代碼。例如:預處理程序指令的常規語法爲:#define標識符值每當預處理程序在源代碼中遇到「標識符」時,它將用「值」替換,並在編譯以前生成新的源代碼。

[80] C++代碼中"using namespace std"的功能是什麼?

namespace是指標識符的各類可見範圍。命名空間用關鍵字namespace 來定義。命名空間是C++的一種機制,用來把單個標識符下的大量有邏輯聯繫的程序實體(例如類、對象和函數)組合到一塊兒。"std"是"standard"一詞的縮寫。 standard namespace (std namespace)是一種特殊類型的名稱空間,其中保留了全部內置的C ++庫(例如字符串,cin,cout,vector等)。 所以,"using namespace std"告訴C ++編譯器使用標準C ++庫。

[81] 如下兩種初始化的方式有什麼區別:「int a;」 and 「const int a;」?

const關鍵字告訴編譯器,該變量或對象一旦進行初始化便不可更改。因此,int a 聲明後,後續能夠對變量a進行更改,而const int a,後續不可更改

[82] C語言中的關鍵詞volatile是什麼意思?

volatile提醒編譯器它後面所定義的變量隨時都有可能改變,所以編譯後的程序每次須要存儲或讀取這個變量的時候,都會直接從變量地址中讀取數據。若是沒有volatile關鍵字,則編譯器可能優化讀取和存儲,可能暫時使用寄存器中的值,若是這個變量由別的程序更新了的話,將出現不一致的現象。volatile關鍵字主要在與內存映射的輸入輸出(硬件)接口時使用。 變量聲明爲volatile以後,編譯器將沒法執行任何優化,例如:刪除內存分配,將變量緩存在寄存器中或更改分配的執行順序。

[83] 解釋指針的概念

指針是一個變量,其值是另外一個變量的地址。星號*表示指針,int * p 告訴編譯器變量「p」是一個指針,其值是存儲整數變量的存儲位置的地址。 一樣,float * f; 告訴編譯器變量「 f」是一個指針,其值是存儲浮點變量的存儲位置的地址。如下列代碼爲例

int a = 10;
int *b;
int c;
b = &a;
c = *b;
printf(「b=%d and c=%d\n」,b,c);

其中a是一個變量,他的值是10,b是一個指針,經過語句 b = &a 將a的地址傳給了指針b。而經過c = *b 將指針b內地址所指向的值,即a的值賦予c。

[84] 解釋C語言中的「值傳遞」、「地址傳遞」和「引用傳遞」的區別

  • 值傳遞:在這種狀況下,函數會用一塊新的內存去存儲變量,將參數的值複製進來,而且函數內部對參數的修改,不會影響到外部。下例中,在調用Exchg1(a,b)時最開始作的兩個隱含動做是:int x=a;int y=b; 及 x=a;y=b; 原來函數在調用時是隱含地把參數a,b的值分別賦值給了x,y。以後在函數體內一直是對形參x,y進行操做。並無對a,b進行任何操做。函數只是把a,b的值經過賦值傳遞將值傳遞給了x,y。函數裏操做的只是x,y的值,並非a,b的值。這就是所謂的值傳遞
void Exchg1(int x, int y)
{
     int tmp;
     tmp = x;
     x = y;
     y = tmp;
     printf("x = %d, y = %d\n", x, y);
}
main()
{
     int a = 4,b = 6;
     Exchg1(a, b);
     printf("a = %d, b = %d\n", a, b);
     return(0);
}
  • 地址傳遞:地址傳遞的參數爲指針,函數內部其實是經過指針實現的,經過指針的方式尋址,這種修改會對外部的值產生影響。下例中:在調用Exchg2(&a,&b)時最開始作的兩個隱含動做是:int px=&a;int py=&b;.及 px=&a;py=&b; 原來函數在調用時是隱含地把參數a,b的地址分別傳遞給了指針px,py。以後在函數體內一直是對指針px,py進行操做。也就是對a,b的地址進行的操做。
void Exchg2(int *px, int *py)
{
      int tmp = *px;
      *px = *py;
      *py = tmp;
      printf("*px = %d, *py = %d.\n",*px, *py);
}
main()
{
      int a = 4,b = 6;
      Exchg2(&a, &b);
      printf("a = %d, b = %d.\n", a,b);
      return(0);
}
  • 引用傳遞:這種狀況下會將參數的地址複製進來,函數內對參數的修改會反映到外部。一般經過這種方式減少對內存的消耗,例如數組的傳遞,使用引用穿的能夠減少內存消耗。下例中:與值傳遞相比,代碼上只有只有一處不一樣,即函數定義處:void Exchg3(int &x, int &y) Exchg3函數的定義處Exchg3(int&x, int &y)。調用時咱們能夠像值傳遞(如: Exchg1(a, b); )同樣調用函數(如: Exchg3(a,b);)。可是x、y前都有一個取地址符號「&」。有了這個,調用Exchg3時函數會將a、b 分別代替了x、y了,咱們稱:x、y分別引用了a、b變量。這樣函數裏操做的其實就是實參a、b自己了,所以函數的值可在函數裏被修改
void Exchg3(int &x, int &y)
{
     int tmp = x;
     x = y;
     y = tmp;
     printf("x= %d,y = %d\n", x, y);
}
main()
{
     int a = 4,b =6;
     Exchg3(a, b);
     printf("a= %d, b = %d\n", a, b);
     return(0);
}

[85] NULL指針的值和大小是多少?

NULL指針能夠定義爲:int * a = NULL; NULL指針的值爲0。指針是一個變量,其值是另外一個變量的地址。 因爲指針的值是地址,因此指針的大小會因機器而異。 若是是32=4*8位計算機,則指針大小爲4個字節,若是計算機大小爲64=8*8位,則指針大小爲8個字節。

[86] 什麼是鏈表?一共有幾種類型的鏈表?

鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是經過鏈表中的指針連接次序實現的。鏈表由一系列結點(鏈表中每個元素稱爲結點)組成,結點能夠在運行時動態生成。每一個結點包括兩個部分:一個是存儲數據元素的數據域,另外一個是存儲下一個結點地址的指針域。

一共有三種不一樣類型的鏈表:

  1. 單向鏈表
  2. 雙向鏈表
  3. 循環鏈表

[87] 如下算法的「最壞狀況」時間複雜度是多少?

  1. 線性搜索
  2. 二進制搜索
  3. 插入排序
  4. 合併排序
  5. 桶排序

算法的時間複雜度表明了算法的運行時間,n表明輸入算法的參數數量。一般使用big O算法進行評估,例如某算法隱形時間爲5n^4 + 6n^2 + 1,取最高階爲n^4,那麼其算法複雜度爲O(n^4)。因此以上算法的算法複雜度爲:

  1. O(N)
  2. O(log(N))
  3. O(N2)
  4. O(N*log(N))
  5. O(N)

[88] 如下算法的空間複雜度是多少?

  1. 線性搜索
  2. 二進制搜索
  3. 插入排序
  4. 合併排序
  5. 桶排序

空間複雜度的概念相似於時間複雜度,可是衡量的值是算法運行時所須要的內存空間。以上算法的空間複雜度爲:

  1. O(1)
  2. O(1)
  3. O(N)
  4. O(N)
  5. O(N)

[89] C/C++中,"&"和"&&"有什麼區別?

&是按位與運算符,而&&是邏輯與運算符。 邏輯運算符使用布爾值-真(1)和假(0),並返回布爾值。 按位運算符對每一個位執行位操做並返回位值。

按位運算符:若是a = 10而b = 6,則a&b將返回2(4'b1010&4'b0110 = 4'b0010)

邏輯運算符:若是a = 10而b = 6,則如下表達式將返回true,由於對兩個布爾值進行操做,則爲true c =(a == 10)&&(b == 6);

[90] 「Struct」 和 「Union」 在 C/C++ 中,內存分配上有什麼不一樣?

Struct分配足夠的空間來存儲結構中的全部字段/成員。 第一個存儲在Struct的開頭,第二個存儲在Struct的開頭,依此類推。

Union僅分配足夠的空間來存儲列出的最大字段,而且全部字段都存儲在同一空間中。 這是由於在Union中,一次只能使用一種類型的封閉變量,而不是能夠引用全部封閉變量的struct。

[91] 下面這個結構體須要多大的內存進行存儲?

struct ID {
int IntID;
char CharID[8];
};

須要12個字節,int須要4個字節,char數組須要8個字節。

[92] 下面這個聯合體須要多大的內存進行存儲?

union ID {
int IntID;
char CharID[8];
};

須要8個字節,數組CharID須要8個字節。

[93] 什麼是內核(kernel)?

內核是一種計算機程序,它用於管理來自軟件的輸入/輸出請求,並將這些請求轉換爲CPU指令或其餘指令。

[94] perl表明什麼意思?

Practical Extraction and Reporting Language。

[95] perl中有多少種不一樣類型的變量?

  • 標量(scalars):標量用$定義,標量是perl中最簡單的變量。 標量能夠是數字,也能夠是字符串或引用。
  • 數組(arrays):數組用@定義,數組是標量的有序列表,數組的索引是從0開始的。
  • 哈希(hashes):哈希用%定義,哈希是鍵/值對的無序集合,能夠將鍵用做下標來訪問。

[96] 什麼是Cron Job?如何使用Cron Job?

Cron Job是操做系統中基於時間的做業調度程序。 它容許在指定的時間,日期,間隔等自動按期運行做業。例如:假設用戶具備Shell或Perl腳本,該腳本計算UNIX / Linux中磁盤的人均磁盤空間使用狀況。 在UNIX / Linux中爲此腳本以指定的頻率(或時間)設置Cron Job將確保該腳本在計劃的時間(或頻率)下自動運行,而用戶無需每次都手動運行它。

[97] 在UNIX / Linux中,「 rsync」命令的用途是什麼?

「 rsync」表明「Remote Sync(遠程同步)」,它是在磁盤,網絡,服務器和機器之間複製或同步文件/目錄的經常使用命令。 rsync僅移動文件中已更改的那些部分,所以能夠將須要複製的數據量減至最少。 「 rsync」在發送和接收數據時使用某些壓縮和解壓縮方法,進步減少帶寬消耗。 「 rsync」命令最多見的用途之一是在兩臺計算機之間執行數據備份和鏡像磁盤等操做。

[98] C/C++中"\0"字符的用途是什麼?

字符串老是以'\0'做爲串的結束符。所以當把一個字符串存入一個數組時,也把結束符 '\0'存入數組,並以此做爲該字符串是否結束的標誌。

[99] 什麼是二叉樹?

二叉樹是鏈表概念的擴展。 一個二叉樹的節點有兩個指針:「一個左指針」和「一個右指針」。 每個節點能夠進一步分支以造成另外的節點,每一個節點也具備兩個指針。

[100] 什麼是正則表達式中的特殊字符、量詞和錨點?

  • 特殊字符是爲正則表達式用於搜索的,具有特殊含義的元字符。 示例:,^,$,(),[],|,&
  • 量詞用於指定匹配前面的正則表達式的「頻率」。 示例:*, +, ?, {}
  • 錨點指正則匹配時的匹配的位置。錨點容許用戶指定文本搜索的位置。示例:^, $, <, >

Object Oriented Programming Concepts

[101] 類和對象有什麼區別?

類是能夠組合在一塊兒的一組屬性和相關行爲。 對象是類的實例,表示具備屬性和行爲的真實實體。 可使用類數據成員來表示屬性,而可使用方法來表示行爲。 例如:能夠將動物表示爲一類,而不一樣的動物(如狗,貓等)能夠是該動物的對象。

[102] C++的類和結構體有什麼區別?

最初,在C中定義了一個「結構體」,以將不一樣的數據類型組合在一塊兒以執行某些已定義的功能。 可是,在C++中,這種結構體也擴展爲包括函數的結構。 「類」也是一種數據類型,能夠將不一樣的數據類型和其對應的方法進行分類。 C++中二者的區別之一是,類的全部成員默認狀況下都是私有的,而結構的全部成員默認狀況下都是公共的。

[103] Systemverilog中的類和結構體有什麼區別?

在SystemVerilog中,基於要執行的某些功能,類和結構都用於定義一堆數據類型。 可是,結構是總體式的類型,在聲明結構時會分配必要的內存。 類是動態類型,一旦聲明瞭一個類,就只能將一個類句柄引用爲null。 內存分配僅在建立該類的實際對象時發生。

[104] 什麼是public, private 和 protected 成員?

這三者是類成員的不一樣訪問屬性

  • 類的private成員只能從該類內部訪問。 這些數據成員在派生類中將不可見。
  • public成員能夠從該類內部也能夠在類外部訪問。
  • protected數據成員與private成員相似,由於它們只能在該類中訪問。 可是,與private成員不一樣,這些成員在派生類中也可見。

[105] 什麼是多態

多態性是指具備多種形式的能力。 在OOP上下文中,這是指實體在運行時引用各類類的對象的能力。 這能夠經過SystemVerilog中的繼承和虛函數的概念(以及C++中存在的函數和運算符重載的概念)來實現。根據對象的類型,將從相應的類中調用適當的方法。

[106] 什麼是Method Overriding和Method Overloading? 二者有什麼區別?

  • Method Overriding:重寫是子類對父類的容許訪問的方法的實現過程進行從新編寫, 返回值和形參都不能改變。即外殼不變,核心重寫。
  • Method Overloading:重載是在一個類裏面,方法名字相同,而參數不一樣。返回類型能夠相同也能夠不一樣。

[107] 什麼是運算符重載?

在面向對象的編程中,運算符重載是多態的一種特殊狀況,能夠從新定義或重載可用的不一樣內置運算符。 所以,程序員也能夠將運算符與用戶定義的類型一塊兒使用。 C++支持此功能,而SystemVerilog不支持此功能。 如下示例顯示了一個Testclass,其中運算符+被重載,從而能夠把兩個類型爲「Testclass」的類對象相加。 而後,實現未來自兩個對象的數據成員相加,並將其分配給結果類的數據成員。

#include <iostream>
class Testclass{
    public:
    int a;
    int b;
    Testclass operator+(const Testclass& obj);
} 

Testclass Testclass::operator+(const Testclass& obj2){
    Testclass tmp_obj = *this;
    tmp_obj.a = tmp_obj.a + obj2.a;
    tmp_obj.b = tmp_obj.b + obj2.b;
    return tmp_obj;
} 

int main(void){
    Testclass obj1, obj2, obj3;
    obj1.a = 1;
    obj1.b = 1;
    obj2.a = 2;
    obj2.b = 2;
    obj3.a = 0;
    obj3.b = 0;
    obj3 = obj1 + obj2;
    std::cout<<obj3.a<<" "<<obj3.b<<"\n";
    return 0;
}

[108] 什麼是構造函數?

構造函數是類的特殊成員函數,每當建立該類的實例時,構造函數就會自動調用。 在C++中,它與類具備相同的名稱。 在SystemVerilog中,它做爲new()函數實現。

[109] 什麼是析構函數?

與構造函數相反,當對象結束其生命週期,如對象所在的函數已調用完畢時,系統會自動執行析構函數。 在C++中,它與類具備相同的名稱,並帶有波浪號字符前綴,而在SystemVerilog中,因爲該語言支持自動垃圾收集,所以沒有析構函數。

[110] OOP中的組合(composition)和繼承(inheritance)之間有什麼區別?

組合使兩個類之間具備「has - a」關係。 當一個類實例化另外一個類的對象時,該關係爲「 has-a」,而且此屬性稱爲composition。

繼承使兩個類之間具備「is - a」關係。 當一個類從另外一個類派生時,該關係爲「 is-a」,而且此屬性稱爲繼承。

下圖說明了這一點。 基類汽車中派生出福特類,則該關係爲「is-a」,這意味着福特類爲汽車類。 若是福特類內部具備引擎類的對象,則關係爲「has - a」,如圖所示。

image-20191230192310409

[111] OOP的淺拷貝和深拷貝有什麼區別?

在淺拷貝中,將建立一個新對象,該對象具備與原始對象中的值徹底相同的副本。 若是對象的任何字段是對其餘對象的引用,則僅複製引用地址(句柄)。在深拷貝中,將建立一個新對象,該對象具備與原始對象相同的值的精確副本。 若是任何對象都引用了其餘對象,則還將複製屬於該對象的全部值的副本,而不只僅是內存地址或句柄。所以,稱爲深拷貝。

例如,對好比下兩個類。

class A;
    int a;
    int b;
endclass
    
class B;
    int c;
    A objA;
endclass

若是在類B中實現了淺拷貝方法,則當咱們將B複製到新對象時,僅複製「 objA」的內存句柄。 在深度複製的狀況下,還將複製A的全部值(即其數據成員a和b),而不是「objA」的內存句柄。

[112] 什麼是OOP的虛方法?

虛方法是在基類中聲明的成員方法,而且能夠由派生類從新定義。 要建立虛方法,在基類中的方法聲明以前要加上關鍵字virtual。 在派生類中從新定義基類方法的這種方式也稱爲方法重寫。使得調用方法時,是根據對象類型而不是句柄類型調用函數。

[113] 什麼是多重繼承?

多重繼承是某些面向對象的計算機編程語言的功能,其中對象或類能夠從多個父對象或父類繼承特徵和功能。 它不一樣於單一繼承,在單一繼承中,一個對象或類只能從一個特定的對象或類繼承。注意:C++支持多重繼承,而SystemVerilog語言則不支持。

[114] 什麼是抽象類?

抽象類是包含一個或多個抽象方法的類。 抽象方法是已聲明但不包含任何實現的方法。 抽象類可能沒法實例化,而且須要子類爲抽象方法提供實現。 在SystemVerilog中,類名前面帶有虛擬關鍵字,以使其成爲抽象類。 如下是如何使用函數定義爲virtual定義抽象類的示例。 而後派生的類能夠實現此功能。至關於一個模板類。

[115] 什麼是類的靜態方法?

靜態方法是使用static關鍵字在類內部定義的方法。 能夠在不建立類對象的狀況下使用它們。 一樣,若是有多個此類建立的對象,則仍然只有一個靜態方法成爲全部對象的一部分。

[116] 類的this指針是什麼意思?

該指針是一個特殊的指針,可用於在類範圍內引用該類的當前對象。

[117] type conversion 和 type casting的區別是?

type conversion 和 type casting的最大區別就是,type conversion有編譯器自動(隱式)轉換的,而type casting是顯式完成的。

比較內容 type casting type conversion
意義 一個數據類型由用戶分配給另外一個數據類型,使用強制轉換運算符,稱爲"type casting"。 編譯器自動將一種數據類型轉換爲另外一種數據類型稱爲"type conversion"。
應用 類型強制轉換也能夠應用於兩個"不兼容"的數據類型。 僅當兩個數據類型"兼容"時,才能實現類型轉換。
算子 要將數據類型強制轉換到另外一個數據類型,須要強制轉換運算符"()"。 無需操做符。
實現 它在程序設計過程當中完成。 它在編譯時顯式完成。

下面第一個例子是type casting,第二個是type conversion

int a;
byte b;
...
...
b= (byte) a;
////////////////////////////////////////
int a=3;
float b;
b=a; // value in b=3.000.

UNIX/Linux

[118] 如何找到有關UNIX/Linux命令作什麼的詳細信息?

經過man <command-name> ,例如man grep

[119] 編寫UNIX/Linux命令完成如下任務,假設文件名爲file.txt

  1. 顯示文件的前10行
  2. 顯示文件的第10行
  3. 從文件中刪除第13行
  4. 從文件中刪除最後一行
  5. 反轉字符串(例如:「 Hello」 )
  6. 檢查上一條命令是否成功
  7. 查找文件中的行數
  8. 查找文件中的字符數
  9. 查找文件中第17行的字符數
  10. 獲取第三個單詞文件中第17行的內容
  11. 將全部用戶的文件權限更改成「讀取」和「可執行」。
  12. 將文件的組訪問權限更改成組。(假設新的組名稱爲「 new_group」)
  13. 將兩個文件(file1.txt和file2.txt)的內容移動到一個文件(file.txt)
  14. 顯示本帳號下的全部進程
  15. uniquely排序文件(file1.txt)的內容並將其複製到另外一個文件(file2.txt)
  16. 檢查用戶名
  17. 登陸到遠程主機(例如「遠程服務器」)
任意一種: 
    a) head -10 file.txt 
    b) cat file.txt | head -10 
    c) sed 「11,$ d」 file.txt
head -10 file.txt | tail -1 
sed -i 「13 d」 file.txt 
sed -i 「$ d」 file.txt 
echo 「Hello」 | rev 
echo $? 
cat file.txt | wc -l 
cat file.txt | wc -c 
head -17 file.txt | tail -1 | wc -c 
head -17 file.txt | tail -1 | cut -f3 -d’ ‘ 
chmod 555 file.txt 
chgrp new_group file.txt 
cat file1.txt file2.txt > file.txt 
ps -aef 
sort -u file1.txt > file2.txt 
whoami 
ssh username@remote-server

[120] 編寫UNIX/Linux命令,按照要求顯示文件內容,假設文件名爲file.txt

  1. 全部匹配「cat」的行
  2. 全部單詞「 cat」的行
  3. 全部不包含「cat」的行
  4. 全部包含單詞「 cat」的行(不區分大小寫)
  5. 全部以「cat」開頭的行
  6. 全部以「 cat」結尾的行
  7. 全部包含「cat」和「123」的行(「cat」出如今「123」以前)
grep 「cat」 file.txt 
grep -w 「cat」 file.txt 
grep -v -w 「cat」 file.txt 
grep -i 「cat」 file.txt 
grep 「^cat」 file.txt 
grep 「cat$」 file.txt 
grep 「cat.*123」 file.txt

[121] 編寫UNIX/Linux命令以列出目錄中全部文件的名稱(例如/usr/bin/dir/)(及其子目錄),文件應該包含不區分大小寫的「I am preparing for Interview」。

grep -ilr 「I am preparing for Interview」 /usr/bin/dir/*

[122] 有一個文件(例如/usr/home/file.txt)包含目錄列表。 編寫一組UNIX/Linux命令,以查看該文件的內容,進入每一個目錄並運行一個進程(例如script.pl)。 假設文件(/usr/home/file.txt)的每一行僅包含一個目錄的路徑。

foreach x (`cat /usr/home/file.txt`) 
foreach> cd $x 
foreach> script.pl 
foreach> end

[123] 編寫UNIX/Linux命令,該命令將全部非空白行從文件(file1.txt)移至另外一個文件(file2.txt)

grep -v 「^$」 file1.txt > file2.txt

[124] 編寫一個UNIX/Linux命令(假設filename = file.txt):

  1. 查找當前目錄或其子目錄中是否存在某個文件
  2. 查找某個文件是否在目錄「/usr/bin/DIR」或其子目錄中
  3. 查找某個文件是否僅存在於當前目錄中
  4. 查找當前目錄或其子目錄中是否包含名稱中包含特定單詞「dummy」的文件
  5. 查找當前目錄或其子目錄中是否存在不區分大小寫的文件「file」
  6. 查找全部名稱不是「file.txt」且存在於當前目錄或其子目錄中的文件
  7. 從新運行之前執行的find命令
find . -name 「file.txt」 OR find -name 「file.txt」 
find /usr/bin/DIR -name 「file.txt」 
find -maxdepth 1 -name 「file.txt」 
find . -name 「*dummy*」 
find . -iname 「file」 
find -not -name 「file.txt」 
! find

[125] 編寫一個UNIX/Linux命令:

  1. 列出在計算機上以你的名字設置的全部Cron Jobs
  2. 列出用戶在計算機上設置的全部Cron Jobs
  3. 刪除計算機上以你的名字設置的全部Cron Jobs
  4. 刪除用戶在計算機上的全部Cron Jobs(若是你有權這樣作)
  5. 在計算機上以您的名字編輯Cron Job。
  6. 設置天天下午6:30運行的Cron Jobs
  7. 設置每分鐘運行一次的Cron Jobs。
  8. 設置一個Cron Jobs,該做業在每月的前20天上午6:30運行
  9. 設置僅在每個月的星期五的6:30 AM和6:30 PM運行的Cron Jobs
crontab -l 
crontab -u <user_name> -l 
crontab -r 
crontab -u <user_name> -r 
crontab -e 
30 18 * * * <command_to_invoke_your_process> 
* * * * * <command_to_invoke_your_process>
30 6 1-20 * * <command_to_invoke_your_process> 
30 6 18 * * 6 <command_to_invoke_your_process> (assuming Sunday is represented by 0)

[126] 列出下列shell中的快捷鍵

  1. 殺死進程
  2. 將在終端上運行的進程移至後臺
  3. 將光標移至Shell上命令的開頭
  4. 將光標移至Shell上命令的結尾
  5. Ctrl + c
  6. Ctrl + z
  7. Ctrl + a
  8. Ctrl + e

Programming in C/C++

[127] 編寫C代碼以檢測計算機中的架構是little Endian 仍是 big Endian

什麼是大小端請參考問題[32]

#include <stdio.h> 
int main() {
    unsigned int i = 1;
    char *c = (char*)&i;
    if (*c)
        printf("Little Endian \n");
    else
        printf("Big Endian \n");
    return 0;
}

[128] 通過下列代碼後,b和c的值是多少?

a = 10;
b = a++;
c = ++a;

b等於10,而c等於12。後置自增運算符僅在賦值後才進行自增,所以b獲得的是自增前的值。 前置增量運算符將首先進行自增,所以a將從11(在b = a++後變爲11)增長到12

[129] 下列代碼的輸出是什麼?

#include<stdio.h>
int xyz=10;
int main() {
    int xyz=20;
    printf("%d",xyz);
    return 0;
}

變量xyz定義了全局變量和局部變量,而在函數中,優先調用的是局部變量,因此將爲打印出20.

[130] 下列代碼中,y的值是多少?

int main() {
    int x=4;
    float y = * (float *) &x;
    return 0;
}

一個很小的值。 一些編譯器可能會將答案顯示爲0。「(float *)&x」,告訴編譯器指針指向存儲在內存位置的浮點數。 浮點數的存儲方式不一樣於整數(對於浮點數,位[31]表示帶符號的位,位[30:23]表示指數,位[22:0]表示分數)。 所以,當解釋爲浮點數(00000000000000000000000000000100)時,值將爲很是小。

[131] 下列C程序的輸出是什麼?

#include<stdio.h>
int main() {
    int i=0;
    for(i=0;i<20;i++)  {
        switch(i) {
            case 0:i+=5;
            case 1:i+=2;
            case 5:i+=5;
            default: i+=4;
            break;
        }
        printf("%d\n",i);
    }
    return 0;
}

輸出是16,21。

注意兩點,i在循環內進行了修改,case後沒有跟着break。第一次進入循環,i將一次加5 2 5 4,而後打印輸出16,最後再加1。第二次直接進入default,加4,而後輸出21。

[132] 編寫一個遞歸函數求n的階乘,n爲正整數

int factorial (int x) {
    if ( (x==0) || (x==1) )
        return 1;
    else
        return (x*factorial(x-1));
}

[133] 編寫一個遞歸函數求斐波納契數列

int fibonacci (int num){
    if( (num==0) || (num==1) )
        return num;
    else 
        return (fibonacci(num-1) + fibonacci(num-2));
}

[134] 下列代碼在64位機上的輸出是什麼?

#include <stdio.h>
int main() {
    int x = 10000;
    double y = 56;
    int *p = &x;
    double *q = &y;
    printf("p and q are %d and %d", sizeof(p), sizeof(q));
    return 0;
}

輸出是p and q are 8 and 8 。

因爲「p」和「q」是指針,所以它們只不過是64位計算機中的地址。 不管它們指向整數仍是雙精度數據類型,二者的大小均爲64位(8字節)。

[135] 什麼是鏈表?什麼時候使用鏈表?

鏈表是由一組節點組成的數據結構,這些節點一塊兒表明一個序列。鏈表是由一組節點組成的數據結構,這些節點一塊兒表明一個序列。若是咱們不知道要存儲的數據量,則首選鏈表。 例如:咱們能夠在員工管理系統中使用連接列表,在這裏咱們能夠輕鬆地添加新員工的記錄(添加新節點-動態內存分配),刪除舊員工的記錄(刪除節點),編輯 員工記錄(在節點中編輯數據)。

在[136]-[140]中,使用下列變量和定義:

struct node;
typedef struct node NODE;
typedef int Element;
 
// A pointer to a node structure
typedef NODE *LINK;
 
// A node defined as having an element of data
// and a pointer to another node
struct node {  Element elem;   LINK next; };
 
// The Head or start of the List
typedef struct {  int size;  LINK start; } ListHead;

[136] 編寫一個C程序用於建立單鏈表

要建立單鏈表,咱們須要:

  1. 建立鏈表的HEAD(h)

  2. 初始化鏈表的大小(爲零)

  3. 將起始指針指向NULL(在建立時爲空)。

請參考如下函數來建立單鏈表:

ListHead createList() {
    ListHead h;
    h.size = 0;
    h.start = NULL;
    return h;
}

[137] 編寫一個C程序用於在單鏈表的頭部插入一個元素

在鏈表(h)的頭部插入元素(e)時,咱們須要:

  1. 爲新節點動態分配內存。

  2. 爲新節點中的元素分配值。

  3. 將新節點中的「next」指針指向HEAD先前指向的節點。

  4. 在連接列表HEAD中,增大「size」變量(隨着添加了新節點),而後將「start」指針指向新節點。

ListHead InsertElementAtHead(Element e, ListHead h) {
    LINK nl= (LINK) malloc (sizeof(NODE));
    nl->elem = e;
    nl->next = h.start;
    h.start= nl;
    h.size++;
    return h;
}

[138] 編寫一個C程序用於在單鏈表的尾部插入一個元素

在連接列表(h)的末尾插入元素(e)時,咱們須要:

  1. 爲新節點動態分配內存。

  2. 爲新節點中的元素分配值。

  3. 將新節點中的「next」指針指向NULL(由於新節點表明鏈表的尾部)。

  4. 若是鏈表最初爲空,則將HEAD中的「start」指針指向新節點,不然遍歷連接列表以找出連接列表中的最後一個節點,並將最後一個節點中的「next」指針指向新節點。

  5. 在鏈表HEAD中增大「size」變量(隨着添加了新節點)。

ListHead InsertElementAtTail(Element e, ListHead h) {
    LINK temp;
    LINK nl;
    nl=(LINK) malloc (sizeof(NODE));
    nl->elem=e;  nl->next=NULL;
    if(h.start==NULL)
        h.start=nl;
    else  {
        temp=h.start;
        while(temp->next!=NULL)
            temp=temp->next;
        temp->next=nl;
    }
    h.size++;
    return h;
}

[139] 編寫一個C程序用於在單鏈表的pos處插入一個元素

在鏈表(h)中的pos處插入元素(e)時,咱們須要:

  1. 爲新節點動態分配內存,

  2. 爲新節點中的元素分配值。

  3. 若是「pos」大於鏈表的大小,則返回錯誤消息(由於這是不可能的)。 不然,若是「 pos」爲「 0」,則將元素插入頭部(如上所示)。 不然,將鏈表遍歷到「 pos」以前的節點。 將新節點中的「next」指針指向「pos-1」處的節點所指向的節點,並將節點中「pos-1」處的「next」指針指向新節點。

  4. 在鏈表HEAD中增大「size」變量(隨着添加了新節點)。

ListHead InsertAtPos(Element e, ListHead h, int pos) {
    LINK temp;
    LINK nl;
    nl=(LINK)malloc(sizeof(NODE));
    nl->elem=e;
    int count=0;
    if(pos>h.size) {
        printf("Error: Wrong position \n");
        return h;
    }
    if(pos==0) {
        nl->next=h.start;
        h.start=nl;
    }  else {
        for (temp = h.start; count<(pos-2); temp = temp->next, count++) ;
        nl->next=temp->next;
        temp->next=nl;
    }
    h.size++;
    return h;
}

[140] 編寫一個C程序用於刪除單鏈表的一個元素

從鏈表(h)中刪除元素(e)時,咱們須要:

1.檢查鏈表是否爲空。 若是爲空,則無需刪除任何內容。

2.若是鏈表不爲空,則須要遍歷鏈表以找到包含元素(e)的節點。 找到節點以後,咱們須要在要刪除的節點以前更改節點中的「next」指針,以指向要刪除的節點的「next」指針中存的值。

3.減少鏈表HEAD中的「size」變量(由於刪除了節點)。

ListHead DeleteElement(Element e, ListHead h) {
    LINK cur, prev;
    cur=h.start;
    if(cur==NULL)  {
        printf ("Empty List \n");
        return h;
    }
    while(cur!=NULL)  {
        if(cur->elem==e)    {
            if(cur==h.start)
                h.start=cur->next;
            else
                prev->next=cur->next;
            free(cur);
            h.size--;
            break;
        } 
        prev=cur;
        cur=cur->next;
    }
    return h;
}

Programming in PERL

[141] 下列Perl代碼的輸出是什麼?

my @value_array = ("Index0","Index1");
my $value;
foreach $value (@value_array){
    $value =~ s/Index//;
}
print "@value_array\n";

結果:0 1

在foreach中使用$value索引,將會改變數組的值

[142] 下列Perl代碼的輸出是什麼?

my @value_array = ("Index0","Index1");
my $value;
for(my $i=0; $i<@value_array; $i++) {
    $value = $value_array[$i];
    $value =~ s/Index//;
}
print "@value_array\n"

$value對於for循環來講是局部的,不會影響數組內容

[143] 在Perl中的「-w」和「use strict」的做用是?

-w是用於標記warning,對潛在的歧義代碼進行警告。

use strict是Perl中編譯指令,是提供給Perl編譯器的指令,告訴編譯器,若是perl代碼中有很差的編碼風格,那麼提示編譯失敗。也就是說,加上use strict後,咱們的Perl代碼的編寫必須遵循一些規範,不然編譯器會報錯。

[144] 下列Perl代碼的輸出是什麼?

my $line_in_a_file = "I am preparing for an Interview";
my $line_in_a_file =~ s/a/A/;
print "$line_in_a_file\n";

匹配第一個a,替換爲A。所以輸出爲「I Am preparing for an Interview」

[145] 下列Perl代碼的輸出是什麼?

my $line_in_a_file = "I am preparing for an Interview";
my $line_in_a_file =~ s/a/A/g;
print "$line_in_a_file\n";

g表明global,進行全局匹配,將全部的a都替換爲A。所以輸出爲「I Am prepAring for An Interview」

[146] 在Perl中如何將兩個字符串進行拼接?在空白處填充

my $string1 = "I am preparing ";
my $string2 = "for an Interview";
my $string = __?__

Perl使用「.」進行填充。所以空白處應該填寫$string1.$string2

[147] 下面程序的輸出是什麼?

#!/usr/bin/perl
use warnings;
use strict;
my $scalar =0;
my @array = ("A","B","C","D");
$scalar = @array;
print "Scalar is $scalar\n";

標量會存儲數組的元素數量,所以打印出來的值是4

[148] 正則匹配的特殊字符有哪些?解釋他們的做用

  1. \轉義字符。 使元字符成爲文字
  2. ^匹配字符串/行開頭的字符
  3. $匹配字符串/行結尾的字符
  4. .匹配除換行符之外的全部字符
  5. *匹配0或更屢次
  6. +匹配1或更屢次
  7. -表示字符類中的範圍(如a-z)
  8. &匹配到的字符,經過$&引用
  9. ()分組字符
  10. []字符類以匹配單個字符
  11. {}指定量詞範圍
  12. <>指定單詞錨點
  13. ?匹配0或1次
  14. |從多個模式中選擇一個

[149] 正則表達式中的量詞有哪些?他們的用法是?

  1. *匹配0或更屢次
  2. +匹配1或更屢次
  3. ?匹配0或1次
  4. {N}匹配N次
  5. {N,}匹配至少N次
  6. {N,M}匹配至少N次之多M次

[150] 正則表達式的錨位有哪些?他們的用法是?

  1. ^匹配字符串開頭
  2. $匹配字符串結尾
  3. <單詞開頭
  4. >單詞結尾
  5. \b單詞與非單詞的邊界
  6. \B匹配\b所不能匹配的位置

在[151]-[155]中使用以下代碼,針對問題再下面的空白處填空

#!/usr/bin/perl
use warnings;
use strict;
my $input_file = "input_file.txt";
my $output_file = "output_file.txt";
my @input_array;
 
open(OUTPUT_FILE,'>',$output_file) or die "Cannot Open $output_file file for writing\n$!\n"; open(INPUT_FILE,'<',$input_file) or die "Cannot Open $input_file for reading\n$!\n";
 
while(<INPUT_FILE>){
    if($_ =~ /__?__/){
        print OUTPUT_FILE $_;
    }
}

close INPUT_FILE;
close OUTPUT_FILE;

[151] 將input_file.txt中僅包含小寫字母(a到z)的全部行復制到output_file.txt

^([a-z]+)$

[152] 將input_file.txt中僅包含字母(a到z或者A-Z)的全部行復制到output_file.txt

^([a-zA-Z]+)$

[153] 將input_file.txt中僅包含字母或數字(a到z或者A-Z或者0-9)的全部行復制到output_file.txt

^([a-zA-Z0-9]+)$

[154] 將input_file.txt中的全部行復制到output_file.txt

\$

[155] 將input_file.txt中的僅包含「」或者「$」的全部行復制到output_file.txt

^([\\\$]+)$

[156] Perl中chop和chomp的做用是什麼?

chop:刪除字符串的最後一個字符,並返回該字符

chomp:刪除字符串結尾的換行符,並返回刪除的字符數

[157] 下列Perl代碼的輸出是什麼?

#!/usr/bin/perl
use warnings;
use strict;
my $example_1 = "chop_example";
my $example_2 = "chop_example";
chop($example_1);
my $b = chop($example_2);
print "$example_1 AND $b\n";

chop_exampl AND e

參考[157]

[158] 下列Perl代碼的輸出是什麼?

#!/usr/bin/perl
use warnings;
use strict;
my $example_1 = "chomp_example\n";
my $example_2 = "chomp_example\n";
chomp($example_1);
my $b = chomp($example_2);
print "$example_1 AND $b\n";

chomp_example AND 1

參考[157]

相關文章
相關標籤/搜索