1.在C++中同一個程序中可以定義相同名字的變量的,但是先定義的變量如i會被後定義的變量i給覆蓋,
int i = 1;
void main()
{
int i = i;
}
這裏,main函數裏面的i與main(外的i無關,而是一個未定義的值。)
2.1.“==” 與 “=”
“==”: 是判斷左右兩值是否相等,一般情況下,最好將常量作爲左值,因爲常量在“=”中不能不能作爲左值,如果將“==”寫成了“=”,這樣編譯器就會報錯。
“=”: 是賦值語句,即將右邊的值賦給左邊的變量中,因此,”=“左邊不能爲常量。
2.2位與 與 與運算(位或 與 或運算)
”&“: 這個是位與,計算時需要將數轉換爲二進制之後進行相應位之間的與運算。位或(|)同理。4 & 0 = 4. 4 | 0 = 4.
”&&“: 是與運算,即左右兩邊的值只有零與非零兩種情況,只有當兩邊的值都不爲零的時候才位1.或運算(||)也同樣的看待。4 && 0 = 0. 4 || 0 =1.
3.二進制中包含1的個數
int func(int x)
{
int count = 0;
while(1)
{
count ++;
x = x &(x-1);
}
return count;
}
該函數返回的是x轉換爲二進制之後爲1的個數。假如x = 9999(10011100001111),count = 8;
count = 10011100001111 & 10011100001110 = 10011100001110
count = 10011100001110 & 10011100001101 = 10011100001100
count = 10011100001100 & 10011100001011 = 10011100001000
count = 10011100001000 & 10011100000111 = 10011100000000
count = 10011100000000 & 10011011111111 = 10011000000000
count = 10011000000000 & 10010111111111 = 10010000000000
count = 10010000000000 & 10001111111111 = 10000000000000
count = 10000000000000 & 01111111111111 = 0
4.1. "&&"與運算中,左右兩邊值真才爲真,當左邊的值爲假時右邊的條件就不執行了。
4.2. i++: 是先對i進行了操作之後,才進行i++;
++i: 是先進行i + 1之後纔對i進行操作。
5. C中printf計算參數時是從右到左壓棧的。
main()
{
int b = 3;
int arr[] = {6,7,8,9,10};
int * ptr = arr;
*(ptr++) += 123;
/* 打印結果:129 7 8 8 */
printf("%d %d %d %d\n",*(ptr - 2),*(ptr - 1),*ptr,*(++ptr));
/* 打印結果:7 7 8 8 */
printf("%d %d %d %d\n",*(ptr - 1),*(ptr - 1),*ptr,*(++ptr));
}
分析:首先一開始指針ptr是指向數組arr的第0個下標,即指向6,
但是*(ptr++) += 123;先對*ptr += 123 = 129進行了操作之後,ptr + 1,即指針指向數組的1下標,即7.
在printf計算參數時是從右到左壓棧的,所以第一個進行運算的參數也是最右邊的參數是*(++ptr):即指針ptr + 1,指向數組下標2的數,即8,然後取*(ptr)打印出來,打印8.
第二個參與運算的參數是*ptr,因爲這個時候指針沒有進行任何的移動,所以指針還是指向數組下標爲2的數,即8.
同樣的道理,下一個參數爲*(ptr - 1):指針先減1,即ptr指向數組下標爲1的數,即7.
疑惑:*(++ptr) 與 *(ptr + 1)的區別
*(++ptr): 操作結束之後,指針會進行ptr+ 1移動,而*(ptr + 1)進行操作的時候,只是根據指針ptr+ 1 計算對應的值出來,但是指針還是指向原來的位置,並沒有進行ptr + 1移動。
6.1. if ('A' == a)的寫法好過if (a == 'A'),因爲這時如果將”==“誤寫爲”=“,因爲編譯器不允許對常量賦值,就可以檢查到錯誤。
6.2. 在進行循環運算的時候,一些算法可以放到循環體外,這樣不需要每次進行循環的時候都要進行運算,可以提高程序的效率,但是缺點就是代碼不夠簡潔。
7.浮點數在內存中的存放方式:
任何數據在內存中都是以二進制的形式存儲的,在Intel CPU架構的系統中,存放的方式是小端的方式。
浮點數在目前所有的C/C++編譯器都是採用IEEE所制定的標準浮點格式,即二進制科學表示法。
V = (-1)s * M * 2E的形式來表示一個數:
s(sign)符號: 決定這個數是負數(s = 1)還是正數(s = 0).對於數值0的符號位作爲特殊情況處理。
M(significand)尾數:(規定M的整數部分恆爲1,所以這個1就不進行存儲了) 是一個二進制小數(有效數字位),它的範圍是1~2的n次方-1,或者是0~1-2的n次方。
E(exponent)階碼: 對浮點數據加權,這個權重的2的E次冪。
類型 符號位
階碼 尾數
Bias(偏置值)
float 1
8 23
127 (32位)
double
1 11 52
1023 (64位)
舉例:float型數據125.5轉爲標準浮點格式:
125的二進制表示形式1111101,小數部分表示爲二進制位1,則125.5二進制表示爲1111101.1,
由於規定尾數的整數部分恆爲1,則表示爲1.1111011 * 2^6, 階碼爲6,則加上偏置位127爲133,133的二進制:10000101
對於尾數將整數部分1去掉,爲1111011(1.1111011的尾數),在其後面補0使其位數達到23位:11110110000000000000000.
則125.5的二進制表現形式:0 10000101 11110110000000000000000
然後125.5在內存中的存放方式爲:
高地址 低地址
01000010
11111011 00000000
00000000
int main()
{
float a = 1.0f;
/* 強制輸出a 的整數部分。 */
cout << (int)a << endl;
/* 輸出的是在內存中a所對應的地址。*/
cout << &a << endl;
/* 浮點數在內存裏和整數的存儲方式不同。(int &)a相當於將該浮點數地址開始的sizeof(int)個字節當成(int)型的數據輸出,因此這取決於float型數據在內存中的存儲方式*/
cout << (int &)a << endl;
/* boolalpha: 函數名稱,功能是把bool值顯示爲true 或false. 否則輸出將爲1/0 */
cout << boolalpha << ((int)a == (int &)a) << endl;
float b = 1.0f;
cout << (int)b = endl;
cout << &b << endl;
cout << (int &)b << endl;
/* float a = 1.0f在內存中的表示都是3f800000,而浮點數和一般的整型不同,當(int &)b強制轉換時,會把內存值3f800000當做int型輸出,*/
cout << boolalpha << ((int)b == (int &)b) << endl;
return 0;
}
8.指針類型的轉換
時時刻刻記住一點,所有的指針都是佔四個字節。
int main()
{
unsigned int a = 0xFFFFFFF7;
/* 將int類型的a轉換爲unsigned char類型,由於int類型在內存中佔4個字節,而unsigned char 類型在內存中佔1個字節,所以輸出的時候只能輸出1個低字節,3位和高於3位的數據將被程序自動拋棄。*/
unsigned char i = (unsigned char)a;
/* 0x000000F7. */
printf("%08x\n",i);
/* 將&a是一個指向unsigned int的指針,現在被強制轉換爲char *型的指針,因爲所有類型的指針在內存中都是佔4個字節,所以沒有數據丟失,可以輸出原本的數據。*/
char *b = (char *)&a;
printf("%08x\n,"*b);
}
9.C語言中符號運算符的優先級
第1級: []
() .
-> (從左到右)
第2級: - ~ ++
-- *
& ! (type)
sizeof (右到左)
第3級: /
* %
第4級: +
-
第5級: <<
>>
第6級: >
>= <
<=
第7級: ==
!=
第8級: &
第9級: ^
第10級: |
第11級: &&
第12級: ||
第13級: ?:
第14級: =
/= *=
%= += -=
<<= >>=
&= ^=
|=
第15級: ,
例子: b = ~a >> 4 + 1;
分析:b = (~a) >> (4 + 1);
10.判斷一個數是否是2的n次方
如果該數是2的n次方的話:
00000000 0
00000001
1
00000010
2
00000100
4
00001000
8
00010000
16
00100000
32
01000000
64
10000000
128
那麼該數x與(x-1) 相位與的話,結果便爲0.
00000100 & 00000011 = 0.
所以可以根據 !(x & (x - 1))。
11.
int f(int x, int y)
{
return (x & y) + ((x ^ y)>> 1);
}
那麼:(729,271) = __.
分析:(x & y) :是表示x 與 y 相應位都爲1的時候才爲1,這個結果是x與y的相同位的一半。
(x ^ y) >> 1: 是表達的x 與 y 相應位不同的時候就爲1(即表示的是x 與 y 的不同位),>>1:可以表示除2(x 與 y 的不同位的一半).
那麼f(x,y)求的是x與y的平均值。
12.位運算實現兩個整數的加法運算。
int Add(int a, int b)
{
if(b == 0)
{
return a;
}
int sum, carry;
sum = a ^ b;
//位運算沒有進位
carry = (a & b) << 1;
//完成第二步進位的加法運算並且左移
return Add(sum, carry);
//進行遞歸,相加。
}
13.找出兩個數的較大數
1. int max = ((a + b) + abs(a - b)) / 2;
/*根據兩數相減後的數的符號,如果爲負數,那麼31位存放的是1, 如果是正數,31位存放的是0. */
2. int c = a - b;
char * strs[2] = {"a Large ", “b Large ”};
c = unsigned(c) >> (sizeof(int) * 8 - 1);
14.獲得三個數中的中間數(非最大,非最小)
inline int max(int a, int b){return a>= b ? a : b;}
inline int min(int a, int b){return a<= b ? a :b;}
inline int medium(int a, int b, int c)
{ //求兩兩數的最大值,則可以排除最小值
int t1 = max(a,b);
int t2 = max(a,b);
int t3 = max(a,b);
//返回最大兩個數中的最小值,那麼就是中間值
return min(t1, min(t2, t3));
}
15.a,b兩個數不使用中間值進行交換
1. 缺點就是如果a,b都是較大的兩個數,a = a + b會越界
a = a + b;
//兩個數相加,爲接下來做準備
b = a - b;
//a - b得到的就是原來的a,賦給b
a = a - b;
//a - b得到的就是原來的b,賦給a
2. 最好的方法
a = a ^ b;
//得到相應位不同則爲1,
b = a ^ b;
//又進行異或,則可以得到原來的a
a = a ^ b;
//得到原來的b
16.在C++程序中被C編譯器編譯後的函數,爲什麼要用“exter C”?
因爲C++語言支持函數重載,C語言不支持函數重載。函數被C++編譯後在庫中的名字與C語言的不同。假設某個函數的原型爲void foo(int x, int y).
該函數被C編譯器編譯後在庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字。
C++提供了C連接交換制定符合extern "C"解決名字匹配問題。
17.頭文件中的ifndef/define/endif是幹什麼用的?
防止該頭文件被重複引用。
18.switch語句:
當從滿足case 'c':開始,如果執行了相應的指令之後沒有break終止switch
語句,那麼餘下的case操作,不管滿不滿足相應的條件,都會被執行的。
程序員面試寶典第四版第五章
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.