C語言總結
C語言的概述(本身總結)
起源,發展,現狀,特色,優缺點
數據類型
內建:C語言自帶的數據類型
整型
stdint.h 對數據類型進行了封裝
limits.h 各類數據類型的最大值是小值
unsigned
uint8_t,uint16_t,uint32_t,uint64_t
char,short,int,long,long long
char 0~255 256個值
short 0~65535 65536個值
signed
int8_t,int16_t,int32_t,int64_t
char,short,int,long,long long
char -128~127 256個值
short -32768~32767 65536個值
浮點型(小數點浮動)
數據格式:符號位 指數位 尾數位
默認小數點後六位有效,精度有限,運算效率低
有專門針對浮點運算的CPU
float 4
double 8
如何判斷float類型的數據是「零值」?
if(val<0.000001 && val>-0.000001)
{
//不等於0,但無效,至關於零值
}
如何提升浮點類型數據的準確率?
先放大,在還原。
布爾型
因爲C語言出現於1970年左右,布爾類型流行於1980之後,因此c語言中是沒有真正的布爾類型。
bool stdbool.h
true 非零值 NULL 絕大多狀況小爲假 '\0'
false 零值
NULL == ((void*)0)||((void*)1);
_bool C99標準中補充的
如何判斷int,bool,int*類型的值是否爲假?
int num;
if(0 == num)
if(flag)
if(NULL==p)
字符型
底層採用整數存儲的,整數與ASCII表的字符對應
'\0' 0
'0' 48
'A' 65
'a' 97
轉義字符
\a
\b
\t
\v
\f
\n
\r
%%
\"
\\
枚舉
功能受限制的int類型,防君子不防小人
使用枚舉是一直錦上添花,使用枚舉能夠提升程序的安全性和可讀性
有名枚舉
typedef enum CMD {ADD,DEL,FIND};
能夠定義枚舉變量
匿名枚舉
ENUM {UP,DOWN,RIGHT,LEDT}
使用枚舉值,或者與switch配合使用
指針:整型(整數),表示的是內存的編號
自建:C程序本身設計的數據類型
結構
聯合
數組
變量(容器)與常量
常量:字面值,宏常量,枚舉值,初始化過而且被const修飾的全局變量
變量:
全局變量:普通全局變量,靜態全局變量
做用域不一樣
局部變量:普通全局變量,靜態全局變量
存儲位置不一樣:普通在棧,靜態在bss
塊變量:普通塊變量,靜態塊變量
變量名:
一、由數字、字母、下劃線組成
二、不能以數字開頭
三、不能與關鍵字重名
四、見名知義
功能、範圍、類型
輸入數據
scanf 佔位符 變量地址
scanf返回值,成功接取數據的個數
如何不理輸入緩衝區:
getchar()
scanf("%*[^\n]"),scanf("%*c");
stdin->_IO_read_ptr = stdin->_IO_read_end;
輸出數據
printf 佔位符 變量名
數據遇到什麼條件纔會從緩存區到達屏幕:
一、滿4k(4096byte)
二、遇到\n
三、遇到輸入類型的函數
四、手動刷新 fflush(stdin);
五、程序結束
數組
數組的定義:類型 數組名[數量];
在內存的分佈上優先定義數組,再定義變量
數組的初始化:類型 數組名[數量] = {val1,val2...};
一、初始化值過多會有警告
二、初始化值不夠補0
三、類型 數組名[數量] ={};
四、類型 數組名[] = {val1,val2...};
數組的越界:
一、髒數據
二、段錯誤
三、一切正常
變長數組:數組的長度在編譯時沒法肯定,在運行時能夠發生變化,當執行到定義數組語句時,數組的長度就肯定下來了,不可再變
優勢:根據需求在肯定數據的長度,節約內存。
缺點:不能初始化(數組的初始化是由編譯器幫助完成)
多維數組:
一維數組:變量組成的隊列
二維數組:變量組成的方陣
三維數組:變量組成的立方體
流程控制語句:
分支
if else if else
switch
小括號中只能是整型數據
case後必須是常量
default 最後執行
break 關閉執行開關
循環
for
for([1];[2];[3])
{
[4]
}
for 語法靈活,1,2,3,4均可以缺乏
用循環變量i(index)引導for的運行,負責明確知道循環次數的狀況
while
是for的一種精簡,負責只知道循環條件
do while
先執行循環體,在判斷循環條件,直到循環
if、for、while 若是沒有大括號,默認下一行代碼是它的語句體,但不建議這樣使用,大括號不要省略(安全性、可擴展性),若是執行異常,記得檢查小括號後面是否有多餘的分號
跳轉
goto
goto 標籤;功能是在函數內能夠任意跳轉,這種跳轉會破壞原先的分支,循環結構
大多數公司會禁止使用goto,禁止的方式就是把goto定義爲病毒(應用層程序)
但在驅動編程時goto很是適合用來處理異常
break
一、switch中關閉開關
二、在循環中使用能夠跳轉一層循環
continue
只能在循環中使用,功能是結束本次循環進入下次循環
return
一、返回函數的執行結果
二、提早結束函數的執行
函數
函數的聲明:
extern 返回值類型 函數名(參數類型,參數名,..);
返回值類型 函數名(參數類型,參數名,...);
返回值類型 函數名(參數類型1,參數類型2,...);
函數的定義:
返回值類型 函數名(參數類型,參數名,...);
{
函數體
}
使用函數要注意的問題:
一、函數傳參所有都是值傳遞(內存拷貝)
因爲數據名就是指針,以數組當函數參數時也是值傳遞,並且數組的長度也會丟失,
二、函數的隱式聲明
當調用函數,若是沒有提早聲明,編譯器會猜想函數的格式,若是猜想正確函數則正常執行若是猜錯,則會執行異常。
三、若是函數不須要參數要寫void
定義函數時若是小括號中是空的,則意味着任意類型,任意個參數均可以調用函數
四、不寫return不表示沒有返回值
遞歸:
函數本身調用本身的行爲叫遞歸,這種解決問題的思想:分支
這種調用極易引起死循環,遞歸編寫的格式:
一、出口
二、解決一部分問題
三、再次調用本身
遞歸是一種解決複雜問題的常見手段,也比較適合解決樹型結構問題,容易理解但不能模擬它的執行過程
指針:
什麼是指針:一種數據類型,表明內存編號的整數
使用它能夠定義指針變量
什麼狀況下使用指針:
一、函數之間共享變量
二、優化函數傳參
三、使用堆內存必須配合指針
指針的使用方法:
定義:類型* 變量名_p;
一、指針的類型決定了,經過指針訪問內存時的字節數
二、指針不能連續定義
int* p1,p2,p3;//p1是指針,p2是int變量
int *p1,*p2,*p3;
三、指針的默認是隨機的(野指針),若是沒有肯定的值能夠初始化爲NULL(空指針)
四、指針變量與普通變量的使用方法有很大區別,所以最好從名字上就能區分開,因此以p結尾
arr,str
賦值:指針變量名 = 內存編號
一、類型要匹配,不然會有警告
二、類型指針<=>void*
三、void*不能直接使用,要轉換成有類型的指針
int* p = malloc(4);
訪問內存:*指針變量
int *p = #
*p <=>num;
這個過程是有可能產生段錯誤的
訪問內存的字節數由指針的類型決定的
使用指針要注意的問題
一、空指針
指針變量的值爲NULL,NULL不必定是0
使用空指針的後果就是必定產生段錯誤
0地址是操做系統的復位地址,存儲了重啓時要使用的數據,所以不能讓應用程序訪問,NULL也是應用程序的錯誤標誌,若是函數的返回值是NULL說明函數執行錯誤
使用來歷不明的指針錢要先檢查NULL == p
strlen strcat strcpy strcmp
二、野指針
指針變量的值不肯定
使用野指針不必定出錯,肯呢過產生的後果:
一、髒數據
二、段錯誤
三、一切正常
出現野指針比出現空指針的後果更嚴重,所以野指針沒法判斷
防止野指針出錯是隻能從根源着手,不製造野指針:
一、定義指針變量時必定要初始化
二、不持有局部變量的地址
三、堆內存一旦初始釋放,指針要及時設置爲空
三、指針的運算
所以指針變量的值就是整數,因此整數數據可使用的運算符它基本均可以使用,可是要以實際意義爲準則
四、指針與數組名
數組名:是一種常指針,他與數組的首地址是對應關係
指針和數組名的用法是能夠互換的:
p[i] = *(p+i);
*(arr+i) = arr[i];
修飾變量的關鍵字
auto 不能與static 一塊兒用,全局不變量也不能使用
定義自動分配,釋放的變量,不加就表明加
unsigned:定義無符號整型變量
signed:定義有符號整型變量,不加就表明加
const:爲數據提供一種保護機制,被它修飾過的變量不能顯示修改
變量、函數參數、返回值、指針
const 全局變量 初始化 = 常量
const int *p; 不能經過 *p修改內存的值
inr const *p;同上
int* const p; p的值不能修改
const int* const p; 不能經過*p修改內存的值,p的值也不能修改
static
限制做用域:全局變量、函數
改變存儲位置:局部、塊變量
延長生命週期:局部、塊變量
volatile
防止編譯器優化變量的取值過程
register
申請把變量存儲到寄存器
extern
聲明變量、函數
程序在內存中的分佈
代碼:能夠執行文件會被所有加載到此段
只讀:字面值、常量
全局:被初始化過的全局變量
bss:靜態變量、未初始化的全局變量
程序執行前會把這段內存清理爲0
棧:局部變量、塊變量
堆:程序員本身變量、沒法取名、足夠大
字符串
串:是一種數據結構,由若干個相同類型的數據組成,有一個明確的結束標誌'\0'。
字符串字面值:
以地址形式存儲在只讀內存中。
若是在程序中已經存在一份字符串字面值,當再使用它時不會在內存中再定義一份。
字符串能夠換行寫,編譯器會自動把它們鏈接。
定義:
const char* str = "hehe";
char str[] = "hehe";
處理字符串的函數:
輸入:
scanf
gets
fgets
getstr
fscanf
fread
輸出:
printf
puts
fpritnf
fwirte
string.h
strlen
strcat/strncat
strcpy/strncpy
strcmp/strncmp
strchr
strstr
atoi
memset
memcpy
sscanf/sprintf
字符串-》數值 數值-》字符串
堆內存使用
C語言中是沒有提供內存管理的語句,只能靠標準庫提供的庫函數(stdlib.h)。
內存芯片-》操做系統-》malloc-》a.out
malloc 申請內存
calloc 按塊申請內存,並把申請的內存初始化
realloc 調整已有內存的大小,把內存調大就至關於申請內存,把內存調小就至關於在釋放內存。
free 內存的釋放。
使用堆內存要注意的問題:
一、重複釋放
二、越界:
前續錯誤
後續錯誤
段錯誤
髒數據
一切正常
三、泄漏
誰申請,誰釋放
誰知道該釋放,誰釋放
結構、聯合
typedef struct 結構名
{
成員類型 成員名=-1;
void func(void); // eroor
void (*funcp)(void); // 容許
char sex:1;
}結構類型;
一、在定義結構變量時struct不能省略。
二、結構的成員不能初始值。
三、結構的成員不能是函數,但能夠是函數指針。
四、結構變量可對結構變量直接賦值
Student stu1 = {};
Student stu2 = stu1;
stu2 = stu1;
結構的大小:
補齊:結構的總字節數要是它最大成員的整數倍,若是不是則添加空白字節補齊。
對齊:每一個成員在結構中的內存起始編號,要是它自身大小的整數倍,若是不是則添加空白字節保持對齊。
Linux和Windows系統對待補齊和對齊的區別?
Window會嚴格按照補齊和對齊的規定嚴格執行
Linux對待補齊和對齊時,超過4字節按4字節計算。
補齊和對齊的字節數是能夠設置的。
聯合:節約內存的一種手段。
聯合常考的問題:
一、聯合的字節數。
union data
{
char arr[5];
int num;
};
二、使用聯合判斷大、小端系統。
0x010203 高位數據1 低位數據3
0x18[][][][] 高位地址0x1B 低位地址0x18
大端 0x01020304
小端 0x04030201
文件操做:
文件的分類:
二進制文件:數據的補碼。
文本文件:存儲的是ASCII的二進制。
windows系統對待換行與Linux系統不一樣。
\n
\n\r
文件的打開方式:
r
w
a
r+
w+
a+
wb \n -> \n
w \n -> \n\r
文件操做函數:
fopen
fscanf/fprintf
fgets/fputs
fread/fwrite
fclose
fseek 調整文件位置指針
ftell 返回文件位置指針的位置
rewind 調整文件指針到文件的開頭。