面試 C/C++ 觀念整理

Skyler Chen
6 min readMar 1, 2020

--

這裡有些題目是來自網路上MTK面試的C考古題,另外又加入了一些易搞混的觀念,幫自己統整一下,也希望能幫助在求職的讀者,面試的過程真的心很累啊!如果有寫錯的地方再麻煩告知我。

  • Explain “#error” ?
預處理指令。預處理階段只要遇到 #error 就會生成一個錯誤提示訊息並停止
  • What is “const” ? and what is the meaning of:
  1. const int a;
  2. int const a;
  3. const int *a;
  4. int * const a;
  5. int const * a const;
const 代表只可讀不可改。
1. 一個常數型整數
2. 同 1,一個常數型整數
3. 一個指向常數型整數的指標 (整型數不可修改,但指標可以)
4. 一個指向整數的常數型指標 (指標指向的整數可以修改,但指標不可修改)
5. 一個指向常數型整數的常數型指標 (指標指向的整數不可修改,同時指標也不可修改)
  • Explain “struct” and “union” ?
struct 稱為結構體,可以包含數個不同資料型態的變數,所有變數佔用不同的內存。union 稱為聯合體,也可以包涵不同資料型態的變數,但是所有辨識站又相同內存。
  • Explain “volatile”. Can we use “const” and “volatile” in the same variable? Can we use “volatile” in a pointer?
一個定義為 volatile 的變量是說這變量可能會被意想不到地改變(尤其在嵌入式系統),因此編譯器不會去假設這個變量的值了。精確地說就是,優化器不會將其優化,而是在用到這個變量時必須每次都重新讀取這個變量的值,不是使用保存在暫存器裡的備份。下面是 volatile 變量的幾個例子︰1. 並行設備的硬體暫存器 (如︰狀態暫存器)2. 一個中斷服務子程序中會訪問到的非自動變數(Non-automatic variables)3. 多執行緒中共享的變數是的。一個例子是只讀的狀態寄存器(不應該被程式修改,但有可能被硬體修改,比如interrupt routine)。它是 volatile 因為它可能被意想不到地改變。它是 const 因為程序不應該試圖去修改它。是的。比如當一個中斷服務的子程序修改一個指向buffer的pointer時。
  • What is the difference between “Inline Function” and “Macro” ?
Macro是在預處理時直接單純的文字替換,inline function是在compile階段時,直接取代function。比較下面兩個例子:inline寫法:inline int square(int x) {
return x * x;
}
output: SQUARE(3 + 2) → (3 + 2) * (3 + 2) = 25Macro寫法:#define SQUARE(x) (x * x)output: SQUARE(3 + 2) → 3 + 2 * 3 + 2 = 11
  • Explain “static” ?
1. static 出現在變數前,且該變數宣告於函式中 (C/C++):
局部變數加上 static 修飾後便不會因為離開可視範圍而消失。
2. static 出現在變數前,且該變數不是宣告於函式中(C/C++):
讓變數只限定在該檔案內,而不是整個程式中(解決編譯時連結多個檔案造成相同變數名衝突)。
3. static 出現在類別的成員變數前 (C++ only):
表示該變數不屬於某個類別實例,他屬於這個類別,所有以此類別生成出來的實例都共用這個變數。
4. static 出現在類別的成員函式之前 (C++ only):
表示該函式不屬於某個類別實例,他屬於這個類別,所有以此類別生成出來的實例都共用這個函式(即便我們沒有產生實例出來,我們也隨時可以取用這個函式)(同 python 的 @static method)。
reference
  • What is stack and heap when talking about memory ?
