鏈接屬性
1.extern 關鍵字用於標識符第二次或以後的聲明並不會改變第一次聲明所指定的屬性。
2.static 防止被訪問 (和java完全不同)
存儲類型
1.變量存儲地方:普通內存,堆棧,硬件寄存器
2.代碼塊外聲明的是靜態變量,存於靜態內存(普通內存),程序運行前存在,始終存在
3.自動變量
4.代碼塊內變量 + static --> 靜態變量
運算符
1. i+++ ++i 這種5個加號的存在,gcc中間有空格可以通過,甚至可以是6個,i+++ + ++i,一個表示正數
指針
1.定義:
#define NULL (void*) 0
#define EOF -1
2. int *a; *a=1;
unix:段違例 segmentation violation ,內存錯誤:memory fault,總線錯誤:bus error
3.對NULL指針間接訪問,有的編譯器訪問內存0,有的引發一個錯誤並終止程序
4.盡量顯示初始化指針
5.指針與整型值的相互轉換罕見
6.*100=25 不是對100內存地址的地方賦值25,是非法的,100是整型, *(int *)100=25;
訪問硬件本身,很少用
7. * 從右向左的結合性
8.後綴 ++ -- 順序點 ()不是順序點!
; , || && ?: 還有函數的所有的賦值之後,第一條語句執行之前。
函數返回值已拷貝給調用者但在該函數外代碼執行之前
每個基類和成員初始化之後
9. *cp++ *++cp ++*cp (*cp)++ ++*++cp ++*cp++ *(*cp)++ 後綴++優先級大於* *不是++順序點
10.for(cp=&arr[0];cp<&arr[LEN];) *cp++;
for(cp=&arr[LEN];cp>&arr[0];) *--cp;
for(cp=&arr[LEN-1];cp>=&arr[0];cp--) *cp;//都是作為左值操作
第三句cp到達&arr[0]之後還減1,再進行比較 cp>=&arr[0]值是未定義的,因為cp移動到了數組邊界之外
標准允許數組元素的指針與指向數組最後一個元素後面的那個內存進行比較,但不允許與數組第一個元素之前!
11.指針的加減法會根據類型自動調整
函數
1.函數原型:向編譯器提供一些關於函數的特定信息,更為安全
2.函數原型參數不是必須
3.沒有參數的原型 int *func(void); void提示沒有參數,而不是表示一個void類型的參數
4.函數的缺省認定:程序調用一個無法見到原型的函數是,編譯器認為該函數返回整型值
5.stdarg 宏
定義在stdarg.h中,這個文件聲明了一個類型 va_list和三個宏 va_start va_arg va_end
float average(int values,...){
va_list args;
int sum=0;
va_start(args,values);//准備訪問可變參數
for(int count=0;count
數組
1.數組名是指針常量,而不是指針變量,編譯器用數組名來記住數組屬性
2.程序在完成鏈接之後,內存中的數組的位置是固定的,不能移動,所以數組名是指針常量
3.兩種情況下數組名並不用指針常量來表示:
1)作為sizeof的操作數:返回整個數組長度
2)作為單目操作符&的操作數:取一個數組名的地址返回指向數組的指針,
而不是指向一個指針常量的指針!!
4.array[subscript]等同於*(array+(subscript)) subscript甚至可以為負
2[array]=*(2+array)=array[2] 對編譯器來說無差別
5.下標絕不會比指針更有效率,但指針有時比下標更有效率
int array[10] a; for(a=0;a<10;a++) array[a]=0;//每次都會有a*4
int array[10] *ap; for(ap=array;ap
字符串,字符和字節
1.包含string.h,它裡面所包含的原型可以是編譯器更好的執行錯誤檢測
2.自己編寫字符串函數,保留以str開頭的函數名,用於標准庫的擴展
3. size_t strlen(char const *string)
size_t 在stddef.h中定義,是一個unsigned int
程序保護不會溢出
4.在表達式中無符號數可能導致不可預料的結果
if(strlen(x) >= strlen(y))....
if(strlen(x) - strlen(y) >= 0)....
看似相等,事實上第二局永遠是真,無符號數不可能為負
5.標准庫函數有的是用匯編實現的
6.char *strcpy(char *dst,char const *src);
src和dst出現重疊,結果是未定義的
如果src比dst長,多余的字符仍將復制!必須程序控制
7.char *strcat(char *dst,char const *src);
src和dst出現重疊,結果是未定義的
和strcpy一樣,必須保證剩余的空間大於src
8.int strcmp(char const *s1,char const *s2);
s1小於s2,返回小於0的數,大於返回大於0的數,等於返回0
不等 if( strcmp(a,b) )
9.char *strncpy(char *dst,char const *src,size_t len);
char *strncat(char *dst,char const *src,size_t len);
char *strncmp(char const *dst,char const *src,size_t len);
strncpy 總是復制的長度為len,如果strlen(src)小於len,dst用額外的NUL字節填充到len長度
如果大於len,只有len長度被復制,但是!他的結果不會以NUL結尾!
strncat 與 strncpy 不同,它總是在結果字符串後面加NUL,不會進行NUL填充,
最多復制len長度外加一個NUL,不管空間夠不夠
10.char *strchr(char const *str,int ch);
char *strrchr(char const *str,int ch);
strchr查找ch第一次出現的位置,返回指向其的指針,strrchr返回最後一個
11.char *strpbrk(char const *str,char const *group);
返回一個指向str中第一個匹配group中任何一個字符的字符位置
12.char *strstr(char const *s1,char const *s2);
13.size_t strspn(char const *str,char const *group);//不再group內
size_t strcspn(char const *str,char const *group);
14.char *strtok(char *str,char const *seq);
找到下一個由seq組成的字符合集分割str的標記,並將其用NUL結尾,返回指向這個標記的指針
沒有const修飾str,會被修改,會被重復調用,知道返回NUL
static char whitespace[]=" \t\f\r\v\n";//有個空格 char *token;
for(token=strtok(line,whitespace);token!=null;token=strtok(NULL,whitespace))
可以在每次調用strtok時使用不同的seq,字符串的不同部分用不同的分割
strtok保存了函數的局部狀態信息,不能同時解析多個字符串,
在for循環體內調用內部調用,strtok的函數將導致程序失敗
15.char *strerror(int error_number)
調用函數或者請求操作系統功能如打開文件出錯時,操作系統通過設置並返回一個外部整型
變量errno進行錯誤代碼報告,此函數接受error並返回描述
16.字符分類:ctype.h 接受一個字符的ASCII碼,函數測試這個字符,並返回整形值表示真假
iscntrl isspace isdigit isxdigit islower isupper isalpha isalnum前三個合集
ispunct標點符號 isgraph圖形字符 isprint圖形字符和空格
17.字符轉換:ctype.h int tolower(int ch) int toupper(int ch)
18.直接測試或測試會降低可移植性 if(ch>='A'||ch<='Z')在ASCII字符集機器上可以
但使用EBCDIC字符集的機器不可以,if(isupper(ch)) 都可以!
19.內存操作:以長度作為操作終止標志,解決字符串\0結尾問題。void指針,其他數據類型也可使用
void *memcpy(void *dst,void const *src,size_t length)
void *memmove(void *dst,void const *src,size_t length)
相比於memcpy,dst和src可以重疊,它利用了一個臨時空間復制,速度慢
void *memcmp(void const *a,void const *b,size_t length)
根據無符號字節進行比較,如果比較的不是單字節數據,結果不可測
void *memchr(void *a,int ch,size_t length)
void *memset(void *a,int ch,size_t length)從a開始設置length個ch
length是操作的字節數,不是一字節的數據類型要數量乘長度,例如int 結構體
結構體
1.struct{....}x;struct{....}*y;這兩個聲明被編譯器當成不同的聲明,y=&x也是非法的,即使成員列表相同
2.想在多個源文件中使用定義的結構體,放在頭文件中
3.間接訪問運算符*的優先級小於成員訪問 . ->大於&
4.可以包含自身的引用,但不能在沒定義別名前用別名。不能包含自身,因為遞歸不能終止
5.相互引用用不完整聲明
6.如果不存在將相關成員放在一起的要求,應該根據邊界進行重排結構體的成員存儲結構
7.sizeof返回結構體的整體長度,offsetof宏(stddef.h)返回指定成員開始存儲的位置距離結構體開始
存儲的位置偏移幾個字節,返回size_t,offset(type,member)type是結構名,member是成員名
8.位段:
只能聲明為int,signed int,unsigned int(用作表達式時自動升級的類型),
用int並不好,它究竟是解釋為有符號還是無符號由編譯器決定
段中的最大位數限制在一個整型之內,成員的內存分配從左到右還是從右到左未知
後面的位段不能夠容納與前面一個位段剩余空間時,可能直接接在前面的位段後面(內
存位置邊界上形成重疊),也可能放在內存的下一個字。
9.位段實現的功能都可以用移位和屏蔽來實現,在目標代碼中,移位和屏蔽是必需的,
位段唯一好處源代碼簡潔,但是可移植性較弱
聯合體
1.初始化必須是第一個元素,必須位於一對花括號內,如果類型不符,會轉換(如果可能)並賦給第一個
動態內存分配
1.void *calloc(size_t num_elements,size_t element);void *malloc(size_t size);
void *realloc(void *ptr,size_t new_size);void free(void *pointer);
calloc 會初始化為0。free,realloc傳遞NULL作為參數無作用。分配不成功返回NULL
定義在stdlib.h。NULL定義在stdio.h
高級指針
1.指向指針的指針
2.理解聲明方法 1)推論聲明 2)用於聲明變量的表達式和普通的表達式在求值時使用相同的規則
int *f() int (*f)() int *(*f)() int *f[] int(*f[])() int *(*f[])()
int f()[] f是一個函數,它的返回值是一個整形數組。它是非法的,函數不能返回數組
int f[]() f是一個數組,它的元素類型是返回整型的函數。非法的,數組元素長度相同,不可能是函數
unix系統cdecl程序可以轉換聲明和英語
3.函數指針
初始化:int f(int ); int (*pf)(int) = &f;
調用函數: f(12) (*pf)(12) 或者 pf(12)
f(12)簡單調用函數。過程:函數名f首先被轉換成一個函數指針,該指針指向函數在內存中的位置。
然後,函數調用操作符調用該函數,執行開始與這個地址的代碼。所以,(*pf)(12)函數指針轉換
成函數編譯器又將其轉換回去,pf(12)才是正道
4.回調函數,java中策略模式,接口實現,例如Comparator,但java中可以用實現接口和泛型解決
類型的問題,C中只能是 void*,靈活但不安全。
在寫用於函數指針調用的函數時一般參數為void*,注意強制轉換。
強制類型轉換會躲過一般的類型檢測,必須格外注意類型的問題。
函數指針調用庫函數,例如strcmp,編譯器一般有警告,因為參數是void*,而不是char*
5.轉換表。匯編中TAB也經常這樣用
6.字符串是指針常量,字符串出現在表達式中的時候就是指針常量
轉換二進制為字符 "0123456789ABCDEF"[value % 16]; *"xyz" 就是 x
預處理
1.文本性質的操作
2.預處理符號 _FILE_ _LINE_ _DATE_ _TIME_ _STDC_
3.#define 可以多行,除了最後一行,其他行行尾要加反斜槓。
4.宏定義中如果調用函數不要再末尾加上分號。有些語句還好,但例如if中,兩個分號的出現會出問題
5.#define name(parameter-list) stuff。參數列表左括號和name必須緊鄰,否則變成stuff
6.對數值進行求值得宏定義各個參數都要加上括號,最外層還要括號
7.宏參數和#define定義可以包含其他#define定義的符號,宏不可以出現遞歸
8.預處理對字符串常量內容並不進行進檢測。把宏參數插入字符串常量中兩種方法
1)鄰近字符串自動連接特性
#define PRINT(FORMAT,VALUE) printf("result:" FORMAT "\n",VALUE) PRINT("%d",1+1);
2.使用預處理器把宏參數轉換成字符串 #argument會被翻譯成 "argument"
#define PRINT(FORMAT,VALUE) printf(#VALUE "is" FORMAT "\n",VALUE) PRINT("%d",1+1);
9.## 把位於它兩邊的符號連接成一個符號
#define ADD_T0_SUM(sum_num,value) sum ## sum_num +=value
ADD_T0_SUM(5,25) sum5變量加上25
10.宏與函數:
定義簡單的工作 #define MAX(a,b) ((a)>(b)?(a):(b))
考慮函數調用的消耗,與宏類似內聯函數占用的空間
函數有數據類型的限制,例如上面的。
一些任務函數無法實現,例如當參數是一種數據類型。
11.宏參數的副作用,宏參數在宏定義中出現超過一次時,宏參數副作用可能出現危險。
common lisp 宏也有這個問題,但它的宏實在強大,可以很輕松解決
z=MAX(x++,y++) z=((x++) > (y++) ? (x++) : (y++))
小的值增加了一次,大的增加了兩次。
不僅限於改變變量的值,例如getchar()也有副作用。
12.條件編譯 #if constant-expression 不想出現在產品中,調試,維護卻需要
statement
#elif ...... #else .... #endif ....
constant-expresion(常量表達式) 由預處理器進行求職,非0就statement。例如ASSIGN宏
#if defined(symbol) 等同於 ifdef symbol , if !defined(symbol) 等同於 ifndef symbol
#if 功能更強大 #if x>0 || defined(ABC) && defined(BCD)
可以嵌套,
13.編譯器定義一系列標准位置查找函數庫頭文件,/user/include,可以添加
14.標准要求頭文件嵌套至少支持8層,但沒有理由讓嵌套超過兩層,很難判斷源文件之間真正依賴關系
unix的make實用工具必須知道這些依賴關系決定文件修改後哪些要重新編譯。
15.#error #line #progma # 無效指令
輸入輸出函數
1.ANSI編譯器允許在函數庫基礎上增加函數,但如果關心可移植性,應該避免
2.void perror(char const *message); stdio.h ;會在message後面加個冒號和錯誤內容
3.標准庫函數在一個外部整型變量errno(errno.h中定義)中保存錯誤代碼後把這個信息傳遞給用戶程序
4.只有當一個庫函數失敗時errno才會被設置,所以我們不能通過測試errno值來判斷是否有錯誤發生
5.void exit(int status);stdlib.h; status值返回個操作系統,用於提示程序是否正常,這
個值和main返回的整型狀態相同。經常在perror後調用,實在出錯的不能忍了。無處可返回
6.絕大多數流失完全緩沖的,意味著讀取和寫入實際上是從一塊緩沖區內存區域來復制數據
7.printf分布於程序中用於調試。但這些函數的輸出結果被寫入緩沖區,並不會立刻顯示。
如果程序失敗,緩沖輸出可能不會被實際寫入,會得到錯誤出現的位置不正確的結論
解決辦法:printf("something");fflush( stdout ) ;立即 fflush
8.對於那些文本行的外在表現形式與換行符表示文本結束的標准不同的系統上,庫函數負責翻譯
9.stdio.h聲明了FILE結構,用於訪問一個流。每個流對應一個FILE。
10.每個程序運行,系統至少提供三個流,stdin,stdout,stderr,都是指向FILE結構的指針
11.標准輸入輸出和錯誤是缺省的位置,因編譯器而異,通常鍵盤和終端
可以重定向 $ program < data > answer DOS和UNIX都支持
12.FILE *fopen( char const *name , char const *mode ); FILE *變量的名字用於保存fopen的返回值,它並不影
響哪個文件被打開。name為字符串,避免在各系統中的差異。文本:r w a 二進制:rb wb ab 更新:a+,可讀寫
失敗返回NULL指針,errno會提示問題的性質,應該始終檢查返回值
13.FILE *freopen(char const *filename,char const *mode,FILE *stream);
打開或重新打開stream,首先試圖關閉stream,然後用指定的filename和mode重新打開這個流,失敗返回NULL
14.int flose(FILE *f);成功返回0,否則返回EOF
15.fopen和fclose直接的程序可能導致FILE*的改變,造成fclose失敗
16.int fgetc(FILE *stream); int getc(FILE *stream); int getchar(void);
讀取一個字符,沒有返回EOF。返回值是int而不是char,是因為EOF
17.int fputc(int character,FILE *stream);int putc(int character,FILE *stream);int putchar(int character);
第一個參數是要被打印的字符,在打印前,函數把這個整型參數裁剪為一個無符號字符值
putchar('abc');只打印一個字符,至於是哪一個由編譯器決定。寫入到已關閉流或其他失敗,返回EOF
18.fgetc和fputc是函數,getc,putc,getchar,putchar,是宏
19.int ungetc(int character,FILE *stream);把character返回到流中
20.char *fgets(char *buffer,int buffer_size,FILE *stream);
緩沖區到達buffer_size-1或者讀到換行符,停止讀取。下一次調用從流下一個字符開始,無論如何末尾都是NIL
如果在任何字符讀取前就到達了文件尾,緩沖區沒改變,fgets返回NULL,否則返回指向緩沖區的指針
21.int fputs(char const *buffer,FILE *stream);buffer必須包含一個字符串,但它不像fgets最多只能讀取一行。
寫入錯誤時,返回EOF,否則返回非負值
22.char *gets(char *buffer);int puts(char const *buffer);和fgets,fputs類似,保留它們是為了向後兼容
不同在於gets讀取一行時,並不在行尾保留換行符,puts寫入時會再添加一個換行符。
而且,gets沒有緩沖長度參數,多出來的字符會被寫入緩沖區後面的內存!!
23.int fscanf(FILE *stream,char const *format,...);
int scanf(char const *format,...);int sscanf(char const *string,char const *format,...);
省略號代表一個可變長度的指針列表,從輸入轉換而來的值逐個存儲到這些指針指向的內存。
會跳過空白字符。當格式化字符串到達末尾或者讀取的輸入不再匹配格式字符串所指定的類型時,
輸入就停止,輸入值的數目被作為返回值,沒有任何輸入就到結尾返回EOF。
格式代碼format都是以%開頭,後面可以是一個可選星號(丟棄不存儲這個字符),一個可選的寬度(非負整數,
限制被讀取用於轉換的長度,在類型長度長於或短於缺省長度時,不指定寬度將出錯,總是指定更具移植性),
一個可選限定符(h,l,L),和一個格式代碼
24. h l L
d,i,n short long
o,u,x unsigned short unsigned long
e,f,g double long double
25.格式碼:
c(char *) 讀取單個字符,如果給出寬度,就讀取寬度個,末尾不會加NUL,
i,d(int *) 有符號,i根據第一個字符決定基數,
u,o,x(unsigned *) u十進制,o八進制,x十六進制
e,f,g(float *)
s(char *) 一串非空字符,發現空白停止,自動加NUL
[xxx](char *) 一圈字符,發現第一個不在給定組合內的字符停止,自動加NUL,列表頭可加^,表示不在組合內,
是否支持橫槓表示范圍內字符因編譯器而異,例如 %[a-z]
p(void *) 輸入預期為一串字符,轉換方式因編譯器而異,但轉換結果用p打印產生的字符和輸入是相同的
n(int *) 到目前為止通過scanf從輸入讀取的字符數被返回。%n轉換的字符並不計算在scanf返回值之內。
它本身不消耗輸入
% 與輸入中的%相匹配,該%被丟棄
26.int fprintf(FILE *stream,char const *format,...);
int printf(char const *format,...); int sprintf(char *buffer,char const *format,...);
27.size_t fread(void *buffer,size_t size,size_t count,FILE *stream);
size_t fwrite(void *buffer,size_t size,size_t count,FILE *stream);
size是緩沖區每個元素的字節數,count是讀取或寫入的元素數,buffer的空間要有size*count這麼大
返回子是實際吸入或讀取的元素(不是字節)數目。可以實現java中對象流的操作
28.int fflush(FILE *stream);迫使一個輸出流的緩沖區的數據進行物理寫入。
29.一般情況數據室線性寫入,
long ftell(FILE *stream);返回流的當前位置,在二進制流中,這個值就是當前位置距離文件起始位置的
字節數偏移量,在文本流中,並不一點准確地代表字符數偏移量,因為有些系統將對行末字符進行翻譯
但ftell的返回值總可以用於fseek函數中。
int fseek(FILE *stream,long offset,int from);定位一個流,改變下一次操作的位置。
from:SEEK_END,從尾部起offset個字節,可正可負。SEEK_CUR,offset可正可負。SEEK_SET,起始位置,offset非負
30.試圖定位到文件起始位置之前是錯誤,定位到文件尾之後並進行寫入會擴展這個文件,試圖訪問會導致返回
一條“到達文件尾”的信息。二進制流可能不支持SEEK_END,文本流中SEEK_CUR,SEEK_END,offset必須是0,
如果from是SEEK_SET,offset必須是ftell的返回值
31.fseek副作用:行末指示字符被清除。如果fseek之前ungetc,那麼被退回的字符會被丟棄,因為定位操作後,它不
再是下一個字符。定位允許從寫入模式切換到讀取模式,或者回到打開的流以便更新
32.void rewind(FILE *stream);定位到流的起始位置,同時清楚流的錯誤標識
int fgetpos(FILE *stream,fpos_t *position);int fsetpos(FILE *stream,fpos_t const *position);
ftell與fseek的替代方法,fgetpos存儲當前位置到fpos_t,fsetpos設置文件到fpos_t
fpos_t表示文件位置不是標准定義的,可能是偏移量也可能不是,
33.void setbuf(FILE *stream,char *buf);int setvbuf(FILE *stream,char *buf,int mod,size_t size);
必須在流打開但並沒有執行任何其他操作前執行,setbuf設置一個數組對流進行緩沖,長度為BUFSIZ,
在stdio.h中的定義。為流自行制定緩沖區可以防止I/O函數庫為它動態分配緩沖。buf為NULL則關閉緩沖。
為流使用自動數組緩沖可能導致流還沒關閉,但數組已經出了代碼快,內存被別的函數使用,流也繼續使用
setvbuf:mode用於指定緩沖的類型,_IOFBF指定一個完全緩沖的流,_IONBF指定一個不緩沖的流,_IOLBUF指定一個
行緩沖流,就是每當一個換行符寫入緩沖區,緩沖區進行刷新。buf為NULL,size必須為0,一般為BUFSIZ
34.流錯誤函數;int feof(FILE *stream);流處於文件尾返回真。int ferror(FILE *stream);報告流的錯誤狀態,
如果出現任何讀寫錯誤就返回真。void clearerr(FILE *stream);對流的錯誤標志進行重置
35.臨時文件: FILE *tmpfile(void);以wb+模式打開,這使它可用於二進制和文本數據。如果文件必須由其他模式打開
或者由另一個程序打開,必須用fopen,而且不再需要時必須使用remove刪除。
char *tmpnam(char *name);創建臨時文件的名字。參數為NULL,返回一個指向靜態數組的指針,該數組包含
文件名,否則指定一個長度至少為L_temnam的數組,文件名在返回的指針代表的數組中。會保證不重名,TMP_MAX
36.int remove(char const *filename);int rename(char const *oldname,char const *newname);
成功返回0,否則返回非0。remove文件已經打開,結果取決編譯器。rename存在newname,結果編譯器,oldname仍可用
標准庫函數
1.stdlib.h int abs(int value); long int labs(long int value);長整形的abs
div_t div(int numerator,int denominator);第二個參數是分母,第一個是分子。產生商和余數,
div_t的結構 int quot;//商,int rem;//余數
ldiv_t ldiv(long int number,long int denom);
2.stdlib.h 下面函數產生的是偽隨機數 int rand(void);0-32767 為了避免每次調用rand獲得相同的隨機列表,用
void srand(unsigned int seed);常用每天的時間做種子 srand( (unsigmaned int ) time(0));
3.math.h double sin(double angle);....cos....tan.....double asin(double value);..atan....
double atan2(double x,double y);y/x的正切值。都是弧度表示
double sinh(double angle);.....cosh....tanh.....
4.math.h double exp(double x); double log(double x); double log10(double x);
5.math.h 浮點表示形式 double frexp(double value,int *exponent);計算一個指數exponent和小數fracion使
fraction*pow(2,exponent)的值等於value,其中0.5<=fraction<1。
double ldexp(double fraction,int exponent);返回fraction*pow(2,exponent);
double modef(double value,double *ipart);把浮點數value分成整數*ipart和小數返回值
6.math.h double pow(double x,double y); x的y次方
double sqrt(double x);
7.定義域錯誤demain error,實參不再函數定義域內。范圍錯誤range error數過大或過小超過表示范圍
8.double floor(double x);double ceil(double x);double fabs(double x);double fmod(double x,double y);
fmod返回x除以y產生的余數,商被限制為整數值。用double只是為了表示更大的范圍
9.stdlib.h 字符串轉換
int atoi(char const *string);
long int atol(char const *string);
long int strtol(char const *string,char **unused,int base);
unsigned long int strtoul(char const *string,char **unsed,int base);
double atof(char const *string);
double strtod(char const *string,char **unused);
任何一個函數的第一個參數包含前導空白字符將被忽略,任何非法後綴,它們也將被忽略
atoi和atol執行基數是10的運算。strtol保存一個指向轉換值後面第一個字符的指針,如果函數的第二個參數
並非NULL,這個指針便保存在第二個參數所指向的位置。這個指針允許字符串的剩余部分進行處理而無需推測
轉換在哪個位置終止。base是轉換的基數,如果基數是0,任何用於書寫整數字面量的形式都被接受,包括指定
數字基數的形式,如0x2af4,0377。否則,基數值應該在2到36直接,對於基數11-36,字母A/a-Z/z被解釋為10-35
如果string無法表示合法的數值,返回0,函數在errno中存儲ERANGE
10.time.h clock_t clock(void);程序開始運行處理器消耗時間,近似值,想得到精確值在main開始調用,相減。
返回的是處理器時鐘滴答次數,想得到秒要除以常量CLOCKS_PER_SEC。太大返回-1
11.time_t time(time_t *returned_value);太大返回-1,標准沒規定結果用秒表示,不能用於判斷時間流逝,
12.char *ctime(time_t const *time_value);返回字符串,例如 Sun Jul 4 04:02:28 1976\n\0;
字符串內的空格是固定的,
double difftime(time_t time1,time_t time2);計算差,並轉化成秒
13.struct tm *gmtime(time_t const *time_value);把時間轉換成格林尼治時間,世界協調時間
struct tm *localtime(time_t const *time_value);轉換成當地時間,但標准沒有UTC和當地時間關系
strutc tm{int tm_sec;0-61;int tm_min;0-59;int tm_hour;0-23;int tm_mday;1-31;
int tm_mon;0-31;int tm_year;0-?;要加1900;int wday;0-6;int tm_yday;0-356;int tm_isdat;夏令時標志}
14.char *asctime(struct tm const *tm_ptr);返回的格式和ctime相同
size_t strftime(char *string,size_t maxsize,char const *format,struct tm const *tm_ptr);
非常靈活的tm結構轉換成字符串
15.time_t mktime(struct tm *tm_ptr);
16.setjmp.h int setjmp(jmp_buf state); void longjmp(jmp_buf state,int value); 類似goto機制
首先聲明jmp_buf,並調用setjmp對它初始化,返回值是0,setjmp把程序狀態保存到緩存區,調用處的函數
稱為頂層函數,以後調用longjmp,會導致保存的狀態恢復,setjmp返回longjmp的參數value
17.信號 signal.h
18.void abort(void); void atexit(void (func)(void)); void exit(int status);
abort不正常終止程序,引發SIGABRT信號。atexit注冊退出信號,當eixt調用時,注冊的函數將按注冊順序
反序被調用,然後流的緩沖區被刷新,文件關閉,tmpfile文件被刪除
19.assert.h void assert(int expression);假時打印信息並終止, #define NEBUG禁用斷言
20.stdlib.h char *getenv(char const *name);返回操作系統維護的name對應的信息
21.stdlib.h void system(char const *command);系統執行,存在可用,返回非零值,否則返回零
22.void qsort(void *base,size_t n_elements,size_t el_size,int (*compare)(void const *,void const *));
void bsearch(void const *key,void const *base,size_t n_element,size_t el_size,
int (*compare)(void const*,void const *));
運行時環境
1.-S保留匯編代碼
2.參數按參數列表相反的順序壓入堆棧,這樣第一個參數位於堆棧中參數的頂部
如果相反順序,第一個參數距離幀指針的偏移量就和壓入堆棧的參數數量有關。雖然編譯器可以計算,但
可變實參列表就無法計算偏移量了
3.函數三部分:函數序prologue,函數啟動需要的工作。函數體body。函數跋epilogue,函數返回前清理堆棧