1.字符串
字符串就是一個字符數組,結尾以'\0'作為標志
一個字符占用一個字節(漢字占用兩個字節),從左到右依次存放,在字符串的結尾自動加入一個字節的結束標志'\0'
'a'與"a"的不同:'a'代表一個字符占用一個字節;"a"代表一個字符串占用兩個字節.
字符串初始化:char str[10]="abc123!@#";//不能寫成char str[10];str="dfh";(初始化聲明的時候的=不代表賦值操作,只是初始化)
2.sizeof(類型名)
sizeof返回的值是無符號的整數
可以用sizeof(a)/sizeof(a[0])計算數組長度
3.類型定義(typedef)
typedef int Bool; ? ?//(后面變量名的首字母最好大寫)
Bool flag; ? ?//類似與使用了int flag
4.宏定義
【定義宏】#define BOOL int
數組和指針不能用宏定義,宏定義中的替換列表為空也是合法的,也可以包含對另一個宏的調用,但宏不能調用它本身.
一個數字常量,如果不是0和1,就最好定義成宏.
【帶參數的宏】 #define ?標示符(x1,x1,…,xn) ?替換列表 ? ?//參數在替換列表中都要放在圓括號中
5..數組
定義數組時,數組名不能和變量名相同,也不能和系統關鍵字一樣
數組的地址就是數組元素的首地址,使用數組名a,代表的就是數組a[]的地址
多維數組:不常用,因為指針數組更加的靈活好用
無論是一維數組還是多維數組,通過單詞const作為數組聲明的開始可以把數組變為“常量”;
(如:const int months[]={31,28,31,30,31,30,31,31,30,31,30,31};)
6..函數
在調用函數前,都需要先聲明函數,函數聲明類似與函數定義的第一行,函數的聲明必須與函數的定義一樣。
【函數聲明】 返回類型 ?函數名(形式參數); ? ?【編譯器只預處理函數,但是不分配內存】
【函數定義】 返回類型 ?函數名(形式參數) ? ?【開辟內存空間,分配內存給函數,函數入口地址為函數名所在地址】
2)從返回值的角度:
有返回值:return,(函數有且只能返回一個返回值),可以是基本數據類型和指針等。
無返回值:void,在C89標準中可以忽略返回值類型,UNIX中默認為int,Window VC中為void;在C99標準中不可以忽略返回值類型。
3)從參數的角度:
帶參數:需要告訴編譯器參數的類型和數量
int main(int argc,char *argv[]);
int main(int argc,char **argv);
不帶參數:參數列表為空,void,可以省略,即int main()或int main(void);就是不需要參數來參與運算。
.返回語句
return:【return 表達式】如果return中表達式的類型和函數返回的類型不一致,系統會把表達式的類型轉換成返回類型
exit:任何函數中都可以使用,【exit(表達式)】;包含在#include 頭文件中。
main函數的返回值是狀態碼,0表示正常結束,非0為異常結束。
7..遞歸
遞歸是函數嵌套調用的一種特殊形式,就是當一個函數調用另外一個函數的過程時,另一個函數恰好是它本身。
遞歸產生的條件:直接或間接的調用它本身,有一個出口(即結束遞歸的條件),要有一個明顯的公理或公式,有規律可循。
1)直接遞歸調用
2)間接遞歸調用
注意:
1)遞歸調用在發生時,消耗了大量的系統資源,反復讀寫棧內存,CPU資源,會降低系統性能,不可控或深層遞歸都會造成系統不穩定
2)我們在開發過程中使用的都是淺層遞歸,如Windows搜索,使用了多線程,淺層遞歸(一般不超過3層)
3)遞歸調用也被用于分治算法
4)能不用就不用遞歸,如:.(){ .|. };. ?(.本身是一個函數,()為.函數的參數列表,;前為.函數的定義,最后一個.是調用這個函數)
8..迭代
迭代法又叫做遞推,凡是能用遞歸來實現的迭代或遞推都能實現。
9..指針
簡單的說,指針就是地址。
內存中的最小存儲單元是字節,一個字節有8位,每一位都有自己的地址,指針就是他們的首地址。
基本數據類型的指針,就是他們在內存中的首地址。
構造類型的指針,數組,他的位置就是,數組名稱所在內存的首地址,即a[0]的地址或者是數組名。
函數類型的指針,就是函數的入口地址,即函數名所在內存的首地址。
指針變量:和其他基本數據類型的變量類似,特殊的是他是能保存地址的變量。
1.定義指針的時候沒有初始化
2.指針指向一個局部變量,當局部變量執行完畢釋放后,仍然指向該局部變量的時候(用完置NULL即可)
3.當指針指向一塊動態的內存空間時malloc(new)使用完畢被free(delete)釋放后,仍然指向該空間,(用完置NULL即可)
10.指針和常量的關系
常量指針:指針指向了一個常量的指針變量,常量的內容不可以修改,但是地址可以修改。
int const *p; ? ?const在*號后,是p的值不能修改;const在*號前,是*p的內容不能修改
指針常量:是個常量,是指指針變量P的值不能被修改,p是個常量,而指針指向的對象的值是可以改變的。
11.指針和數組的關系
數組指針:指向一維數組的指針,即數組的首元素
int a[10];int *p=NULL;p=a;
是一個指向二維數組一行的指針變量,即二維數組的首行的地址
int (*p)[表達式];
指針數組:數組元素是指針變量
int *p[表達式];
12.結構體(struct)
能夠保存不同數據類型的一種構造數據類型
【關鍵字】struct
【定義結構體】 ? ?struct 結構體名{
成員變量1;
成員變量2;
…
成員變量n;
}; ?
【結構體和指針】
1)指向結構體的指針
struct struct_name *p; ? ?//p是指針變量名
p=&object_name; ? ? ? ?//&取地址符不能忘
【結構體的嵌套】
一個結構體中嵌套了另一個結構體
struct struct_name{
成員變量1;
成員變量2;
struct struct_name_a{
成員變量a;
成員變量b;
}object_name_a;
}object_name;
【結構體數組】
數組中的每個元素都是一個結構體變量
struct struct_name{
成員變量1;
成員變量2;
}數組名[表達式]; ? ? ? ?//表達式可以為空,為空的時候是不定長度的數組
13.枚舉(enum)
枚舉的成員中只能用一種類型,成員內不指定序號的時候都以0開始,C語言把枚舉變量和常量作為整數來處理
enum color{red, black, blue}a,b; ? ?//中間以逗號隔開
14.鏈表
鏈表是線性表的一種,是線性表的鏈式存儲;是一種使用動態內存分配的,能保存不同數據類型的一種數據結構.構成鏈表的最小單位稱為節點.
C語言執行過程中,在內存中的情況:
1)代碼段(靜態區域)
代碼段由程序中的機器碼組成,C語言中源代碼編譯后就形成了機器碼,執行的時候,CPU的程序計數器指向了代碼段的每一條代碼,并由CPU依次執行
2)數據段(靜態區域)
只讀數據段,是程序使用一些不會被修改的數據,使用這些數的方式類似與查表式的操作,放置在只讀存儲器中;
已初始化讀寫數據段,是在程序中聲明,有初值的變量,需占用寄存器空間,在程序執行時,位于可讀寫的內存區域內,供程序運行時讀寫
4)堆空間(動態區域)
只在程序運行時出現,一般由程序員分配和釋放,在具有操作系統的情況下,若程序員忘記釋放,在程序結束后,系統會自動回收內存
5)棧內存(動態區域)
只在程序運行時出現,在函數內部使用的變量,函數參數及返回值,函數調用(遞歸)都將使用棧空間.棧空間是由編譯器自動分配和釋放的內存.
C語言提供的兩種內存分配的方式:
1).靜態內存分配(棧內存)
由編譯器自動為我們分配的內存空間,一般棧內存的大小為10M~30M
內存的對齊:是指整型占4個字節,大于4個字節的數據類型,也按照4個字節來計算,而且是4的整數倍
內存的補齊:只在結構體中有,如果所占字節數不足4個數據類型,比如char,需將不足的字節數補空,補夠4個字節
2).動態分配內存(malloc向堆申請內存)
malloc函數(分配后不初始化)
void *malloc(size_t size); ? ?//返回值是萬能指針,在Mac下占8個字節,在Win下占4個字節
用于動態的向堆內存申請內存空間,使用完后,要使用free()函數釋放該內存
一旦指針p指向動態分配的內存塊,就可以忽略p是指針的事實,并且把它用作數組的名字,p[i].
靜態庫(.a): 是指在編譯鏈接時, 把庫文件中的代碼全部加入到可執行文件中, 因此生成的文件比較大, 但在運行時就不再需要庫文件了.
動態庫(.so): 在編譯鏈接時, 并沒有把庫文件的代碼加入到可執行文件中, 而是在程序執行時由運行時鏈接文件加載庫, 節省了系統開銷.