第一章
-
float 單精度浮點數(shù)
由下面三部分組成,占位32位| 符號位 | 指數(shù)位(8 bit) | 尾數(shù)位(23 bit) | | :-: | :-: | :-: |
符號位(1位)
1 : 表示負數(shù) 0 : 表示正數(shù)
指數(shù)位(8位) 使用EXCESS系統(tǒng)表現(xiàn),值域位[-127,128]
尾數(shù)位(24位)
先把小數(shù)轉成二進制小數(shù),比如11.1875的二進制小數(shù)為1011.0011
值域表示區(qū)間為正數(shù): [1.401298 * 10^-45, 3.402823 * 10^38] 負數(shù): [-3.402823 * 10^38, -1.401298 * 10^-45]
-
int 整型
同樣是32位,int的十進制精度是10位,表示的區(qū)間為有符號: [-2,147,483,648, 2,147,483,647] 無符號: [0, 4,294,967,295]
-
double 雙精度浮點數(shù)
跟float類似,位數(shù)不同| 符號位 | 指數(shù)位(11 bit) | 尾數(shù)位(52 bit) | | :-: | :-: | :-: |
值域表示區(qū)間為
正數(shù): [4.94065645841247 * 10^-324, 1.79769313486232 * 10^308] 負數(shù): [-1.79769313486232 * 10^308, -4.94065645841247 * 10^-324]
-
輸出右對齊,第一個數(shù)字至少占3格,第二個至少占6格
printf("%3d %6d\n", fahr, celsius); //output 0 -17 20 -6 40 4 60 15 80 26 100 37
浮點數(shù)和整形算數(shù)運算,整形會自動轉成浮點數(shù)
printf 參數(shù) %o八進制 %x十六進制 %c字符 %s字符串 %%百分號
-
define 定義常量不用分號
#define LOWER 0 #define UPPER 300 #defind STEP 20
聲明函數(shù)的時候返回值默認為int,不寫就是int
'\0' 空字符標記字符串結束,這一約定已被C語言采用
如果全局變量定義在函數(shù)之前哟玷,可以省略extern關鍵字辐宾;但如果全局變量定義在不同文件中豫喧,則需要使用extern關鍵字。
-
為了兼容老版本ANSI C,定義函數(shù)的時候如果沒有參數(shù)需要傳個void
int get_line(void);
第二章
- short int 最少16位, short int 永遠小于等于int, long int至少32位
- 'x' 和 "x" 是不同的, 'x'是一個整數(shù), "x" 是一個包含'x'以及一個'\0'的字符數(shù)組
- %取余操作不能應用于浮點數(shù)float double
- 參數(shù)通過函數(shù)原型聲明時,當函數(shù)被調(diào)用時,將對參數(shù)進行自動強制轉換
double sqrt(double); root = sqrt(2); //2會自動轉成double
- 位運算符只能應用于整型,char,short,int,long,有無符號都可以
- & 運算符通常用來屏蔽某些位
n = n & 0177 也就是 n = n & 01111111 結果除了最后7個位,其他都設置成0
- | 運算符通常用于將某些位設置為1
- ^ 運算發(fā)把兩個操作數(shù)對應位不相同時將該位設置為1,相同時設置為0
- x << 2 操作位左移兩位,空出來的位補0, 相當于乘以4
- ~ 運算符求反碼,1變0,0變1
x = x & ~077 相當于 x = x & ~(00111111) x = x & 11000000 //把x最后6位都變成0
- (x >> (p + 1 - n)) & (0 << n) 返回x中從右邊數(shù)第p位開始向右數(shù)n位的值
第三章
- switch case 的值只能是整數(shù)值或者是結果是整數(shù)的表達式,break和return都可以終止switch
- break,continue 只能控制退出最近一層的循環(huán)
- goto可以跳出多層循環(huán),能不用就不用
第四章
外部變量和函數(shù)的作用域從聲明處開始硅确,直到所在文件的末尾。如果需要在變量定義之前使用該變量潜的,或者變量的定義與使用不在同一個源文件中狰域,就需要使用extern關鍵字來強制聲明邦蜜。
-
外部變量的定義中必須指定數(shù)組長度,但extern聲明則不一定要指定數(shù)組的長度
double val[MAXVAL]; //定義 extern double val[]; // 引用
static 靜態(tài)變量
使用"static"關鍵字可以將變量或函數(shù)的作用域限制在聲明它們的文件內(nèi)依鸥,其他文件無法直接訪問。對于全局變量悼沈,這使得它們具有靜態(tài)屬性贱迟。在函數(shù)內(nèi)部聲明的靜態(tài)變量在函數(shù)調(diào)用結束后仍然保持其值姐扮,并且在下一次調(diào)用時繼續(xù)使用。使用"static"關鍵字修飾函數(shù)時衣吠,函數(shù)的鏈接屬性為內(nèi)部鏈接茶敏,只能在定義它的文件中訪問。register 寄存器變量
register告訴編譯器把變量放在寄存器中,只適用于自動變量以及函數(shù)的形參,現(xiàn)代編譯器一般都忽略這個特性外部變量和靜態(tài)變量初始化為空值,自動變量和寄存器變量的初值則沒有定義
對于外部變量與靜態(tài)變量來說,初始化表達式必須是常量表達式,且在程序開始執(zhí)行前初始化一次,對于自動變量和寄存器變量,則在每次進入函數(shù)或程序塊時才會初始化
-
宏替換
#define forever for (;;) forever { //直接替換成 for(;;) } // 最好不要這樣用 比如 max(i++,j++) 這里i++ 會執(zhí)行兩次 #define max(A, B) ((A) > (B) ? (A) : (B)) int main () { printf("%d", max(1, 3)); //輸出3 }
undef forever 取消宏定義
#ifdef
#ifndef
在預處理階段判斷常量是否定義
第五章
指針只能應用于變量或者數(shù)組,不能應用于表達式,常數(shù),寄存器變量
void類型的指針可以指向任何類型,但不能指向自身
指針,取指&的優(yōu)先級別比算數(shù)運算符+-/高
++優(yōu)先級大于指針,所以(ip)++是必須的
數(shù)組變量的指針和第0個元素的指針相同
如果pa是一個數(shù)組指針,pa[i]與*(pa+i)
當把數(shù)組傳遞給一個函數(shù)時,實際上傳遞的時該數(shù)組的第0個元素的地址,也就是該數(shù)組的指針
在形參中,字符串常量,數(shù)組,字符指針傳遞給函數(shù)的時候都是字符指針, char s[] 和 char *s是等價的
形參傳遞部分數(shù)組 f(&a[2]) 或者 f(a+2)
p是數(shù)組,p[-1]在語法上是合法的,在訪問邊界上是非法的
指針和整形之間不能相互轉換,0例外
NULL 常量定義在<stddef.h>中,空指針經(jīng)常用NULL代替0
p,q 指向同一個數(shù)組時,pq之間可以進行==, !=, <, <=, >, >=等操作,pq指向不同數(shù)組時,沒法做運算,有個特例,指針運算中,p可以使用數(shù)組最后一個元素的下一個元素的地址
如果p指針指向整型,因為整形占4個字節(jié),所以p+n相當于p + 4 * n,對應的n將按4倍來算
以下指針運算合法:相同類型指針的賦值運算,指針和整數(shù)的加減法運算,指向相同數(shù)組中元素的兩個指針的減法或比較運算,指針賦值為0或者和0比較,除此之外其他都是非法的
-
如果將二維數(shù)組作為參數(shù)傳遞給函數(shù),那么在函數(shù)的聲明中,必須指明數(shù)組的列數(shù),行數(shù)倒沒什么關系
//函數(shù)帶二位數(shù)組參數(shù)的聲明,三種方式都可以 f(int daytab[2][13]); f(int daytab[][13]); f(int (*daytab)[13]);
-
二維數(shù)組和指針數(shù)組
int a[10][20]; //分配了200個int類型的存儲空間 int *b[10]; //分配了10個指針的存儲空間,指針指向的數(shù)組的長度可 以不同,字符串數(shù)組首選指針數(shù)組,節(jié)省內(nèi)存
main函數(shù)可以接收命令行參數(shù),第一個參數(shù)argc(argument count)表示參數(shù)數(shù)量,第二個參數(shù)argv(argument vector)表示字符串數(shù)組,數(shù)組第一個元素argv[0]是啟動該程序的程序名,另外 argv[argc]的值是空指針0
-
函數(shù)指針
int (*comp)(void *, void *) //表明comp是一個指向函數(shù)的指針 if ((*comp)(1,2) < 0) {} //調(diào)用
-
復雜聲明
1.[] 優(yōu)先級大于 *
2.() 優(yōu)先級大于 *char **argv //argv是字符指針的指針 int (*daytab)[13] //daytab是指向某個13位整形數(shù)組的指針 int *daytab[13] /daytab/整形數(shù)組第14個元素的指針 void *comp() //comp是一個返回void(*)指針的函數(shù)名 void (*comp)() //comp是函數(shù)指針,返回void char (*(*x())[])() //x是一個函數(shù),它返回一個指針,該指針指向一個一維數(shù)組,該一維數(shù)組的元素為指針,這些指針分別指向多個函數(shù),這些函數(shù)的返回值為char類型 char (*(*x[3])())[5] // // x是一個三個元素的數(shù)組,數(shù)組元素是函數(shù)指針,函數(shù)返回指向5個char元素的數(shù)組指針
第六章
- 如果結構體聲明的后面不帶變量,則不需要為它分配存儲空間,因為沒有實例化(面向對象的說法)
- 結構體的合法操作只有幾種:整體復制和賦值,&取址,訪問其成員,結構體之間不可以進行比較,
- 結構體類型的參數(shù)和其他類型的參數(shù)一樣,都是通過值傳遞的,如果傳遞的結構體很大,建議傳指針
-.
的優(yōu)先級高于*
, 所以 (*pp).x 的 ()是必須的,不過也可以簡寫為pp->x,只有pp是指針時才能用-> - sizeof 函數(shù) 返回的是無符號整型,其類型為 size_t , 在stddef.h定義
- 編譯時獲得數(shù)組個數(shù)
struct key{ char *word; int count; } keytab[NKEYS]; #define NKEYS (sizeof keytab / sizeof keytab[0])
-
#if
中不能使用sizeof,因為預處理器不對類型名進行分析,但預處理器并不計算#define語句中的表達式,留到編譯的時候,因此,#define中使用sizeof是合法的 - 兩個指針的加法運算時非法的,但是劍法運算卻是合法的,在C語言理,數(shù)組末尾之后的第一個元素(&arr[len])是可以訪問的,也就是說針對這個元素的指針運算是可以正確執(zhí)行的
- 一個包含自身實例的結構是非法的,但是指向結構之身是合法的,比如二叉搜索樹
- 哈希表相當于一個數(shù)組,數(shù)組元素是實現(xiàn)了鏈表功能的結構體,這種應該是開放鏈表法
- typedef char *String 定義一個字符串類型String
- typedef類似于#define,但由于typedef是由編譯器解釋的,define是由預處理器解釋的,編譯器的文本替換能力要超過預處理器
- union只能用第一個成員的值進行初始化
- 屏蔽碼必須是2的冪,方便使用位運算
struct tnode { char *word; int count; struct tnode *left; struct tnode *right; }
第七章
- 輸入重定向符
prog < infile // < infile 都不包含在命令行參數(shù)argv中 prog > file // prog 的標準輸出重定向到文件中 prog | anotherprog //prog 的標準輸出重定向到 anotherprog 的標準輸入
- printf和putchar一樣也向標準輸出設備上輸出數(shù)據(jù)
- include <stdio.h>在unix中回去 /usr/include中查找
- 打印字符
printf("%.3s", s); //打印s字符串前面3個字符 printf("%.*s", max, s); //打印s字符串前面max個字符,max必須為int printf(s); //打印字符串,如果s中包含%,則會報錯
- sprintf執(zhí)行的轉換和printf相同,但它將輸出保存到一個字符串中
- FILE 是由typedef定義的類型,而不是一個結構
- 輸出文件通常使用緩沖區(qū)來提高寫入效率缚俏。當您使用putc函數(shù)或其他輸出函數(shù)寫入數(shù)據(jù)時惊搏,數(shù)據(jù)實際上是先存儲在內(nèi)存中的緩沖區(qū)中。當緩沖區(qū)滿了忧换、手動刷新緩沖區(qū)或關閉文件時恬惯,緩沖區(qū)的內(nèi)容才會被寫入到文件中。而fclose函數(shù)在關閉文件時會自動刷新緩沖區(qū)亚茬,將緩沖區(qū)中的內(nèi)容寫入到文件中宿崭。
- 標準輸入輸出stdin stdout可以通過fclose關閉,守護進程會用到這個
- exit(0) 表示正常 -exit(其他)表示不正常,exit參數(shù)可以被父進程獲取,exit為每個已打開的輸出文件調(diào)用fclose函數(shù),以將緩沖區(qū)中的所有輸出寫到相應的文件中才写。
- 在main函數(shù)里面, return 0; 相當于 exit(0);
- feof(FILE) 和 ferror(FILE) 類似
- gets()在讀取一行字符串時將刪除結尾的換行符,puts()在寫入字符串時將在結尾添加一個換行符
- 使用free()釋放一個不是由malloc/calloc得到的指針將是一個嚴重的錯誤
第八章
- unix操作系統(tǒng)中,所有外圍設備都被看作是文件系統(tǒng)中的文件
- 系統(tǒng)調(diào)用read/write一次可以轉換任意個字符,一次轉換多個字符減少系統(tǒng)調(diào)用更加有效率,比如1024/4096相當于一個物理塊大小的字節(jié)
- 系統(tǒng)調(diào)用open 類似于fopen ,但是 open返回文件描述符,fopen返回文件指針
- 系統(tǒng)調(diào)用creat創(chuàng)建新文件,如果文件已存在,則清空文件內(nèi)容,返回文件描述符
- unix文件系統(tǒng)中,每個文件對應一個9bit的權限信息,使用3位八進制表示如0755
- 系統(tǒng)調(diào)用lseek(int fd, long offset, int origin); origin的值0表示從文件開始,1表示從當前位置,2表示從文件末尾,offset表示偏移量
- FILE指針指向struct,內(nèi)容包括:
typedef struct _iobuf { int cnt; //記錄緩沖區(qū)中剩余的字符數(shù)的計數(shù)器 char *ptr; //下一個字符的指針 char *base; //緩沖區(qū)的位置指針 int flag; //文件訪問模式 :讀,寫,不對文件緩沖,已到文件的末尾,該文件發(fā)生錯誤 int fd; //文件描述符 整型 }
- fopen 不自帶緩沖區(qū)
- MS-DOC系統(tǒng)獲取文件名需要系統(tǒng)調(diào)用,unix不用
- 目錄就是文件,包含了一個文件名列表和inode編號
- stat 通過指定路徑遞歸獲取文件和文件夾信息
- fstat 通過文件描述符獲取文件信息
- malloc在編譯時沒有確定存儲空間,在執(zhí)行的時候才向操作系統(tǒng)申請
- malloc管理的空間不一定是連續(xù)的,而是通過鏈表連接在一起
- malloc函數(shù)返回的存儲空間滿足將要保存的對象和最受限的類型的內(nèi)存對齊要求,機器類型不同,最受限類型可能是double,long,int
- 內(nèi)存對齊是由union實現(xiàn)的
typedef long Align; union header { struct { union header *ptr; //空閑鏈表中下一個指針 unsigned size; // block大小 } s; Align x; //最受限類型 long, x永遠都不會用到,僅僅用于強制每個頭部在最壞的情況下滿足對齊要求 }
-
空閑block是一個鏈表,每個block都包括一個空閑空間本身的指針(3)以及header,header里面有一個指向下一個block的指針(1),和block的大小(2)
- unix系統(tǒng)調(diào)用sbrk(n),返回一個指向n字節(jié)儲存空間的指針
- malloc里面有個morecore會調(diào)用sbrk申請更多的空間,減少系統(tǒng)調(diào)用次數(shù),優(yōu)化性能
附錄
- 預定義名字
__LINE__包含當前源文件行數(shù)的十進制常量。
__FILE__包含正在被編譯的源文件名字的字符串字面值奖蔓。
__DATE__包含編譯日期的字符串字面值赞草,其形式為“Mmm dd yyyy”。
__TIME__包含編譯時間的字符串字面值吆鹤,其形式為“hh:mm;ss
__STDC__整型常量1厨疙。只有在遵循標準的實現(xiàn)中該標識符才被定義為1。
- 頭文件的包含順序是任意的,并可以包含任意多次