1. 程式人生 > >嗨翻C語言--這裏沒有蠢問題(一)

嗨翻C語言--這裏沒有蠢問題(一)

環境變量 文本編輯 進制 括號 大寫 指針變量 位數 literal 意義


問:card_name[0]是什麽意思?
答:它是用戶輸入的第一個字符。如果用戶輸入了10,那麽card_name[0]就將是1。
問:總是得用/*和*/寫註釋嗎?
答:如果你的編譯器支持C99標準,就可以用//開始註釋。編譯器會將這一行的其余部分當做註射處理。
問:怎麽才能知道我的編譯器支持哪種標準?
答:你可以查看編譯器的文檔。對gcc來講,ANSI,C,C99和C11這三種標準它全部支持。
問:為什麽我在linux和Mac中運行程序時必須在程序前加上./?
答:因為在類Unix操作系統中,運行程序必須指定程序所在的目錄,除非程序的目錄已經列在了PATH環境變量中。
問:為什麽字符要從0開始編號?為什麽不是1?
答:字符的索引值是一個偏移值:它表示當前要引用的這個字符到數組中第一個字符之間有多少個字符。
問:為什麽要這樣做?
答:計算機在存儲器中以連續字節的形式保存字符,並利用索引計算出字符在存儲器中的位置。如果計算機知道c[0]位於存儲器1 000 000號單元,那麽就可以很快地計算出c[96]在1 000 000+96號單元。
問:為什麽要設立哨兵字符?難道計算機就不知道字符串的長度嗎?
答:通常不知道。記錄數組的長度不是C語言的強項,字符串其實就是個數組。
問:C語言居然不知道數組有多長?
答:是的,雖然編譯器有可以通過分析代碼計算出數組的長度,但一般情況下,C語音希望你來記錄數組的長度。
問:單、雙引號有區別嗎?
答:有區別,單引號通常用來表示單個字符,而雙引號通常用來表示字符串。
問:我應該用雙引號(“)定義字符串。還是以顯式字符數組的形式定義字符串?
答:通常應該用雙引號來定義字符串。用雙引號定義的字符串叫字符串字面值(string literal),比起字符數組,它輸入起來也更方便。
問:字符串字面值和字符數組有沒有區別?
答:只有一個區別:字符串字面值是常量。
問:那是什麽意思?
答:也就是說這些字符一旦創建完畢,就不能在修改它們。
問:如果我改了會怎麽樣?
答:這取決於編譯器,gcc通常會顯示總線錯誤(bus error)。
問:總線錯誤?那是什麽東西?
答:C語言采取不同的方式在存儲器中保存字符串字面值。總線錯誤意味著程序無法更新那一塊存儲器空間。
問:為什麽不能寫一個|和&?
答:也不是不行。&和|操作符總是計算兩個條件,而&&和||可以跳過第二個條件。
問:那還要|和&幹什麽呢?
答:對邏輯表達式求值只是它們的一個用處,它們還能對數字的某一位進行布爾運算。
問:那是什麽意思?
答:6 & 4等於4,是因為當對(二進制110)和4(二進制數100)的每一個二進制位布爾與時,就會得到4(二進制數100)。
問:為什麽我要用switch語句取代if?
答:當需要多次檢查同一變量時,使用switch語句會更方便。
問:使用switch語句有什麽好處?
答:有這幾個好處。第一,讓代碼更清晰,一段代碼處理一個變量的結構,結構一目了然,相反,一連串的if語句就沒那麽清晰了;第二,可以用下落邏輯在不同的分支之間復用代碼。
問:switch語句只能檢查變量嗎?它能檢查值嗎?
答:能,switch語句僅僅檢查兩個值是否相等。
問:我能在switch語句中檢查字符串嗎?
答:不能用switch語句檢查字符串或任何形式的數組,switch語句只能檢查值。
問:如果我創建了一個void函數,是否就意味它一定不能有return語句?
答:你還是可以包含return語句,但編譯器很可能會產生一條警告消息。而且在void函數中包含return語句沒有任何意義。
問:真的嗎?為什麽沒有意義?
答:因為如果你試圖讀取void函數的值,編譯器會報錯。
問:C語音為什麽需要編譯?其他一些語音就不需要編譯,比如JavaScript,是嗎?
答:為了讓代碼執行起來更快,C語音需要編譯。盡管有寫語音不是編譯型語言,但它們中的一些,向JavaScript和Python,為了提高速度通常會在幕後使用一些編譯技術。
問:C++是另一個版本的C語音嗎?
答:不是,雖然C++的設計初衷是為了擴展C,但現在看來遠不止如此,人們最初創造的C++和Objective-C都是為了C語音面向對象的程序。
問:什麽是面向對象?我們在本書中會學嗎?
答:面向對象是一種對抗軟件復雜性的技術,我們在本書中不會做專門的研究。
問:C語音為什麽看起來很像JavaScript,Java和C#語言?
答:C語言的語法非常簡潔,因此影響到了很多其他語言。
問:gcc這三個字母分別代表什麽含義?
答:GNU編譯器套裝(GNU Compiler Collection)
問:為什麽是“套裝”?難道不止C語言一種嗎?
答:GNU編譯器套裝可以用來編譯很多語言,而C語言可能是人們在應該gcc時使用最多的語言。
問:我能創建一個永無止境的循環嗎?
答:可以,如果循環條件的值是1,循環就會永無止境地運行下去。
問:創建一個永無止境的循環是個好主意嗎?
答:有時候是,通常在一些如網絡服務器的程序中會使用無限循環(一個永無止境的循環),程序會反復地做一件事知道人們停止它。但大部分的程序員使用循環是為了讓它們在某個時刻停止。
問:我在自己的機器上打印了變量的單元號,但它不是4 100 000。是不是哪裏做錯了?
答:你沒有做錯,在不同機器中,程序用來保存變量的存儲器單元號不同。
問:為什麽局部變量保存棧裏,而全局變量保存在其他地方?
答:局部變量和全局變量的用法不同。你永遠只能得到一份全局變量,但如果寫了一個調用自己的函數,就會得到同一個局部變量的很多個實例。
問:存儲器中的其他區域是用來做什麽的?
答:你會在本書的後續章節中看到它們的作用。
問:指針是真實的地址單元,還是某種形式的引用?
答:它們是進程存儲器中真實編號的地址。
問:為什麽存儲器是進程的?
答:計算機會為每個進程分配一個簡版存儲器,看起來就像是一長串字節。
問:但存儲器並非如此?
答:實際的存儲器復雜多了,但細節對進程隱藏了起來,這樣操作系統就可以在存儲器中移動進程,或釋放並重新加載到其他位置。
問:存儲器不僅僅是一長列字節?
答:物理存儲器的結構十分復雜,計算機通常會將存儲器地址分組映射到存儲芯片的不同的存儲體(memory bank)。
問:我需要理解它是怎麽映射的嗎?
答:對大部分程序來說,你不需要關心機器組織存儲器的細節。
問:為什麽我一定要用%p格式串來打印指針?
答:不一定要用%p,在大多數的現代計算機上可以用%li,但編譯器可能會給出一條警告。
問:為什麽%p以十六進制顯示存儲器地址?
答:工程師通常以十六進制表示存儲器地址。
問:如果我們把讀取存儲器單元的內容稱為“解引用”,那麽指針是不是應該叫“引用”?
答:人們有時候會把指針叫做“引用”,因為它引用了存儲器中的某個地址單元。但C++程序員通常用“引用”表示C++中一個稍有不同的概念。
問:太好了,C++,我們會學到嗎?
答:別想了,這本書只教C語言
問:sizeof是一個函數嗎?
答:不是,它是一個運算符。
問:有什麽區別?
答:編譯器會把運算符編譯為一串指令,而當程序調用函數時,會跳到一段獨立的代碼中執行。
問:所以程序是在編譯期間計算sizeof的?
答:沒錯,編譯器可以在編譯時確定存儲空間的大小。
問:為什麽在不同的計算機上指針變量的大小不同?
答:在32位操作系統中,存儲器地址以32位數字的形式保存,所以它叫32位操作系統。32位==4字節,所以64位操作系統要用8個字節來保存地址。
問:如果我創建了一個指針變量,它位於存儲器中嗎?
答:是的,指針變量只不過是一個保存數字的變量罷了。
問:我可以找到指針變量的地址嗎?
答:可以用&運算符找到它的地址。
問:我可以把指針轉化為一般的數字嗎?
答:在大多數操作系統中,可以這樣做。C編譯器通常會把long數據類型設為和存儲器地址一樣長。如果想要把指針p保存在long變量a中,可以輸入a=long(p)。
問:是在大多數操作系統中嗎?所以並不是全部?
答:並不是全部。
問:我真的需要理解指針算術運算嗎?
答:有的程序員不使用指針算術運算,因為它很容易出錯,但你可以用它有效地處理數組數據。
問:指針能做減法嗎?
答:能,但小心別讓指針越過數組的起點。
問:C語言什麽時候對指針算術運算進行調整?
答:在編譯器生成可執行文件時,編譯器會根據變量的類型,用變量的大小乘以指針的增量或減量。
問:然後呢?
答:假如編譯器看到你對一個指向int數組的指針加2,就會用2乘以4(int長度),然後對地址加8。
問:C語言在調整指針算術運算時用了sizeof運算符嗎?
答:本質上如此,sizeof運算符的結果也是在編譯時決定的,對各種數據類型,sizeof和指針算術運算都將使用相同的長度。
問:指針可以相乘嗎?
答:不可以。
問:為什麽要把數組定義成tracks[][80]而不是tracks[5][80]?
答:也可以這樣定義,但編譯器知道列表有5項,所以你可以省略5寫成[]。
問:既然如此,為什麽不直接寫tracks[][]?
答:每首歌的名字不一樣長,為了放下最長的歌名,需要讓編譯器分配足夠大的空間。
問:也就是說tracks數組中每個字符串都有80個字符?
答:程序會為每個字符串分配80個字符,即使歌名很短。
問:所以tracks數組一共占了80 * 5 = 400字符?
答:沒錯。
問:如果我忘了string.h這樣的頭文件會怎樣?
答:對於某些頭文件來說,編譯器會給出一個警告,但最後還是會包含它們;但對另一些來講,編譯器會直接提示編譯錯誤。
問:為什麽我們要把tracks數組定義在函數外面?
答:我們把tracks放在全局域,全局變量可以在所有函數中使用。
問:既然我們創建了兩個函數,計算機會先運行哪一個?
答:程序總是首先運行main()函數。
問:為什麽我一定要把find_track()放在main()之前?
答:在調用函數前,編譯器需要知道兩件事,函數接收什麽參數以及函數的返回值類型是什麽。
問:如果我把main()放在前面會怎麽樣?
答:你會得到幾個警告。
問:既然有stdout和stderr,自然就有stdin吧?
答:有,如你所料,它代表標準輸入。
問:我可以打印stdin嗎?
答:不可以
問:我可以從stdin中讀取數據嗎?
答:恩,你可以使用fscanf()來讀取,它的用法和scanf()很像,區別是可以自動fscanf()從哪條數據流中讀取數據。
問:也就是說fscanf(stdin,...)和scanf()等價?
答:沒錯,它完全相同。說到底,scanf()就是用fscanf(stdin,...)實現的。
問:我可以重定向標準錯誤嗎?
答:可以,你可以用>重定向標準輸出,2>重定向標準錯誤。
問:所以我要寫geo2json > errors,txt?
答:沒錯
問:為什麽小工具要使用標準輸入和標準輸出?
答:有了它們,就可以輕易用管道將小工具蒙串連起來。
問:為什麽要把它們串連在一起?
答:小工具只能解決一個小技術問題,例如轉換數據的格式,而無法解決整個問題。只能把它們組合在一起,才能解決大問題。
問:到底什麽是管道?
答:不同操作系統實現管道的方法不同,可能用存儲器,也可能用臨時文件。我們只要知道它從一端接收數據,在另一端發送數據就行了。
問:如果兩個程序用管道相連,第二個程序要不要等第一個程序執行完後才能開始運行?
答:不需要,兩個程序可以同時運行,第一個程序一發出數據,第二個程序馬上就可以處理。
問:為什麽小工具要使用文本?
答:文本是一種開發格式,程序員可以用文本編輯器來查看小工具的輸出,並理解裏面的內容,相比之下,二進制格式就難懂多了。
問:我能用管道連接多個程序嗎?
答:能啊,只要在每個程序前加上一個1就行了,一連串相連的進程就叫流水線(pipeline)。
問:當我用管道連接多個進程時,<與>分別重定向哪個進程的標準輸入,哪個進程的標準輸出?
答:< 會把文件內容發送到流水線第一個進程的標準輸入, >會捕獲流水線中最後一個進程的標準輸出。
問:當我在命令行中運行bermuda和geo2json程序時,它們外面的括號是必須的嗎?
答:是的,這對括號保證保證了數據文件由bermuda程序的標準輸入來讀取。
問:最多能有幾條數據流?
答:這取決於操作系統。通常情況下,一個進程最多可以有256條數據流,但請記住,數據流的數量是有限的,用完後應該關閉它們。
問:為什麽FILE要大寫?
答:說來話長,最早FILE是用宏定義的,而宏的名字通常都要大寫。
問:我能合並兩個選項嗎?例如用-td now代替-d now -t。
答:可以,getopt()函數會全權處理它們。
問:我可以改變選項之間的順序嗎?
答:可以,因為我們用循環讀取選項,所以-d now -t, -t -d now, -td now都一樣。
問:也就是說,只要程序在命令行看到一個前綴為 - 值,就會把它當成選項處理?
答:是的,前提是它必須在命令行參數之前出現。
問:如果我想在命令行參數使用負數怎麽辦?像set_temperature -c -,程序會把4當做選項嗎?
答:為了避免歧義,可以用--隔開參數和選項,比如set_teperature -c -- -4。getopt()看到-- 就會停止讀取選項,程序會把後面的內容當成普通的命令行參數讀取。
問:為什麽不同操作系統的數據類型大小不同?設成一樣不是更明了?
答:為了適應硬件,C語言在不同的操作系統與處理器上使用不同的數據類型大小。
問:怎麽說?
答:C語言誕生之初還是8位機的天下,但現在大部分計算機都是32位和64位的,因為C語言沒有指定數據類型的具體大小,所以才能與時俱進。即使新的計算機處理,C語言還是能夠很好適應。
問:8位,64位到底是什麽意思?
答:從技術上來講,計算機的位數有多種含義,它既可以代表CPU指令的長度,也可以代表CPU一次從存儲器讀取數據的大小。實際上,位數是計算機能夠處理的數值長度。
問:這和int, double的大小有什麽關系?
答:如果一臺計算機能夠處理32位的數值,就會把基本數據類型(例如int)的大小設為32位。
問:我知道int這樣的整數是怎麽工作的,但float或double是怎麽保存的呢?計算機如何表示有小數點的數字呢?
答:一言難盡,大部分計算機使用了IEEE發布的標準。
問:我需要理解浮點數的工作原理嗎?
答:不需要,大部分程序員使用float與double時不會關註它們的細節。

嗨翻C語言--這裏沒有蠢問題(一)