本篇文章送上5道c/c++面試題目,並附上答案、解題思路以及擴展知識。ios
#include <stdio.h> int func(int x) { int iCnt = 0; while(x) { iCnt++; x = x&(x-1); } return iCnt; } int main() { printf("cnt = %d\n", func(9999)); return 0; }
這題問的是函數的返回值,而經過代碼咱們能看到返回值的多少取決於x何時變爲0,而x的值又取決於x&(x-1)
這個表達式,在c++中有一個規則,凡是看到&或者|這樣的符號,那就把它左右兩邊的值轉換爲二進制去計算,假設x是7,轉換爲二進制是00000111,x-1那就是00000110,那x&(x-1)
就變成00000110了,再減一個1,變成00000101,那x&(x-1)
就是00000100,因此實際上這個表達式每執行一次,二進制就少一個1,這樣的話,這篇題目就轉換成了,輸入的數字轉換爲二進制有多少個1,那麼返回值就是多少。c++
9999轉換爲二進制是10011100001111,因此本道題目答案:cnt = 8
。面試
給一段代碼,以下:函數
#include <stdio.h> void testputs() { unsigned int a = 6;//無符號整型 int b = (-20);//有符號整型 (a+b) > 6 ? puts(">6"):puts("<6"); } int main() { testputs(); return 0; }
初一看,6+(-20)應該是-14,那就應該輸出<6
,可是這麼簡單的話,就不會有這麼一道題了,咱們編譯後實際上輸出了>6
的結果,這是爲何呢,由於在c語言中,無符號和有符號進行運算或者比較的時候,都會直接把有符號的轉換爲無符號,而後再進行運算或者比較。spa
如今讓咱們增長一行代碼,看看輸出結果,以下:code
#include <stdio.h> void testputs() { unsigned int a = 6; int b = (-20); (a+b) > 6 ? puts(">6"):puts("<6"); printf("%u\n", b);//%u輸出無符號整型 } int main() { testputs(); return 0; }
編譯後輸出以下結果:對象
>6 4294967276
也就是說-20
轉換爲無符號整型之後變成了4294967276,這個數字是怎麼來的呢,首先這裏涉及到int和unsigned int的取值範圍,以下:進程
那有符號轉換爲無符號是什麼樣的一個規則呢,有符號的0轉換爲無符號也是0,而後有符號的-1轉換爲無符號其實就是unsigned int的最大值2^32-1,也就是4294967295,那-20的話,再減19那就是4294967276,這樣就獲得了咱們先前輸出的結果。內存
固然上面這是字面上的轉換規則,還有一種辦法,咱們能夠根據內存的存儲二進制去進行計算,本質上這個轉換隻是轉換了類型,但並不會去動內存中存儲的內容,那負數是怎麼存儲的呢,分三步:字符串
那麼20的二進制是00000000000000000000000000010100,而後按位取反11111111111111111111111111101011,加1之後變成11111111111111111111111111101100,轉換爲無符號就是:4294967276。
看下面這段代碼:
#include <unistd.h> #include <sys/types.h> int main() { fork(); fork()&&fork()||fork(); fork(); //while(1); return 0; }
這題的關鍵有兩點:
&&
和||
的用法,對於&&
,若是它左邊的表達式值爲真,則執行右邊的表達式,不然再也不執行後面的表達式,而對於||
,若是它左邊的表達式爲真,則右邊的表達式再也不執行,不然繼續執行右邊的表達式。下面咱們用一張圖來描述一下進程產生的過程:
下面咱們用文字對圖進行解說,以下:
&&
,只有左邊值不爲0,纔會繼續調用,因此只有1號進程和2號進程調用了第三個fork進程,分別產生了5號進程和6號進程,此時對於fork函數返回值,1號進程返回5號進程id,2號進程返回6號進程id,5號進程和6號進程都返回0;||
,它左邊爲假,纔會執行右邊的表達式,而||
的左邊是fork()&&fork()
,因此只要第二個fork函數和第三個fork函數的調用有任意一個返回值爲0,它都要執行第四個fork函數,而根據上面的第二點和第三點,三、四、五、6這四個進程都要執行第四個fork函數,繼而產生了七、八、九、10這四個進程;因此答案是:20,咱們能夠把代碼裏面的while循環註釋放開,而後查看進程數量,就是20個進程。
代碼以下:
#include <stdio.h> int main() { char *szName = "shengzhenjiayou"; printf("%s %5.3s %3.5s %3.4s\n", szName, szName, szName, "aa"); return 0; }
先看輸出結果:shengzhenjiayou she sheng aa
這就很疑惑了,不少時候咱們只有在輸出浮點數的時候格式裏面纔會帶小數點,這裏輸出字符串帶小數點是什麼意思呢?
其實這裏%5.3s這樣的格式,小數點前面的表示至少要輸出的總寬度(其實就是對齊寬度),小數點後面的表示從左邊開始字符串輸出的最大寬度,因此%5.3s輸出了' she'這樣的數據,它總共輸出5列,但只取字符串前面3列,不足的部分補空格,之因此空格在左邊,那是由於默認是右對齊的,那若是是%-5.3s這樣的,就會變成左對齊。
得出結論以下:對於%5.3s這樣的格式而言,小數點前面的表示最少要輸出這個寬度,小數點後面的表示只能從字符串中截取這個寬度的數據,不夠也不會進行補充。
首先看一下下面的代碼:
#include <iostream> class A { }; int main() { printf("sizeof(A)=%d\n", sizeof(A)); return 0; }
輸出結果以下:sizeof(A)=1
這題通常不瞭解的人就會很疑惑,咱們通常計算一個類佔用多大空間,其實就是計算它的成員變量所佔用的空間,而類A沒有任何成員變量,那爲何長度會爲1呢。
這是由於c++標準規定,類實例化對象佔用內存的大小不能爲0,爲何這麼規定呢。
咱們來看,不管是標準c++類型仍是咱們自定義的類型(這裏剔除包含純虛函數的類),它都是能夠實例化產生一個變量的,而變量都是要存儲在內存中的,若是變量沒有大小,是沒有存儲的,也沒有辦法得到一個地址,那若是類型A實例化了不少對象,沒有地址的話,咱們就沒有辦法區分各個對象了,因此編譯器纔會給空類一個字節的空間,這樣咱們每個對象都會擁有一個獨一無二的地址。
這裏延伸一下,空類大小是1,那空結構體呢,基於以上一樣的緣由,空結構體實際上也是1。
本篇是c/c++題解第一期,後續會不按期發佈更多的題解,若是文章對你有用,麻煩分享和再看哦!