c c 遇到的坑

2021-09-25 16:17:44 字數 3035 閱讀 2623

如果c語言是0,那麼c++是多少?

先來點個題,與本文其他內容無關。這可能是宇宙中最難以回答的問題了,它似乎牽扯到了哲學和倫理。不管怎樣,c++起初都被認為是帶類的c(c with classes),那他起碼也得比c語言更厲害一點,那似乎應該是1。真的是這樣嗎?回到**本身:

int c = 0;

printf("%d", c++);

這個……好像還是0!

函式宣告被誤以為建立物件

假設foo是乙個類,問以下**中有多少個物件被建立:

foo foo1();

foo foo2(2);

foo foo3[3];

foo* foo4[3];

foo& foo5 = foo2;

如果你被這個語法看花了眼,那一定是5個,因為你把第一行當成了用foo類的預設構造版本建立物件,其實他只是乙個返回值是foo型別的無參函式的宣告。注意,不同於new乙個物件,new foo;和new foo();是等價的,在棧中用預設建構函式建立物件的話請務必去掉這對圓括號。

&& 和 || 的優先順序

問以下**執行完後,b的值是多少:

int a = 2, b = 1, c = 0;

bool result = a > 0 || ++b && c;

如果你整天把&&、|| 短路短路求值的特性記得滾瓜爛熟而忘了他倆的優先順序這個最根本的東西,肯定會不假思索的回答1!

空指標呼叫物件的方法

老實說這個就是筆試題中的老鼠屎,你還得夾起來扔掉,要不然壞一鍋粥,看**:

class foo

};int main()

這得從哲學的角度好好想一想,傳int a 和 int* a時因為不知道陣列在記憶體中的邊界故而不清楚陣列的長度,那麼a退化成指標(即sizeof(a) == 4 or 8)似乎是乙個不錯的辦法,讓程式設計師自己想辦法解決大小問題;但是現在指定了陣列大小,是不是就意味著我了解了這個陣列引數真正的、確切的長度,那麼sizeof(a)是不是就是4 * 10 == 40呢?似乎從哲學上說的過去,那麼事實真的是這樣嗎?很遺憾,並不是,a依然只是個int*,引數裡的10在這裡好像並沒有什麼用,除了讓你自我感覺良好一點:看!我限制了傳入陣列的長度!但事實是你依然可以如此呼叫:

int a[3];

foo(a);

int* p = a;

foo§;

// 甚至……

foo(null);

就算你把整個天傳進去,在函式體內sizeof(a)永遠只是乙個指標的大小!如果真的想限制陣列引數的長度,那麼有兩種辦法:

傳指向指定大小陣列的指標

void foo(int (*a)[10]);

現在就只能傳大小為10的int陣列了,但是得在呼叫時稍微改變一下,得加乙個取位址操作符,即:foo(&a);

傳指定大小的陣列引用

void foo(int (&a)[10]);

完美解決你的問題!

陣列名和指標的關係

課堂上老師總是說陣列的名字就是指標,指向第乙個元素的位址。於是:

int a[3];

int* p1 = a;

int* p2 = &a;

對於上面的**,我當時認為這裡面的p1和p2是等價的,對於陣列的取位址操作(&)可有可無,就像引用乙個函式一樣:

void foo() {};

//…void(*f1)() = foo;

void(*f2)() = &foo;

事實上,這段對函式的引用是沒有問題的,取位址操作確實是可有可無的,甚至在某些編譯器上你都可以加任意個&,像這樣:

void(*p3)() = &&&&&foo;

但是,對於陣列來說,情況就完全不同了。

不加&的話表示乙個指向陣列第乙個元素的指標,他的型別是int*,也就是老師常說的陣列名就是指標;而加上&的話,就代表「取整個陣列的位址」,他的型別不是普通的指標了,而是指向乙個特定大小的陣列的指標,對於上面來說,就是int()[3]了,對其解引用,得到的才是乙個int,指向該陣列的第乙個元素。那麼問題來了,這個型別能不能賦值給int* 型別的變數呢?畢竟他們都是指標,最終都是指向int的,答案當然是不行!所以上面的int* p2 = &a;是根本不能通過編譯的,應該是int (*p2)[3] = &a;。

int的意思大概是:記憶體裡有好多個int,我的任務就是指向其中乙個。

int()[3]的意思大概是:記憶體中有好多3個int連在一起的空間,我的任務就是指向其中乙個空間的開始。

這就好理解為什麼對int()[3]解引用後便是乙個普通的int指標,意思大概是:我int()[3]已經在記憶體中找到了3個int連續的空間了,確定到底要其中哪個int的任務就交給你int*吧!

上面這話的意思是這兩種型別步進的偏移不同:32位環境下,int* 的偏移就是int的大小,即4,int(*)[3]的偏移是3個int的大小,即12。知道了這兩種區別,就不會做錯下面這道面試題了:

int a[5] = ;

printf("%d,%d", *(a + 1), ((&a + 1) - 1));

(a + 1)很好理解,就是陣列的第2個元素,即2;重點是((&a + 1) - 1),先看&a + 1,前面說過了,&a代表指向有5個元素的陣列的指標,他的步進偏移是5 * 4 = 20,所以&a + 1可以看成是代表這個陣列後面的那個相同大小陣列的位址,比a的位址高20個位元組,然後給他解引用,前面說過,得到了指向int的指標,此時這個指標指向陣列a後面的那個陣列的第乙個元素,而實際情況是a後面並沒有陣列了,若是此時對這個指標進行解引用,那麼要麼得到乙個隨機值,要麼直接崩潰。接著,對解引用出來的int 減了個1,int*的偏移是4,故向前偏移4個位元組,這不正好指向了陣列a的最後乙個元素嗎?解引用之,得到5。

你還會發現,這個型別不就是二維陣列的陣列名的型別嗎?像這樣:

int a[2][3];

int (*p)[3] = a;

而對二維陣列取位址,結果就又是另外一種情況了……好了,就此打住。

建構函式中成員變數的初始化順序

分析這段**的輸出:

class foo

void print()

}// …

foo foo;

foo.print();

原文:

joda time遇到的坑

system.out.println datetime.parse 2015092408 datetimeformat.forpattern yyyymmddhh getmillis system.out.println datetime.parse 2015092408 datetime form...

Spring Websocket 遇到的坑

1 跨域問題 經查閱官方文件springwebsocket 4.1.5版本前預設支援跨域訪問,之後的版本預設不支援跨域,需要設定 setallowedorigins override public void registerwebsockethandlers websockethandlerregi...

打包遇到的坑

android studio 錯誤 com.android.dex.dexindexoverflowexception method id not in 0,0xffff 65536 gradle中引用的包太多 android dex最大索引範圍為65536個方法 一旦超過酒會報這種錯誤 那麼此時就...