第1章 聲明和初始化
基本類型
1.1 我該如何決定使用哪種整數(shù)類型?
1.2 為什么不精確定義標準類型的大???
1.3 因為C語言沒有精確定義類型的大小,所以我一般都用typedef定義int16和int32。然后根據實際的機器環(huán)境把它們定義為int、short、long等類型。這樣看來,所有的問題都解決了,是嗎?
1.4 新的64位機上的64位類型是什么樣的?
指針聲明
1.5 這樣的聲明有什么問題?char *p1, p2; 我在使用p2的時候報錯了。
1.6 我想聲明一個指針,并為它分配一些空間,但卻不行。這樣的代碼有什么問題?char *p; *p=malloc(10);
聲明風格
1.7 怎樣聲明和定義全局變量和函數(shù)最好?
1.8 如何在C中實現(xiàn)不透明(抽象)數(shù)據類型?
1.9 如何生成“半全局變量”,就是那種只能被部分源文件中的部分函數(shù)訪問的變量?
存儲類型
1.10 同一個靜態(tài)(static)函數(shù)或變量的所有聲明都必須包含static存儲類型嗎?
1.11 extern在函數(shù)聲明中是什么意思?
1.12 關鍵字auto到底有什么用途?
類型定義(typedef)
1.13 對于用戶定義類型,typedef 和#define有什么區(qū)別?
1.14 我似乎不能成功定義一個鏈表。我試過typedef struct{char *item; NODEPTR next;}* NODEPTR; 但是編譯器報了錯誤信息。難道在C語言中結構不能包含指向自己的指針嗎?
1.15 如何定義一對相互引用的結構?
1.16 Struct{ } x1;和typedef struct{ } x2; 這兩個聲明有什么區(qū)別?
1.17 “typedef int(*funcptr)();”是什么意思?
const 限定詞
1.18 我有這樣一組聲明:typedef char *charp; const charp p; 為什么是p而不是它指向的字符為const?
1.19 為什么不能像下面這樣在初始式和數(shù)組維度值中使用const值?const int n=5; int a[n];
1.20 const char *p、char const *p和char *const p有什么區(qū)別?
復雜的聲明
1.21 怎樣建立和理解非常復雜的聲明?例如定義一個包含N個指向返回指向字符的指針的函數(shù)的指針的數(shù)組?
1.22 如何聲明返回指向同類型函數(shù)的指針的函數(shù)?我在設計一個狀態(tài)機,用函數(shù)表示每種狀態(tài),每個函數(shù)都會返回一個指向下一個狀態(tài)的函數(shù)的指針??晌艺也坏饺魏畏椒▉砺暶鬟@樣的函數(shù)——感覺我需要一個返回指針的函數(shù),返回的指針指向的又是返回指針的函數(shù),如此往復,以至無窮。
數(shù)組大小
1.23 能否聲明和傳入數(shù)組大小一致的局部數(shù)組,或者由其他參數(shù)指定大小的參數(shù)數(shù)組?
1.24 我在一個文件中定義了一個extern數(shù)組,然后在另一個文件中使用,為什么sizeof取不到數(shù)組的大???
聲明問題
1.25 函數(shù)只定義了一次,調用了一次,但編譯器提示非法重聲明了。
1.26 main的正確定義是什么?void main正確嗎?
1.27 我的編譯器總在報函數(shù)原型不匹配的錯誤,可我覺得沒什么問題。這是為什么?
1.28 文件中的第一個聲明就報出奇怪的語法錯誤,可我看沒什么問題。這是為什么?
1.29 為什么我的編譯器不允許我定義大數(shù)組,如double array[256][256]?
命名空間
1.30 如何判斷哪些標識符可以使用,哪些被保留了?
初始化
1.31 對于沒有顯式初始化的變量的初始值可以作怎樣的假定?如果一個全局變量初始值為“零”,它可否作為空指針或浮點零?
1.32 下面的代碼為什么不能編譯? intf(){char a[]="Hello, world!";}
1.33 下面的初始化有什么問題?編譯器提示“invalid initializers ”或其他信息。char *p=malloc(10);
1.34 char a[]= "string literal";和char *p="string literal"; 初始化有什么區(qū)別?當我向p[i] 賦值的時候,我的程序崩潰了。
1.35 char a{[3]}= "abc"; 是否合法?
1.36 我總算弄清楚函數(shù)指針的聲明方法了,但怎樣才能初始化呢?
1.37 能夠初始化聯(lián)合嗎?
第2章 結構、聯(lián)合和枚舉
結構聲明
2.1 struct x1{ };和typedef struct{ }x2; 有什么不同?
2.2 這樣的代碼為什么不對?struct x{ }; x thestruct;
2.3 結構可以包含指向自己的指針嗎?
2.4 在C語言中用什么方法實現(xiàn)抽象數(shù)據類型最好?
2.5 在C語言中是否有模擬繼承等面向對象程序設計特性的好方法?
2.6 為什么聲明extern f(struct x *p); 給我報了一個晦澀難懂的警告信息?
2.7 我遇到這樣聲明結構的代碼:struct name {int namelen; char namestr[1];};然后又使用一些內存分配技巧使namestr數(shù)組用起來好像有多個元素,namelen記錄了元素個數(shù)。它是怎樣工作的?這樣是合法的和可移植的嗎?
2.8 我聽說結構可以賦給變量也可以對函數(shù)傳入和傳出。為什么K&R1卻明確說明不能這樣做?
2.9 為什么不能用內建的==和!=操作符比較結構?
2.10 結構傳遞和返回是如何實現(xiàn)的?
2.11 如何向接受結構參數(shù)的函數(shù)傳入常量值?怎樣創(chuàng)建無名的中間的常量結構值?
2.12 怎樣從/向數(shù)據文件讀/寫結構?
結構填充
2.13 為什么我的編譯器在結構中留下了空洞?這導致空間浪費而且無法與外部數(shù)據文件進行“二進制”讀寫。能否關掉填充,或者控制結構域的對齊方式?
2.14 為什么sizeof返回的值大于結構大小的期望值,是不是尾部有填充?
2.15 如何確定域在結構中的字節(jié)偏移量?
2.16 怎樣在運行時用名字訪問結構中的域?
2.17 C語言中有和Pascal的with等價的語句嗎?
2.18 既然數(shù)組名可以用作數(shù)組的基地址,為什么對結構不能這樣?
2.19 程序運行正確,但退出時卻“core dump ”(核心轉儲)了,怎么回事?
聯(lián)合
2.20 結構和聯(lián)合有什么區(qū)別?
2.21 有辦法初始化聯(lián)合嗎?
2.22 有沒有一種自動方法來跟蹤聯(lián)合的哪個域在使用?
枚舉
2.23 枚舉和一組預處理的#define有什么不同?
2.24 枚舉可移植嗎?
2.25 有什么顯示枚舉值符號的容易方法嗎?
位域
2.26 一些結構聲明中的這些冒號和數(shù)字是什么意思?
2.27 為什么人們那么喜歡用顯式的掩碼和位操作而不直接聲明位域?
第3章 表達式
求值順序
3.1 為什么這樣的代碼不行?a[i]= i++;
3.2 使用我的編譯器,下面的代碼int i= 7; printf("%d\n", i++ * i++); 打印出49。不管按什么順序計算,難道不該是56嗎?
3.3 對于代碼int i=3; i=i++; 不同編譯器給出不同的i值,有的為3,有的為4,哪個是正確的?
3.4 有這樣一個巧妙的表達式:a^= b^= a^= b; 它不需要臨時變量就可以交換a和b的值。
3.5 可否用顯式括號來強制執(zhí)行我所需要的計算順序并控制相關的副作用?就算括號不行,操作符優(yōu)先級是否能夠控制計算順序呢?
3.6 可是&&和||操作符呢?我看到過類似while((c = getchar()) != EOF && c != '\n')的代碼
3.7 是否可以安全地認為,一旦&&和||左邊的表達式已經決定了整個表達式的結果,則右邊的表達式不會被求值?
3.8 為什么表達式printf("%d %d", f1(), f2()); 先調用了f2?我覺得逗號表達式應該確保從左到右的求值順序。
3.9 怎樣才能理解復雜表達式并避免寫出未定義的表達式?“序列點”是什么?
3.10 在a[i] = i++;中,如果不關心a[]的哪一個分量會被寫入,這段代碼就沒有問題,i也的確會增加1,對嗎?
3.11 人們總是說i=i++的行為是未定義的??晌覄倓傇谝粋€ANSI編譯器上嘗試過,其結果正如我所期望的。
3.12 我不想學習那些復雜的規(guī)則,怎樣才能避免這些未定義的求值順序問題呢?
其他的表達式問題
3.13 ++i和i++有什么區(qū)別?
3.14 如果我不使用表達式的值,那我應該用i++還是++i來做自增呢?
3.15 我要檢查一個數(shù)是不是在另外兩個數(shù)之間,為什么if(a b c)不行?
3.16 為什么如下的代碼不對?int a=1000, b=1000; long int c=a * b;
3.17 為什么下面的代碼總是給出0?double degC, degF; degC= 5.0 / 9 * (degF - 32);
3.18 需要根據條件把一個復雜的表達式賦給兩個變量中的一個??梢杂孟旅孢@樣的代碼嗎?((condition) ? a : b)= complicated_expression;
3.19 我有些代碼包含這樣的表達式。a ? b=c : d 有些編譯器可以接受,有些卻不能。為什么?
保護規(guī)則
3.20 “semantics of‘’change in ANSI C”的警告是什么意思?
3.21 “無符號保護”和“值保護”規(guī)則的區(qū)別在哪里?
第4章 指針
基本的指針應用
4.1 指針到底有什么好處?
4.2 我想聲明一個指針并為它分配一些空間,但卻不行。這些代碼有什么問題呢?char *p; *p =malloc(10);
4.3 *p++自增p還是p所指向的變量?
指針操作
4.4 我用指針操作int數(shù)組的時候遇到了麻煩。
4.5 我有一個char *型指針碰巧指向一些int型變量,我想跳過它們。為什么((int *)p)++; 這樣的代碼不行?
4.6 為什么不能對void *指針進行算術操作?
4.7 我有些解析外部結構的代碼,但是它卻崩潰了,顯示出了“unaligned access”(未對齊的訪問)的信息。這是什么意思?
作為函數(shù)參數(shù)的指針
4.8 我有個函數(shù),它應該接受并初始化一個指針:void f(int *ip){ static int dummy = 5; ip = &dummy;}但是當我如下調用時:int *ip; f(ip); 調用者的指針沒有任何變化。
4.9 能否用void ** 通用指針作為參數(shù),使函數(shù)模擬按引用傳遞參數(shù)? 48
4.10 我有一個函數(shù)extern intf(int *); ,它接受指向int型的指針。我怎樣用引用方式傳入一個常數(shù)?調用f(&5);似乎不行。
4.11 C語言可以“按引用傳參”嗎?
其他指針問題
4.12 我看到了用指針調用函數(shù)的不同語法形式。到底怎么回事?
4.13 通用指針類型是什么?當我把函數(shù)指針賦向void *類型的時候,編譯通不過。
4.14 怎樣在整型和指針之間進行轉換?能否暫時把整數(shù)放入指針變量中,或者相反?
4.15 我怎樣把一個int變量轉換為char *型?我試了類型轉換,但是不行。
第5章 空指針
空指針和空指針常量
5.1 臭名昭著的空指針到底是什么?
5.2 怎樣在程序里獲得一個空指針?
5.3 用縮寫的指針比較“if(p)”檢查空指針是否有效?如果空指針的內部表達不是0會怎樣?
NULL 宏
5.4 NULL是什么,它是怎么定義的?
5.5 在使用非零位模式作為空指針的內部表示的機器上,NULL 是如何定義的?
5.6 如果NULL定義成#define NULL((char *)0) ,不就可以向函數(shù)傳入不加轉換的NULL 了嗎?
5.7 我的編譯器提供的頭文件中定義的NULL為0L。為什么?
5.8 NULL可以合法地用作函數(shù)指針嗎?
5.9 如果NULL和0作為空指針常量是等價的,那我到底該用哪一個呢?
5.10 但是如果NULL的值改變了,比如在使用非零內部空指針的機器上,用NULL(而不是0)
不是更好嗎?
5.11 我曾經使用過一個編譯器,不使用NULL就不能編譯。
5.12 我用預處理宏#define Nullptr(type)(type *)0幫助創(chuàng)建正確類型的空指針。
回顧
5.13 這有點奇怪:NULL可以確保是0,但空(null)指針卻不一定?
5.14 為什么有那么多關于空指針的疑惑?為什么這些問題如此頻繁地出現(xiàn)?
5.15 有沒有什么簡單點兒的辦法理解所有這些與空指針有關的東西呢?
5.16 考慮到有關空指針的所有這些困惑,要求它們的內部表示都必須為0不是更簡單嗎?
5.17 說真的,真有機器用非零空指針嗎,或者不同類型用不同的表示?
地址0上到底有什么?
5.18 運行時的整數(shù)值0轉換為指針以后一定是空指針嗎?
5.19 如何訪問位于機器地址0處的中斷向量?如果我將指針值設為0,編譯器可能會自動將它轉換為非零的空指針內部表示。
5.20 運行時的“null pointer assignment”錯誤是什么意思?應該怎樣捕捉它?
第6章 數(shù)組和指針
數(shù)組和指針的基本關系
6.1 我在一個源文件中定義了char a[6],在另一個源文件中聲明了extern char *a。為什么不行?
6.2 可是我聽說char a[]和char *a是等價的。是這樣的嗎?
6.3 那么,在C語言中“指針和數(shù)組等價”到底是什么意思?
6.4 既然它們這么不同,那為什么作為函數(shù)形參的數(shù)組和指針聲明可以互換呢?
數(shù)組不能被賦值
6.5 為什么不能這樣向數(shù)組賦值?extern char *getpass(); char str[10]; str=getpass("Enter password:");
6.6 既然不能向數(shù)組賦值,那這段代碼為什么可以呢?int f(char str[]){ if(str[0] == '\0') str="none";}
6.7 如果你不能給它賦值,那么數(shù)組如何能成為左值呢?
回顧
6.8 現(xiàn)實地講,數(shù)組和指針的區(qū)別是什么?
6.9 有人跟我講,數(shù)組不過是常指針。這樣講準確嗎?
6.10 我還是很困惑。到底指針是一種數(shù)組,還是數(shù)組是一種指針?
6.11 我看到一些“搞笑”的代碼,包含5["abcdef"]這樣的“表達式”。這為什么是合法的C語言表達式呢?
數(shù)組的指針
6.12 既然數(shù)組引用會退化為指針,如果array是數(shù)組,那么array和&array又有什么區(qū)別呢?
6.13 如何聲明一個數(shù)組的指針?
動態(tài)數(shù)組分配
6.14 如何在運行時設定數(shù)組的大小?怎樣才能避免固定大小的數(shù)組?
6.15 我如何聲明大小和傳入的數(shù)組一樣的局部數(shù)組?
6.16 如何動態(tài)分配多維數(shù)組?
6.17 有個很好的竅門,如果我這樣寫:int realarray[10]; int *array = &realarray[-1]; 我就可以把“array”當作下標從1 開始的數(shù)組。
函數(shù)和多維數(shù)組
6.18 當我向一個接受指針的指針的函數(shù)傳入二維數(shù)組的時候,編譯器報錯了。
6.19 我怎樣編寫接受編譯時寬度未知的二維數(shù)組的函數(shù)?
6.20 我怎樣在函數(shù)參數(shù)傳遞時混用靜態(tài)和動態(tài)多維數(shù)組?
數(shù)組的大小
6.21 當數(shù)組是函數(shù)的參數(shù)時,為什么sizeof不能正確報告數(shù)組的大小?
6.22 如何在一個文件中判斷聲明為extern的數(shù)組的大?。ɡ纾瑪?shù)組定義和大小在另一個文件中)?sizeof操作符似乎不行。
6.23 sizeof返回的大小是以字節(jié)計算的,怎樣才能判斷數(shù)組中有多少個元素呢?
第7章 內存分配
第8章 字符和字符串
第9章 布爾表達式和變量
第10章 C預處理器
第11章 ANSI/ISO標準C
第12章 標準輸入輸出庫
第13章 庫函數(shù)
第14章 浮點運算
第15章 可變參數(shù)列表
第16 章 奇怪的問題
第17章 風格
第18章 工具和資源
第19章 系統(tǒng)依賴
第20章 雜項
術語表
參考文獻