Stack: allocated by compiler, store function parameters and local variables
1. very fast access
2. don't have to explicitly de-allocate variables
3. space is managed efficiently by CPU, memory will not become fragmented
4. local variables only
5. limit on stack size (OS-dependent)
6. variables cannot be resized
Heap: allocated by programmer
1. variables can be accessed globally
2. no limit on memory size
3. (relatively) slower access
4. no guaranteed efficient use of space, memory may become fragmented
5. you must manage memory (you're in charge of allocating and freeing variables) or memory leakage will happen
6. variables can be resized using realloc()
Static: store global variable and static variable (initialized when process starts)
Literal Constant: store comments (text)
  • Explain “thread” and “process”, and what is the difference ?
Process: an executing instance of an program. Process takes more time to terminate and it is isolated means it does not share memory with any other process.Thread: a path of execution within a process. Thread takes less time to terminate as compared to process and like process threads do not isolate. They share memory with other threads.--> The typical difference is that threads (of the same process) run in a shared memory space, while processes run in separate memory spaces.Read more
  • define a variable “a” from the following requests:
  1. An integer
  2. A pointer to an integer
  3. A pointer to a pointer to an integer
  4. An array of 10 integers
  5. An array of 10 pointers to integers
  6. A pointer to an array of 10 integers
  7. A pointer to a function that takes an integer as an argument and returns an integer
  8. An array of ten pointers to functions that take an integer argument and return an integer
ANS.
1. int a
2. int *a
3. int **a
4. int a[10]
5. int *a[10]
6. int (*a)[10]
7. int (*a)(int)
8. int (*a[10])(int)
  • What is the content of array a ?

int a[] = {6, 7, 8, 9, 10};

int *p = a;

*(p++) += 123;

*(++p) += 123;

ANS: {129, 7, 131, 9, 10}
  • 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為一個實際的結構,這也許不是你想要的,所以沒事不要亂用 macro。
  • What is the difference between variable declaration and definition ?
A declaration provides basic attributes of a symbol: its type and name. A definition provides all of the details of that symbol.
  • Is the program below correct ?

unsigned int zero = 0;

unsigned int compzero = 0xFFFF; /*1’s complement of zero */

對于一個整數型不是16位元的處理器為說,上面的程式碼是不正確的。應編寫如下︰ unsigned int compzero = ~0;
  • What is the output of the following program ?

void foo(void) {

unsigned int a = 6;

int b = -20;

(a + b > 6) ? puts(“> 6”) : puts(“<= 6”);

}

當表達式中存在有符號類型和無符號類型(unsigned)時所有的操作數都自動轉換為無符號類型。因此-20變成了一個非常大的正整數,所以該表達式計算出的結果大于6。
  • The faster way to an integer multiply by 7 ?
i = (i << 2) + (i << 1) + (i << 0)
  • Reverse a string.
void reverseStr(string& str) {
int n = str.length();
for (int i = 0; i < n / 2; i++)
swap(str[i], str[n - i - 1]);
}
  • 計算自訂型態的記憶體大小(不可使用sizeof,也不可有自訂型態變數或其指標
  • 以單字為單位反轉字串,例如:He is a boy 變成 boy a is He。
  • 給定一個正整數列進行排列,奇數在前偶數在後,奇數由小到大,偶數由大到小。
  • Write functions isUpper() and toUpper()
bool isUpper(int ch) {
return (ch >= 'A' && ch <= 'Z');
}
int toUpper(int ch) {
if (isUpper(ch))
return ch;
else
return (ch + 'A' - 'a');
}
  • The value of v within the program below?

unsigned long v1 = 0x 00001111;

unsigned long v2 = 0x 00001202;

unsigned long v;

v = v1&(~v2); — — — — (1)

v = v | v2; — — — — (2)

記得先轉成2進位再做 bit operationANS. (1) v = 0x00000111 (2) v = 0x00001313
  • The value of *(a+1), (*p-1) within the program below?

int a[5] ={1,2,3,4,5}

int *p = (int *)(&a+1);

ANS. *(a+1) = 2, (*p — 1) = 一個亂數
  • Write a code that
  1. set the specific bit
  2. clear the specific bit
  3. inverse the specific bit (0->1; 1->0)
1. void setBit(int &a, b) { a |= (0x1<<b); }2. void clearBit3(int &a, b) { a &= ~(0x1<<b); }3. void inverseBit(int &a, b) { a ^= (0x1<<b); }
  • What is the meaning of int(*a)(int) and int(*a[10])(int) ?
A pointer to a function that takes an integer argument and returns an integer.An array of 10 pointers to functions that take an integer argument and return an integer.
  • Re-write the program below:

void(*(*papf)[3])(char *);

typedef__________;

pf(*papf)[3];

papf is a pointer to array of "pointer to function return void"papf is a pointer to array of "pf"pf is a pointer to function return void--> typedef void(*pf)(char *);
  • Write a code that check the input is a multiple of 3 or not without using division or mod.
#include<iostream>
using namespace std;
int main () {
int n;
cin >> n;
while(n >= 3) n-= 3;
if (!n) cout << n << “ is multiple of 3” << endl;
else cout << n << “ is not multiple of 3” << endl;
}

實際上這題有更快的解法是使用 bit operation,在 leetcode上有

  • What is l-value and r-value ?
左值是一個表達式,它代表一個變量或對象的內存位置,並且允許用 & 來取值。如果一個表達式不是左值就是右值。
  • Write a code to swap two integer without temporary variable.
int a = 1, b = 2;
a = a ^ b;
b = a ^ b;
a = a ^ b;
  • Write one line expression to check if a integer is power of 2.
isPow2 = x && !( (x-1) & x );(x-1) & x == 0
  • Count the number of 1 in an integer x (in binary) ?
#include<iostream>
using namespace std;
int main() {
int x, cout = 0;
cin >> x;
while (x > 0) {
c++;
x = x & (x - 1);
}
cout << c << endl;
return 0;
}
  • Write a function to find the middle field of singled-linked list without traverse whole list.
ListElement* getMiddle (ListElement* first) {
if (!first) return NULL;
int n = 1;
ListElement *middle=first,
*current=first;
while (current) {
current = current->next
++n;
if (n % 2) middle= middle->next;
}
return middle;
}
  • Write a code to reverse the linked list.
void reverse_list(ListNode* head) {
//create three pointer precedent, current, and previous
ListNode *curr = head,
*prev = NULL,
*prec = NULL;
while(curr) {
prec = curr->prec;
curr->next = prev;
prev = curr;
curr = prec;
}
head = prev;
}
  • Find the possible error:

int ival;

int **p;

ival = *p;

Ans,  *p is a pointer to int and ival is int
  • What is the possible error of below SQR function:

int SQR(volatile int *a) { return (*a)*(*a); }

由於 *a 的值可能被意想不到地該變,因此第一個 (*a) 和第二個 (*a) 可能是不同的。結果,這段程式碼可能返回不是你所期望的平方值!正確的程式碼如下︰long square(volatile int *a) {
int b;
b = *a;
return b * b;
}
  • 保證 n 一定是下面五個數字之一,不能用 if 和 switch case,請用你認為最快的方法實作 main

extern void func1(void);

extern void func2(void);

extern void func3(void);

extern void func4(void);

extern void func5(void);

void main(int n)

{

if n==1 execute func1;

if n==2 execute func2;

if n==3 execute func3;

if n==4 execute func4;

if n==5 execute func5;

}

typedef void (*fp)(void);fp fpa[5];
fpa[1] = func1; // equivalent to fpa[1] = &func1
fpa[2] = func2;
fpa[3] = func3;
fpa[4] = func4;
fpa[5] = func5;
void main(int n) {
(*fpa[n])();
}

--

--