C和指針 學習筆記—第1-2章

C和指針這本經典著作,最近開始學習,然後想與大家共享下,希望共同進步!網絡的力量是強大的,會碰撞出思想的火花來!

 

第一章 快速上手

1、要從邏輯上刪除一段C代碼,更好的辦法是使用#if指令:

#if 0

statements

#endif

#if  和 #endif之間的程序段就可以有效地從程序中去除,即使這段代碼之間原先存在註釋也無妨

 

2、關於scanf返回值的問題

     scanf函數,與printf函數一樣,都被定義在stdio.h裏,因此在使用scanf函數時要加上#include<stdio.h>。它是格式輸入函數,即按用戶指定的格式從鍵盤上把數據輸入到指定的變量之中,其關鍵字最末一個字母f即爲“格式”(format)之意。

scanf()函數返回成功賦值的數據項數,讀到文件末尾出錯時則返回EOF

 

3、當數組名作爲實參時,傳給函數的實際上是一個指向數組起始位置的指針,也就是數組在內存中的地址

 

4、爲什麼ch被聲明爲整型,但是又用來讀取字符的原因?

例如:

int ch;

while( (ch = getchar()) != EOF &&  ch != '\n');

EOF是一個整型值,它的位數比字符類型要多,把ch聲明爲整型可以防止從輸入讀取的字符意外地被解釋爲EOF。但同時,這也意味着接收字符的ch必須足夠大,足以容納EOF,這就是ch使用整型值的原因。儘管char類型變量的目的是爲了讓它們容納字符型的值,但字符在本質上是小整型值 

 

5、數組做參數的時候是以引用的方式傳遞的,即地址傳遞。而標量和常量都是傳值調用,被調用的函數無法修改調用函數以傳值形式傳遞給它的參數,然而當被調用函數修改數組參數的其中一個元素時,調用函數所傳遞的數組就會被實際修改。

當數組名作爲實參時,傳給函數的實際上是一個指向數組起始位置的指針,也就是數組在內存中的地址。正因爲實際傳遞的是一個指針而不是一份數組的拷貝,才使數組名作爲參數時具備了傳址調用的語義。函數可以按照操縱指針的方式來操縱實參,也可以像使用數組名一樣用下標來引用數組的元素。

但是,由於它的傳址調用語義,如果函數修改了形參數組的元素,它實際上將修改實參數組的對應元素。

 

6字符串是以一串NUL字節結尾的字符。NUL作爲字符串終止符,它本身並不被看作字符串的一部分。字符串常量就是源程序中被雙引號括起來的一串字符。

 

7、使用scanf函數應該注意:使用所有格式碼(除了%c之外)時,輸入值之前的空白(空格、製表符、換行符等)會被跳過,值後面的空白表示該值的結束,因此,用%s格式碼輸入字符串時,中間不能包含空白。

 

8、編譯器通常不對數組下標的有效性進行檢查。(是因爲下標引用可以作爲任意的指針,而不僅僅是數組名

 

9、while( gets(  input ) != NULL){}

你認爲這段代碼可能會出現什麼問題?

因爲gets沒有指定輸入字符的大小,會發生內存越界,堆棧溢出

 

 第二章 基本概念

1、ANSI C的任何一種實現中,存在兩種不同的環境:

第一種是翻譯環境:在這個環境裏,源代碼被轉換爲可執行的機器指令

第二種是執行環境:用於實際執行代碼

兩種環境不必在同一臺機器上

交叉編譯器:就是在一臺機器上運行,但它所生成的可執行代碼運行於不同類型的機器上。

 

2、翻譯

翻譯有幾個步驟組成:

首先,組成一個程序的若干個源文件通過編譯過程分別轉換爲目標代碼

然後,各個目標文件由鏈接器捆綁在一起,形成一個單一而完整的可執行程序

鏈接器同時也會引入標準C函數庫中任何被該程序所用到的函數,而且它也可以搜索程序個人的程序庫,將其中需要使用的函數也鏈接到程序中。

 

3、編譯

首先由預處理器處理,這個階段,預處理器在源代碼上執行一些文本操作

然後,源代碼經過解析,判斷它的語句的意思。第2個階段是產生絕大多數錯誤和警告的信息的地方。隨後,產生目標代碼。

 

目標代碼是機器指令的初步形式,用於實現程序的語句。如果我們在編譯程序的命令行中加入進行優化的選項,優化器就會對目標代碼進一步進行處理,使他的效率更高

 

4、編譯並鏈接一個完全包含於一個源文件的C程序,中間會產生*.o的目標文件,但它在鏈接過程完成後會被刪除。

 

5、編譯並鏈接幾個C文件,當源文件超過一個時,目標文件便不會刪除,這就允許你對程序進行修改後,只對那些進行改動的源文件進行重新編譯。

在UNIX系統中,C編譯器被稱爲cc,

cc program.c這個命令會產生一個稱爲a.out的可執行程序,中間會產生program.o的目標程序,但是鏈接完成後就被刪除

cc main.c sort.c lookup.c----->cc -o name main.o sort.o lookup.o意思是可以是鏈接器把可執行程序保存在name文件中,而不是a.out

 

6、執行

首先、程序必須載入到內存中,在宿主環境中,這個任務由操作系統完成,那些不是存儲在堆棧中的尚未初始化的變量將在這個時候得到 初始值。在獨立環境中,程序的載入必須由手工安排,也可能是通過把可執行代碼置入只讀內存中來完成。

 

然後,程序執行便開始。通常一個小型的啓動程序與程序鏈接在一起,它負責處理一系列日常事務,如收集命令行參數以便使程序能夠訪問它們。接着,便調用main函數

 

然後,便開始執行程序代碼;程序將使用一個運行時堆棧,它用於存儲函數的局部變量和返回地址;程序同時也可以使用靜態內存,存儲靜態內存中的變量在程序的整個執行過程中將一直保留他們的值。

 

最後一個階段:程序的終止;正常終止就是main函數返回;或者是用戶終止執行;或者是執行過程中出現錯誤而自行中斷。

 

7、標識符的長度沒有限制,但是標準允許編譯器忽略第31個字符以後的字符

雖然一個源文件可以包含超過一個的函數,但是每個函數都必須完整的出現在同一個源文件中。

 

絕大部分註釋都是成塊出現的,這樣他們從視覺上在代碼中很突出,讀者就可以很容易找到和跳過他們。

 

總結:

一個C程序的源代碼保存在一個或多個源文件中,但是一個函數只能完整的出現在同一個源文件中。把相關的函數放在同一個文件內是一種好策略。每個源文件都分別編譯,產生對應的目標文件。然後,目標文件被鏈接到一起,形成可執行程序。編譯和最終運行程序的機器有可能相同,有可能不同。

 

程序必須載入到內存中才能執行。在宿主式環境中,這個任務由操作系統完成。在自由式環境中,程序常常永久存儲在ROM;經過初始化的靜態變量在程序執行前能獲得他們的值。你的程序執行的起點是main函數。絕大多數環境使用堆棧來存儲局部變量和其他數據。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章