10道C++输出易错笔试题收集
10道C++輸出易錯筆試題收集
下面這些題目都是我之前準備筆試面試過程中積累的,大部分都是知名公司的筆試題,C++基礎薄弱的很容易栽進去。我從中選了10道簡單的題,C++初學者可以進來挑戰下,C++大牛也可以作為娛樂玩下(比如下面的第6題)。為了便于大家思考,將題目與答案分開,不過無論題目本身如何,我覺得后面的解析過程更值得學習,因為涉及很多我們學習C++過程中必知必會的小知識點 。
?第一部分:題目
如下函數,在32 bit系統foo(2^31-3)的值是:()
int foo(int x){return x&-x;}A:0 B: 1 C: 2 D: 4
運算符優先級?
unsigned char i=0x80;?
printf("0x%x\n", ~i>>3+1);?
輸出什么?
靜態對象是否調用構造函數?
#include <iostream>using namespace std;class A{public:A() { cout << "A's Constructor Called " << endl; }};class B{static A a;public:B() { cout << "B's Constructor Called " << endl; }};int main(){B b;return 0;}?
union問題
#include <stdio.h>union{int i;char x[2];}a;int main(){a.x[0] = 10;a.x[1] = 1;printf("%d",a.i);return 0;}?
下面代碼會報錯嗎?為什么?
class A { public:int m;void print() { cout << "A\n"; } }; A *pa = 0; pa->print();?
下面代碼的輸出是什么?(非常考基礎水平的一道題)
char *c[] = {"ENTER","NEW","POINT","FIRST"}; char **cp[] = { c + 3 , c + 2 , c + 1 , c}; char ***cpp = cp; int main(void) { printf("%s",**++cpp); printf("%s",*--*++cpp+3); printf("%s",*cpp[-2]+3); printf("%s\n",cpp[-1][-1]+1); return 0; }?
結構體
#include <stdio.h> struct data { int a; unsigned short b; }; int main(void) { data mData; mData.b = 0x0102; char *pData = (char *)&mData; printf("%d %d", sizeof(pData), (int)(*(pData + 4))); return 0; }?
改變string變量的值?
#include <iostream> #include <string> using namespace std; void chg_str(string str) {str = "ichgit"; } int main() {string s = "sarrr";chg_str(s);printf("%s\n", s.c_str());cout << s << endl;return 0; }?
靜態變量的輸出
#include <stdio.h> int sum(int a) {int c = 0;static int b = 3; // 只執行一次c++;b += 2;return (a + b + c); } int main() {int i;int a = 2;for(i = 0; i < 5; ++i) {printf("%d\n", sum(a));}return 0; }?
返回值加const修飾的必要性?
你覺得下面兩種寫法有區別嗎?
如果是下面的呢?其中A 為用戶自定義的數據類型。
?
? ? ?
第二部分:答案詳細解析
如下函數,在32 bit系統foo(2^31-3)的值是:
A:0 B: 1 C: 2 D: 4?
答案:C?
解釋:我只想說注意運算符優先級,注意^是異或而不是冪次方。
運算符優先級?
unsigned char i=0x80;?
printf("0x%x\n", ~i>>3+1);
輸出什么??
輸出:0xfffffff7(提示:+的優先級優于>>)?
如果將unsigned去掉,則輸出0x7。
靜態對象是否調用構造函數?
輸出:
B's Constructor Called
解釋:上面的程序只是調用了B的構造函數,沒有調用A的構造函數。因為靜態成員變量只是在類中聲明,沒有定義。靜態成員變量必須在類外使用作用域標識符顯式定義。?
如果我們沒有顯式定義靜態成員變量a,就試圖訪問它,編譯會出錯,比如下面的程序編譯出錯:
?
輸出:
Compiler Error: undefined reference to `B::a
如果我們加上a的定義,那么上面的程序可以正常運行,?
注意:如果A是個空類,沒有數據成員x,則就算B中的a未定義也還是能運行成功的,即可以訪問A。
輸出:
A's constructor called?
B's constructor called?
B's constructor called?
B's constructor called
上面的程序調用B的構造函數3次,但是只調用A的構造函數一次,因為靜態成員變量被所有對象共享,這也是它被稱為類變量的原因。同時,靜態成員變量也可以通過類名直接訪問,比如下面的程序沒有通過任何類對象訪問,只是通過類訪問a。
int main(){// static member 'a' is accessed without any object of BA a = B::getA();return 0;}輸出:
A's constructor called
union問題
#include <stdio.h>union{int i;char x[2];}a;int main(){a.x[0] = 10;a.x[1] = 1;printf("%d",a.i);return 0;}輸出:266,自己畫個內存結構圖就知道了,注意union的存放順序是所有成員都從低地址開始存放。Union的大小為其內部所有變量的最大值,并且按照類型最大值的整數倍進行內存對齊。
?
下面代碼會報錯嗎?為什么?
class A { public:int m;void print() { cout << "A\n"; } }; A *pa = 0; pa->print();答案:正常輸出。上面的代碼可以這樣理解(這非常重要):
?
也就是:并不是類沒有初始化就不能調用類的成員函數,如果成員函數只是簡單的打印個東西,沒有調用類成員啥的就不會報段錯誤。
下面代碼的輸出是什么?(非常考基礎水平的一道題)
?
解答:?
c是一個指針數組,每個數組元素都是char*類型的指針,值分別是那些字符串(的首地址):
c[0] = "ENTER"?
c[1] = "NEW"?
c[2] = "POINT"?
c[3] = "FIRST"
而[]和*是本質一樣的運算,即c[i]=*(c+i)。
c和c+i都是char *[]類型,它可以退化成char **類型,再看cp,它正好是一個char **的數組,來看它的值:
cp[0] = c + 3?
cp[1] = c + 2?
cp[2] = c + 1?
cp[3] = c
引用后就有:cp[0][0]=*(c + 3)=c[3]="FIRST",以此類推。
cp是char **[]類型,它可以退化成char ***類型,看最后的cpp,它正是char ***類型,它是一個指針變量,和上面兩個不同,上面兩個是數組。
這樣分析過后,下面的解析就一目了然了:
- printf("%s",**++cpp);?
++cpp的值是cp+1,引用一次后是cp[1]再引用是*cp[1]=c[2]="POINT",第一句的輸出 - printf("%s",*--*++cpp+3);?
再++cpp的值是cp+2,引用一次是cp[2]=c+1,再對這進行--,減后是c再引用是c[0]="ENTER"再+3,字符串指針指到"ER",輸出是"ER" - printf("%s",*cpp[-2]+3);?
這時cpp的值是cp+2,cpp[-2]=*(cpp-2)=*(cp+2-2)=cp[0]=c+3,再引用是c[3]="FIRST",+3 字符串指針指到"ST",輸出是"ST" - printf("%s\n",cpp[-1][-1]+1);?
cpp還是cp+2,cpp[-1]=*(cpp-1)=*(cp+2-1)=cp[1]=c+2,再[-1]得*(c+2-1)=c[1]="NEW",+1字符串指針指到"EW",輸出是"EW"。
結構體
輸出:4 2?
說明:一般變量都是從高到低分配內存地址,但對于結構體來說,結構體的成員在內存中順序存放,所占內存地址依次增高,第一個成員處于低地址處,最后一個成員處于最高地址處,但結構體成員的內存分配不一定是連續的,編譯器會對其成員變量依據前面介紹的 “對齊”原則進行處理。?
補充知識點:
除了棧以外,堆、只讀數據區、全局變量地址增長方向都是從低到高的。
改變string變量的值?
?
輸出:仍為“sarrr”。?
解釋:string是傳值參數,不能修改其值。要想改變string變量的值,可以改為傳地址方式:
?
靜態變量的輸出
?
輸出:8 10 12 14 16?
解釋:存儲在靜態數據區的變量會在程序剛開始運行時就完成初始化,也是唯一的一次初始化,此后該初始化不再執行,相當于一次執行后就作廢,靜態局部變量保存了前次被調用后留下的值。
返回值加const修飾的必要性?
你覺得下面兩種寫法有區別嗎?
如果是下面的呢?其中A 為用戶自定義的數據類型。
?
答案:沒有任何區別。?
解釋:如果函數返回值采用“值傳遞方式”,由于函數會把返回值復制到外部臨時的存儲單元中,加const 修飾沒有任何價值。所以,對于值傳遞來說,加const沒有太多意義。?
所以:
- 不要把函數int GetInt(void) 寫成const int GetInt(void)。
- 不要把函數A GetA(void) 寫成const A GetA(void)。
在編程中要盡可能多的使用const(比如函數參數采用const&修飾),這樣可以獲得編譯器的幫助,以便寫出健壯性的代碼。
出處:http://www.cnblogs.com/lanxuezaipiao/p/4148155.html
總結
以上是生活随笔為你收集整理的10道C++输出易错笔试题收集的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编程面试的10大算法概念汇总
- 下一篇: s3c2440移植MQTT