基礎
1. C語言默認的函數返回值是int, 而c++中沒有這個規定,必須顯示寫函數返回值,即使是void
2. 1. c語言中的整數類型有char, short, int, long等幾種, 下面是C語言對每種數據類型長度的規定:
(a). short和long類型的長度不相同
(b). int類型通常同具體機器的物理字長相同
(c). short通常是16bits, int通常是16bits or 32bits每種編譯器可以根據硬件的不同自由確定, 但是short和int必須最少是16bits, 而long類型必須最少是32bits, 並且short必須比int和long類型要短。
3. C++中的數據類型
1、字符型數據char,該類型始終是一個字節長,即8位。
2、整形int、短整型short和長整形long。通常int爲一個字長,short爲半個字長,long爲一個或2個字長(在32位機器中爲一個字長)。
3、浮點型float、雙精度double、和長雙精度long double,分別表示單精度浮點數 雙精度浮點數和擴展精度的浮點數值。典型情況下,float 爲一個字,double是兩個字,long double爲三個或四個字。
4. float與double都以%f輸出 %0.f表示不要小數部分
5. 學習C語言,在d:/dev_projects/testc中建立C工程 C盤下turboc下codes
6. int c = getchar(); putchar(c); 由於判斷是否EOF,所以c要大一些,用int
7. UNIX下運行cc hello.c 生成hello.out , 直接運行hello.out就行
8. 函數的默認返回類型爲int,如果返回int,則可省略int
9. 在函數外面定義的是外部變量,函數裏面要使用首先要extern聲明一下
10.void copy(void); ANSI C語言中,如果聲明空參數表,則必須使用void
11.關於extern : file1中定義的變量 在file2中使用要加extern聲明
一般地,把變量和函數的extern聲明放在頭文件中
12.定義:表示創建中分配存儲單元; 聲明指說明變量的性質,並不分配存儲單元
13.變量名
a) 下劃線_被看成是字母,一般用於命名長度較長的變量名,提高可讀性
b) 局部變量短一些,外部變量名長一些
14. short通常16位,int通常16或32位,long通常32位
short和int至少16位,long至少32位,int <= long, short <= int
有關這些類型長度定義的符號學號以及其他與機器和編譯器有關的屬性可以在標準頭文件<limits.h>和<float.h>中找到
long = 23L; 如果沒加L且值太大超過int容量也被當long值處理
一個字符常量是一個整數 用’0’代替48就增加了可讀性,不用關心具體值
通過轉義字符序列表示爲字符和字符串常量
轉義字符序列看起來像兩個字符,卻是一個字符:’\ooo’:一到三個0…7數字, ‘\xhh’:一到多個0…9, a…f, A…F
#defineBELL ‘\007’ /* ASCII響鈴符 */
‘\0’表示值爲0的字符,也就是空字符NULL或null
常量表達式在編譯時求值
字符串常量也叫字符串字面值 “hello”, 雙引號不是其中一部分,只是限定字符串
‘x’是一個整數,其值是字母x在機器字符集中對應的數值;”x”是一個包含字母和’\0’的字符數組
15. leap year: if ((year % 4 == 0 && year % 100 !=0) || year % 400 == 0)
16. 非自動變量只進行一次初始化操作,在編譯階段。 默認情況下,外部變量和static變量被初始化爲0.
自動變量在每次進入函數或程序塊時要顯式初始化一次,初始化表達式可以是任何 表達式。
任何變量的聲明都可以用const進行限定 const數組的元素值都不能改
%不能用於double和float
將字符轉換爲整數要注意,C沒規定char類型的變量是無符號還是帶符號變量,所以當把一個負char變量的值轉爲int類型時,結果有可能是負也有可能是正
帶不帶符號是與機器相關的,爲保證移植性,在char中存放非字符數據最好指定signed或unsigned
二元運算如果沒有unsigned,則按如下轉換:
è long double
è double
è float
char, short-> int
è long
注意:表達式中float類型不會自動轉換爲double類型
如果表達式中含有iunsigned時,轉換規則要複雜:因爲與機器相關
如果int16位,long32則,-1L > 1U ,此時,int的1U提升爲singedlong, 但-1L> 1UL, 此時singed long的-1L提升爲unsignedlong,變成大整數
無論是否進行符號擴展,字符型變量都將被轉換爲整型變量
float -> int 小數部分截掉
double ->float 小數部分進行四捨五入還是截取取決於實現
關於函數原型:函數原型類似函數定義時的函數頭。爲了能使函數在定義之前就能被調用,C++規定可以先說明函數原型,然後就可以調用函數。函數定義可放在程序後面。系統標準函數並沒有在包含文件中定義,而只是提供了函數原型。在調用函數時,系統會正確地調用庫函數。
注意:函數原型與函數定義必須一致,否則會引起編譯錯誤。如果函數是單獨編譯的,則這種錯誤就無法檢測出來
在沒有函數原型的情況下,參數傳遞中,char與short類型都被轉爲int, float轉爲double,所以,這種情況下,最好把參數聲明爲double或int
有一個實現僞隨機數發生器的函數rand以及一個初始化種子數的函數srand,前一個函數用了強制類型轉換 return (usigned int)***
int rand(void );
void srand(unsigned int); // 設置種子數
17. 運算符優先級:
-> . 大於! ++ * (強制轉換) sizeof ~
18. 一個程序可以保存在一個或者多個源文件中,各個文件可以單獨編譯,並可以與庫中已編譯過的函數一起加載。這一過程的具體實現因編譯器不同而異
19. cc main.c file1.c file2.c
如果main.c有錯,則 cc main.cfile1.o file2.o
20. 對於空參數,新程序不提倡func(),而寫成func(void);
21. 外部變量和函數的作用域從聲明它的地方開始,到其所在的文件的結束
如果要在外部變量的定義之前使用該變量,或者外部變量的定義與使用不在一個源文件中,則必須在相應的變量聲明中強制使用extern ,不須要include包含進來
只能定義一次,其他文件中要使用要extern聲明。定義時必須數據指明長度,而extern中不用指明長度
22.關於extern 詳述已存在QQ日誌中。共三條作用
a) 最重要的作用:隱藏
未加static前綴的全局變量和函數都具有全局可見性,另一個文件中只要extern 聲明一下這個變量就可以用,函數可以不用extern就可以用的
加上static以後,全局變量和函數就只能限於當前文件中可見了,對於函數來講,static的作用僅限於隱藏,對於變量,還有持久性和默認0
b) 保持變量內容的持久, 存儲在靜態數據區的變量會在程序剛開始運行時就完成初始化(使用常量表達式初始化),也是唯一的一次初始化。共有兩種變量存儲在靜態存儲區:全局變量和static變量,只不過和全局變量比起來,static可以控制變量的可見範圍,定義在函數內的static變量與同文件中的同名全局變量來講,是局部隱藏,同樣是持久性
c) 默認初始化爲0
比如初始化一個稀疏矩陣,我們可以一個一個地把所有元素都置0,然後把不是0的幾個元素賦值。如果定義成靜態的,就省去了一開始置0的操作。再比如要把一個字符數組當字符串來用,但又覺得每次在字符數組末尾加‘\0’太麻煩。如果把字符串定義成靜態的,就省去了這個麻煩,因爲那裏本來就是‘\0’
23. int sum_array(int a[static 3], int n) 將static放在數字3之前表明數組a的長度至少可以保證是3
只不過是一個"提示",C編譯器可以據此生成更快的指令來訪問數組。(如果編譯器知道數組總是具有某個最小值,那麼它可以在函數調用時預先從內存中取出這些元素值,而不是在遇到函數內部實際需要用到這些元素的語句時才取出相應的值。)如果數組參數是多維的,static僅可用於第一維(例如,指定二維數組的行數。)
24. #include “”在當前位置查找,#include <>根據相應規則查找,跟具體實現有關
25. C預處理
#define作用域是當前文件
宏定義中也可以使用前面出現的宏定義
字符串中的字符不進行替換
#define佔一行,續行使用\
爲了省去函數調用所需的運行時開銷,常常將函數定義爲宏 取消它:#undef getchar
形參不能使用帶引號的字符串替換,參數名以#作前綴則把實參轉爲該參數的帶引號的字符串
##是用於連接兩個參數的
#if!defined(HDR) 或#ifndef
...
#endif
#if中不能使用sizeof(),因爲預處理器不對類型名進行分析
26. 幾個頭文件
NULL定義在#include <stddef.h>中
malloc定義在<stdlib.h> 它參滿足對於不同類型對象的不同大小的對齊要求 返回void *保證能返回不同類型指針,強制轉換一下就可以
EOF<stdio.h> 一般爲-1
27.打印命令行參數
for (i = 1; i < argc; ++i) {
printf("%s%s", argv[i], (i <argc-1) ? " " : "\n");
}
或
while (--argc> 0) {
printf(“%s%s”, *++argv, (argc > 1) ? “ ”: “\n”);
}
printf的格式化參數也可以是表達式: printf((argc > 1) ? “%s” : “%s”, *++argv);
28.算維數的宏: #define dim(arr) (sizeof(arr) /sizeof(arr[0]))
29.關於union聯合體:
union u_tag {
int ival;
float fval;
chart *sval;
} u;
u必須足夠大,以保存這三種類型中最大的一種
這些類型中的任何一種類型的對象都可賦值給u,讀取的類型必須是最近一次存入的類型,程序員負責跟蹤當前保存在聯合體中的類型,如果讀取類型與存入類型不一致,結果取決於具體實現。聯合體只能用第一個成員類型的值進行初始化。上述u能能用int值進行初始化
30.輸入輸出
文件流由一些行組成,每行尾是一個換行符
getch()、getche()和getchar()以及gets函數
(1) getch()和getche()函數 : 前者不回顯,後者回顯 利用回顯和不回顯的特點, 這兩個函數經常用於交互輸入的過程中完成暫停等功能
main函數最後一行:getch(); /*等待輸入任一鍵*/與system(“pause”);一樣
C語言中getch以及上面其他兩個都在<stdio.h>,C++中getch在#include<conio.h>中
再囉嗦一下getch的廢話:可以用它來實現“按任意鍵繼續”的效果,即程序中遇到getch();這行語句,它就會把程序暫停下來,等你按任意鍵,它接收了這個字符鍵後再繼續執行後面的代碼
(2)getchar等待輸入直到按回車才結束, 回車前的所有輸入字符都會逐個顯示在屏幕上。但只有第一個字符作爲函數的返回值。
(3)gets(str)從stdin流中讀取一行到str中,直至接受到換行符或EOF時停止,換行符被刪除,附上’\0’作爲字符串結束符
puts(str)將str輸出到Stdout上,並在末尾加上換行符
下文的文件訪問中,會提到與它們類似的函數fgets與fputs
(4)int putchar(int): 返回輸出的字符,如果發生錯誤,則返回EOF 。 同樣可以使用>將輸出重定向到某個文件中
(5)<stdio.h>中的getchar和putchar以及<ctype>中的tolower函數,一般都是宏,避免調用開銷
printf()
l 負號:左對齊
l h作short打印, l作long打印
l %d或%i
%o 無符號八進制數(沒有前導0)
%x或%X 無符號十六進制(沒有前導0x或0X)
%u
%c
%s char *, 遇到’\0’或已打印了由精度指定的字符數爲止
%f double, 默認6個小數
%e或%E double,m.ddddde+xx d的個數由精度指定,默認6
%g或%G double,如果指數小於-4,大於精度,則以%e或%E輸出,尾部的0和小數點不打印,否則以%f
%p void *
%% 打印一個百分號
小數點前叫寬度,小數點之後叫精度
寬度或精度可用*表示,它的值通過轉換下一參數(必須爲int)來計算,例如:
printf(“%.*s”, max, s); max是int的數
%-15.10s 是十五寬度,最多打印10個字符,且左對齊
printf(s); 如果s中有%則出錯
printf(“%s”, s);// ok
int sprintf(char*string, char *format, arg1, arg2, ...); 把輸出結果放到string中
31. 關於變長參數表./testc/funcs/minprintf.c
int printf(char*fmt, ...);
int scanf(char*format, ...);
關於scanf的說明:
1) 其他參數都是指針——存放地址
2) 掃描完格式串,或者遇到無法匹配的情況時終止
3) 返回成功匹配的個數,如果返回0說明與第一個格式不匹配。如果到達文件尾,則返回EOF
4) 下一次調用scanf將從上一次轉換的最後一個字符的下一字符開始繼續搜索
int sscanf(char*string, char *format, arg1, arg2, ...);
說明:它按照format中的格式掃描string,並把結果存在arg1, arg2, ...中,這些參數必須是指針
scanf基本轉換說明:
a) d: 十進
b) i: 十進制,八進制(以0開頭),十六進制(0x開頭)
c) o: 八進制(可以不以0開頭)
d) x:十六(可以不以0x開頭)
e) u:無符號十進制
f) c:將接下來的多個字符比如%8c存入到指定位置,該轉換規通常不跳過空白字符。如果需要讀入下一個非空白字符,使用%1s
g) s: 指向一個足以存放該字符串+’\0’的char *, 字符串的末尾被添加一個’\0’
h) e, f, g: 浮點數
i) %: 字符%,不進行任何賦值操作
scanf("%d/%d/%d", &m, &d,&y); 讀入mm/dd/yy沒錯 轉義符是\而不是/
scanf忽略格式串中的空格和製表符,在讀入時,將跳過空白符(空格,製表符,換行符)
32. 文件訪問
FILE *fp; // FILE在<stdio.h>中定義
FILE *fopen(char*name, char *mode); // mode: r w a追加
如果打開一個不存在的文件用於寫或追加,該文件將被創建(但是name中是一個相對路徑,且含有一個沒有創建的文件夾時,它會出錯,不會自動創建文件夾),當以寫方式打開一個已存在的文件時,該文件原來的內容將被覆蓋。讀一個不存在的文件將會出錯,或讀一個沒有讀權限的文件也會出錯。如果發生錯,則返回NULL.
打開文件後,通過getc和putc對文件進行讀寫最簡單
int getc(FILE *fp); 返回fp指向的下一個字符,如果到達文件尾或出現錯誤,則返回EOF
int putc(int c, FILE *fp); 寫入到fp中,並返回寫入的字符。如果發生錯,則返回EOF。
上面這兩個也是宏,而不是函數
關閉文件int fclose(FILE *fp);
啓動一個C程序,操作系統打開三個文件,並將這三個指針交給程序,它們是stdin, stdout, stderr。它們在<stdio.h>中聲明,在大多環境中,stdin指向鍵盤,後兩個指向顯示器。可以重定向到文件使用<或>.
getchar putchar可定義如下:
#define getchar() getc(stdin)
#define putchar(c) putc((c), stdout)
示例:test_fopen.c p142_filecopy.c
補充說明:exit(1);會終止調用程序的執行,任何啓用該程序的進程都可以獲取exit的參數值。因此,可以通過另一個將該程序作爲子進程程序來測試該程序的執行是否成功。非0說明異常。exit爲每個憶找開的輸出文件調用 fclose函數,以將緩衝區中的所有輸出寫到相應的文件中.在main中,return 等同於exit。使用Exit的好處還有一個,就是它可從其他函數中調用。feof與ferror類似int feof(FILE *fp),如果到達文件末尾,則返回一個非0值
對文件的格式化輸入和輸出
int fscanf(FILE*fp, char *format, ...);
int fprintf(FILE*fp, char *format, ...);
行輸入與行輸出 原代碼./funcs/fgets.c fputs.c getline.c
char *fgets(cahr*line, int max, FILE *fp);
與getline類似
從fp指向的文件中讀入下一行,包括換行符,並以’\0’作爲字符串結束,即最後兩個字符是’\n’與’\0’。最多讀max-1個字符
返回值:通常返回line,如果遇到EOF且讀入失敗(根本就一個字符都沒讀到),則返回 NULL。
int fputs(char*line, FILE *fp);
寫入到fp中,line不需要包含換行符
返回值:發生錯誤則返回EOF,否則返回一個非負值
gets與puts是對stdin和stdout進行操作,gets在讀取字符串的時候將刪除換行符,而puts在寫入字符串時,將在最後添加一個換行符
33. <string.h>
strcat(s, t)
strncat(s, t, n)
strcmp(s, t)
strncmp(s,t,n)// 只與前n個字符進行比較
strcpy(s,t)
strncpy(s,t,n)
strlen(s)
strchr(s,c) // 在字符串s中查找c,若找到,返回第一次出現的位置指針否則返回NULL
strrchr(s,c) // 查找c,若找到,返回最後一次出現的位置指針
34. <ctype.h>
isalpha
isupper
islower
isdigit
isalnum
isspace 空格,橫向製表符,縱向製表符,換行,換頁,回車
toupper
tolower
35. int ungetc(int c, FILE *fp)
將c寫回到fp中,成功返回c,失敗返回EOF。 每個文件只能接收一個寫回字符。它可以與任何一個輸入函數一起使用,如scanf,getc,getchar
36. 存儲管理
void*malloc(size_t n);
void*calloc(size_t n, size_t size); 返回一個指針 ,該指針指向的空閒空間足以容納由n個指定長度的對象組成的數組。否則返回NULL。此數組初始化爲0
free(p)
典型的錯誤:
for (p = head; p!= NULL; p = p->next) {
free(p);
}
改爲
for (p = head; p!= NULL; p = q) {
q = p->next;
free(p);
}
37. <math.h>
sin cos atan2(y,x) : y/x的反正切,其x與y用弧度表示
exp: 指數函數ex
log(x) : 以e爲底,自然對數, x > 0
log10
pow
sqrt
fabs
38. 隨機數生成
rand成生介於 0與RAND_MAX間的僞隨機整數序列 // RAND_MAX 在<stdlib.h>
#define frand()((double) rand() / (RAND_MAX + 1.0))
39.附錄
a) 標誌符可以是任意長度
b) 與具體實現相關的限制:limits.h float.h
c) 日期時間函數time.h
d) stddef.h中指針相減ptrdiff_t類型
e) auto與register聲明自動類型的對象,僅用在函數中,聲明的同時也是定義,分配了空間。後者說明會被頻繁的訪問,但是隻有很少的變量被真正存放在寄存器中,並且只有特定類型纔可以,與具體實現有關。register變量不能用&取地址操作符,即使它不是一個真正的寄存器變量。
40.d
41.