第五章
1.可以利用右移操作來計算乙個數值中含有1的位的個數。
value = value >> 1;value % 2 != 0;
後面這條語句還可以寫成
(value & 1) != 0;
2.可以用value = value | 1 << bit_number來對對應的
bit_number
位置一;同理,可以通
value = value & ~(1 << bit_number)
來對對應的
bit_number
位清零。
3.&操作符產生它的運算元的位址。
*操作符是間接訪問操作符,與指標一起使用,用於訪問指標所指向的值。
sizeof
操作符判斷它的運算元的型別長度,要位元組為單位表示。(型別)被稱為強制型別轉換符,用於顯式的把值轉換為另外的型別。
4.養成乙個習慣,當你進行相等性的測試比較的時候,你要檢查一下你所寫的確實是雙等號。
5.&&和
||操作符均遵循「短路求值」的原則,即當符號左側的值已經滿足條件的時候,就不再對右側表示式的值進行求值。
6.當你使用if語句的時候,不妨嘗試採用條件操作符,例如
if ( a > 5 )
b = 3;
else
b = -20;
可以寫成: b = a > 5 ? 3 : -20;是不是**量更小了呢?
7. .操作符合
->
操作符的區別,當你擁有的是乙個結構體變數
s,那麼
s.a就是訪問這個結構體中名為
a的結構體成員。如果你擁有的使乙個指向
s的指標
p,那麼你訪問
a的時候就要用
p->a
才是正確的。
8.避免混合使用整型值和布林值,如果乙個變數包含了乙個任意的整型值,應該現實的進行測試,而不是簡寫測試時非零還是零。如果是布林型別,必須是0或者
1.9.要注意有符號數字的移位操作。
第六章(指標)
1.關於邊界對齊,在要求邊界對齊的機器上,整型值儲存的起始位置只能是某些特定位元組,通常是2或者
4的倍數。
2.記憶體中的每個位置由乙個獨一無二的位址標識,記憶體中的每個位置都包含乙個值。
3.變數與記憶體位置之間的關聯並不是硬體所提供的,它是由編譯器為我們實現的。
4.變數的型別取決於它被使用的方式,因此不能簡單地通過檢查乙個值的位來判斷它的型別。
5.變數的值就是分配給該變數的記憶體位置所儲存的數值,即使是指標變數也不例外。
6.一般的,未初始化的指標咋
linux
中最常見的會引起「
segmentation violation
」或者「
memory fault
」,有時還會引起「
bus error
」在pc
端的windows
中,會引起保護性異常(
general protection exception
)。7.指標未初始化的最嚴重的情況就是:它非法的指向了乙個有用的位址,不自覺的這個位址的值被改變了,這種
bug是非常難找的。
8.當乙個指標被建立但是並不立刻使用的時候,需要將他賦值為
null
,可以使他返回的值有很多,
9.*100 = 25這樣的操作是非法的,因為
100是乙個整型值,間接訪問操作只能作用於指標型別的表示式,如果你確實想把
25儲存於位置
100,必須使用強制型別轉換,*(
int *
)100 = 25.
雖然《c
和指標》這本書裡說使用這種表示式的情況絕無僅有,但是做嵌入式底層的,這個應該還是有用武之地的。
10.*操作符的結合性是從右往左,
int **c
相當於int*(*c)
11.指標和乙個整數量執行算術運算的時候,整數在執行加法運算前始終會根據合適的大小進行調整,這個調整就是把整數值和「合適的大小」相乘,例如
int占用
4個位元組,乙個
int型別的指標
+4,實際上加到指標上的整型值為
4*4=16.
這樣做在實際使用的時候是更加合理的。這和指標的型別占用
4個位元組衝突嗎?
12.指標的算數運算只限於兩種,第一:指標
+-整數;第二:指標
- 指標。前者一般適用於指向陣列中某個元素的指標,也適用於
malloc
分配的記憶體。後者只能在指向同乙個陣列中使用。指標相減得到的是兩個指標在陣列中的位置的差值,而不是位址的差值。
13.對
null
指標進行解引用操作的後果?加入乙個指標
int *p;p=null.
編譯期會預設將
null
指標指向零位址,假如在
0位址存放了有效的值,這樣會誤操作改變了這塊記憶體的值。
第七章 函式
1.無返回值的函式叫做(過程型別函式),有返回值的函式叫做真函式。
2.函式的返回值是很重要的,所有的函式都應該具有原型,尤其是那些返回值不是整形的函式。當程式呼叫了乙個無法見到原型的函式的時候,編譯期便會認為該函式返回乙個整型值。
3.關於函式的引數:
(1)c函式的所有引數均以「傳值呼叫」方式進行傳遞;
(2)傳遞給函式的標量引數是傳值呼叫的;
(3)傳遞給函式的陣列引數在行為上就像它們是通過傳址呼叫那樣。(本質是乙個指標,傳遞給函式的是指標的乙份拷貝,下標引用實際上是間接訪問的另一種形式)。
4.抽象資料型別——adt(abstract data type),
抽象資料型別的基本想法很簡單,模組具有功能說明和介面說明,前者說明模組執行的任務,後者定義模組的使用。
5.c通過執行時的堆疊來支援遞迴函式的實現,直接或者間接的呼叫自身。理解了遞迴之後最容易的方法不是糾纏它的執行過程,而是相信遞迴會順利的完成它的任務。
6.遞迴函式的引數必須壓到堆疊中,為每次遞迴產生的區域性變數分配記憶體空間,暫存器的值必須儲存好,當每次呼叫返回的時候,這些操作必須還原,恢復成原來的樣子。
7.有時候,迭代可能比遞迴好用。採用遞迴計算斐波那契數列,當n=10的時候,
f(3)
被計算21
次,當n=30
的時候,
f(3)
被計算317811
次,開銷非常大。而用迭代就可以避免這個問題。
8.stdarg巨集是可變引數列表巨集,定義於
stdarg.h
標頭檔案中,它是標準庫的一部分,宣告乙個
va_list
和三個巨集
va_start,va_arg
和va_end
。在引數列表中至少要有乙個明明引數。
9.整數和字元之間的轉換可以借助』0』來實現,字元轉化為整數a - 『0』,整數轉化為字元b + 『0』。
第八章 陣列
1.陣列名的值是乙個指標常量,在兩種操作符的情況下可以例外,乙個是sizeof,乙個是
&.sizeof
返回的是整個陣列的長度,
&是乙個指向陣列的指標。
2.c之所以不進行下標檢查,是因為下標引用可以作用於任意的指標,而不僅僅是陣列名。
3.加入有乙個陣列array[10],那麼
2[array]
和array[2]
其實是等價的。
4.指標在某些場合具有比下標更好的效率,例如使用for迴圈對乙個陣列進行清零或者複製的時候,但是指標的使用往往出現劣質的**,效率一定取決於好的**。
5.宣告為暫存器變數的指標通常比位於靜態記憶體和堆疊中的指標效率更高。
6.注意字元陣列和字串常量的區別,char massage = 「hello world」和char *message = 「hello world」的區別。
7.區分陣列的首位址和陣列首元素的位址,假如乙個陣列宣告為int matrix[3][10],那麼
matrix+1
其實指向的是第二行的首位址,而不是陣列第二個元素的位址。第二個元素的位址應該是
matrix[0][1];
8.在將二維陣列的陣列名作為引數傳遞給函式的時候,二維陣列的宣告如下:void func2(int (*mat)[array_length]).或者
void func2(int mat[array_length]);
只有第一維可以省略,其他維必須顯氏的寫出來。
9.陣列的下標引用的優先順序要高於間接訪問。
10.計算陣列元素的個數可以採用 #define n_keyword = (sizeof(array)/sizeof(array[0]))。
C和C指標讀書筆記
1.c中變數的儲存型別 儲存型別分為靜態儲存 普通記憶體 堆疊,暫存器自動變數即 塊內部的變數儲存於堆疊,其他變數儲存於普通記憶體即靜態儲存,如果頻繁訪問乙個變數,宣告為暫存器型別後儲存於硬體暫存器中。2.c中實體的鏈結屬性 1 屬於internal鏈結屬性的識別符號在同乙個原始檔內的所有宣告中都指...
C和指標讀書筆記 第3章(資料)
1.長整型至少和整型一樣長,而整型至少和短整型一樣長 char 乙個位元組 int 四個位元組 signed表示有符號數 unsigned表示無符號數,如果顯示的把變數宣告為signed和unsigned,可以提供程式的可移植性。2.如果乙個多位元組字元常量的前面有乙個l,那麼它就是寬字元常量。3....
C和指標讀書筆記 第7章(函式)
1.把函式的型別與函式名分寫成兩行純屬風格問題。這種寫法可以使我們在使用視覺或者某些工具追蹤 時更容易查詢程式。2.ruturn 語法並沒有要求你加上括號。3.向編譯器提供函式資訊的方法是使用函式原型。原型總結了函式定義的起始部分的宣告,向編譯器提供有關該函式應該如何呼叫的完整資訊。在函式原型後面要...