今天呢,想跟大家分享一下我的筆記,很明顯,目前并沒有完成,想要完整的完成,我還有很長一段路要走,其中也許會有一些值得大家借鑒的地方,具體還是因人而異吧,希望大家能夠有所識訓,后續我還會繼續補充,希望大家能夠關注我(雖然寫的不太好),里面有的是一些基礎,有的不是,有的是一些易錯點,有的是一些邊角料,更新頻率的話最少一周一次,直到徹底補充完整,如果大家覺得對自己有所幫助的話,希望大家點一波關注和小小的贊吧,謝謝大家的支持!
目錄
0、基礎常識
(1)進制
(2)變數與常量
(3)記憶體
(4)其它零零碎碎的點
(5)運算子
1、關鍵字
1.switch
2.關鍵字總覽(不需要記,認識即可)
2、分支和回圈
3、函式
4、陣列
5、指標
6、結構體
7、資料的存盤
8、字串
9、動態記憶體管理
10、檔案操作
11、程式的編譯(預處理)
0、基礎常識
(1)進制
1.\ddd表示1~3個八進制的數字,注意\071和\71表示的都是八進制的數字,
(2)變數與常量
1.區域變數是指代碼塊內的變數,全域變數是指代碼塊外定義的變數,
2.定義并且初始化變數的本質是先根據變數型別所占據的記憶體空間大小為依據開辟空間,然后把索要存盤的資料的二進制補碼形式存盤在記憶體中,就像unsigned int 型別的變數也可以存盤125一樣,換句話說,無論什么型別,都可以互相存盤,當然,前提是開辟的記憶體能夠放的下,因為無論存盤什么資料,存放的都是二進制補碼形式,只有在輸出時才會進行不同形式的轉換,比如-128的補碼在轉換為原始碼形式符號位不變,其它位按位取反,(假設輸出型別是unsigned int),然后加1,然后轉換為十進制進行輸出,而如果輸出型別是signed int時,就直接把補碼轉換為十進制即可,至于一些運算就無關緊要了,因為都是以補碼形式進行計算,
3.C語言中的常量分為以下以下幾種:字面常量、const 修飾的常變數(注意const修飾的最然不可被改變,但本質上仍為變數,不能在定義陣列使放入[]內,因為[]內只能是常量)、#define 定義的識別符號常量、列舉常量
列舉常量的定義方式
enum Sex { MALE, FEMALE, SECRET }; //括號中的MALE,FEMALE,SECRET是列舉常量(按照整數列印后數值為0 1 2)
4.當區域變數和全域變數同名的時候,區域變數優先使用,但一般在定義區域變數時不要和全域變數同名,
5.區域變數是指代碼塊內的變數,全域變數是指代碼塊外定義的變數,
6.全域變數靜態變數在編譯期間就創建好了,
(3)記憶體
1.int 和 long(int)一般都是八個位元組,事實上對于long (int)的位元組長度要求是大于或者等于int型別所占的位元組數,
2.強制型別轉換的格式是(型別) 變數名而不是 型別 (變數名),后者是ui變數的定義,編譯器會顯示對變數的重定義,
3.任何有值特性的均能用sizeof()求其所占的記憶體的大小,比如sizeof(10),編譯器一般會把整數默認為是int 型別占據4個位元組,把小數默認為是double占據8個位元組,
(4)其它零零碎碎的點
1.C語言中是沒有次方運算的,如果要進行次方運算需要運用pow()函式,^是異或運算子,
scanf格式輸入要注意同步,scanf()運用時格式時非常嚴格的,代碼格式和輸入格式要嚴格對照,同時注意一點,如果定義普通變數之后未初始化是無法輸出的,但如果在定義之后,用scanf()進行輸入操作此時不初始化也沒有問題,但我們通常并不建議這樣操作,因為在撰寫程式時,我們賦的初值有時會具有某些含義,所以無論后續是否用scanf進行輸入,最好都要初始化,
2.在定義變數時,因為編譯器默認為我們輸入的整數是int,輸入的浮點數為double,所以在定義單精度浮點數時float a = 3.14f
3.浮點數在進行比較的時候,絕對不能用==進行直接比較,浮點數在存盤的時候本身會有精度損失,進而導致結果可能會有各種細微的差別,
解決方案:#define EPSILON(精度的意思) 0.00001(自己設定的精度)
if ( (x - y) >-0.00001 && (x-y) < 0.00001) 或者 if(fabs(x-y)
實際上,系統已經給我們定義好了精度,即DBL_EPSILON 用法同上,判斷兩個數是否相等時是if(fabs(x-y)),如果判斷某一個浮點數是否等于0時可用if(fabs(x)前面不能加=,即這個數不等于0)
4.區分0、\0、NULL ‘0按照整數進行輸出后的結果是48(0的ascii碼值)
事實上,運用printf進行輸出時,格式為%d時資料都是一樣的,均為0,但它們的型別是不同的,
int a = 0; int *a = NULL(型別為void *); (能夠被運算子(+-*/=等)兩端連接起來的資料型別必須是一樣的,如果不一樣會發生報錯或者警告)
int *p=NULL;
推薦if(NULL == p),而不推薦if(p==0)和if(p)和if(p==NULL)
5.按%p格式進行列印是用來列印地址的,
6.如何理解強制型別轉換?
在將''123456''轉換為整型時需要自己寫函式或者使用相應的庫函式,會改變記憶體中的資料,(真實的轉化,并不等于強制型別轉換)
強制型別轉換并不改變記憶體中任一二進制位,只改變了我們如何去解釋該二進制數字,沒有改變記憶體中的資料,(強制型別轉換的本質)
7.#define _CRT_SECURE_NO_WARNINGS要放在(頭)檔案的最前面或者采用#pragma warning(disable:4996) (后者可以不放在最前面)
8.使用getchar()函式時要注意輸入緩沖區的存在,getchar()先檢索輸入緩沖區中有沒有字符,如果沒有,才會把輸入的字符加載進去,尤其注意我們通常輸入的間隔符可能就會因為我們代碼的不嚴謹而被加載到緩沖區中,
9.define不是關鍵字,是一個預處理指令,可以作為變數名,但關鍵字不可以
10.在未宣告時不能用其它.c檔案里的全域變數,如果要使用,需要用extern(關鍵字,專門用來宣告外部符號的,用法為 extern 型別 變數名,全域變數的作用域是整個工程,生命周期是在程式的運行期間,而static修飾了全域變數后,就使全域變數只能在定義的檔案內使用,即使在其它檔案中用extern宣告后也不能使用)進行宣告,
一個全域變數在整個工程的其它檔案內部中可以被使用是因為全域變數具有外部鏈接屬性,當一個全域變數被static修飾后,這個變數的外部鏈接屬性就變為了外部鏈接屬性就變成了內部鏈接屬性,使得這個全域變數只能在自己的源檔案內使用,其它檔案不能使用,給人感覺作用域變小了,生命周期沒有變化,存盤位置也沒有發生變化,
11.記憶體空間的單位是位元組,
12.鍵盤輸入的內容,或者往顯示幕中列印的內容,全部都是字符,從printf()的回傳值即可得出,因為printf的回傳值就是輸出字符的數目,就像getchar()輸入1234,就可以通過printf()進行輸出后得到1234,事實上,1234是四個字符,
13.任何C程式,在默認編譯好之后,運行時,都會打開三種輸入輸出流:
stdin:標準輸入 FILE* stdin 鍵盤
stdout:標準輸出 FILE* stdout 顯示幕
stderr:標準錯誤 FILE*stderr 顯示幕
14.for(;;)將構成死回圈,
15.了解編譯和鏈接,
(1)什么是編譯和鏈接?
編譯是為了將函式變數等變成,o二進制的機器碼格式,鏈接是為了將各個獨立分開的二進制的函式鏈接起來形成一個整體的二進制可執行檔案,
(2)編譯和鏈接以什么為單位?
編譯以檔案為單位、鏈接以工程為單位,
編譯器編譯時會將所有源檔案依次讀出來,以每個檔案為單位進行編譯,因此編譯不會考慮其他的檔案,顯然這樣就簡化了編譯器的設計,
鏈接的時候實際上是把第一步編譯生成的.o檔案作為輸入,然后將它們鏈接成一個一個可執行程式,第一步有多少.c檔案,編譯時就會有多少個.o檔案,鏈接后多個.o檔案就會變成一個可執行檔案,
(3)三種鏈接屬性:外鏈接、內鏈接、無鏈接
外鏈接:外鏈接就是需要的函式與變數可以在外部檔案找到,通俗說就是可以被跨檔案訪問,
內鏈接:與外鏈接相反,需要的函式和變數在當前的檔案的內部就可以找到,或者說具有內部鏈接屬性的變數只能在檔案內部被訪問,static修飾全域變數和函式都是內鏈接的,
無鏈接:這個符號本身不參與鏈接,它跟鏈接沒有關系,區域變數(auto、和被static修飾的區域變數)都是無鏈接的,
(4)函式和全域變數的命名沖突問題
extern修飾的全域函式和全域變數都是外鏈接的,這些函式和變數在整個程式的所有.c檔案中都是可以被訪問到的,因此對于外部鏈接的全域函式和全域變數來說,避免命名沖突是非常重要的,特別是在一個大型的工程專案中,不出現相同的名字是很難做到的,所以在C++中給出了解決方案,就是使用命名空間namespace的方式,通俗點就是給一個變數帶上各個級別的前綴,不過C語言中并沒有這種方法,但是C語言也有自己的解決方案,就是使用之前的外鏈接、內鏈接和無鏈接這三種屬性的方法,
C語言的解決方法是這樣的,我們將明顯不會再其它C檔案中參考的全域變數/函式,使用static修飾使其成為內鏈接,這樣在將來鏈接時,即使2個.c檔案有重名的全域函式/變數,只要其中一個或兩個為內鏈接就不會沖突,當然這種解決方案在一定程度上解決了這個問題,但是并沒有從根本上解決問題,因此留下了一些瑕疵,今后我們在用C語言寫大型專案時要格外注意命名問題,
(5)運用上面的知識分析運用static修飾全域變數和全域函式
當我們使用static修飾全域變數和全域函式的時候,他們的作用范圍就被鎖在了本檔案內,其它檔案在鏈接時無法使用這些函式和全域變數,這就是由原來的外鏈接屬性變成了內鏈接屬性,同時有限避免了函式和全域變數的命名沖突問題,
16.定義域和生命周期的概念
作用域概念:指的是該變數的可以被正常訪問的代碼區域(區域性的概念)
生命周期的概念:變數的創建到變數的銷毀之間的一個時間段(時間上的概念)
17.全域變數,是可以跨檔案被訪問的,
全域函式,是可以跨檔案被訪問的,
18.源反補的轉換方法
原碼:直接將二進制按照正負數的形式翻譯成二進制就可以, 反碼:將原碼的符號位不變,其他位依次按位取反就可以得到了, 補碼:反碼+1就得到補碼,
19.正數的源反補相同,負數的源反補按照上面步驟進行轉換!
20.在計算機系統中,數值一律用補碼來表示和存盤,原因在于,使用補碼,可以將符號位和數值域統一處理; 同 時,加法和減法也可以統一處理(CPU只有加法器),此外,補碼與原碼相互轉換,其運算程序是相同的,不 需要額外的硬體電路,計算也是用補碼進行計算的!
(5)運算子
取模運算子%只能用于整數,即兩側只能是整數,
1、關鍵字
1.switch
(1)switch后面跟整型變數、常量、整型運算式(只能為整型或者字符型)
(2)switch陳述句中,switch陳述句本身沒有判定和分支功能,case完成的是判定功能,而break完成的則是分支功能,一定不要忘記加上default!必須要帶!(代碼具有更好的健壯性),這是作為一個優秀程式員的自我修養!
(3)case后面如果想要定義變數(注意是定義而不是賦值),需要加{},可以在代碼塊內進行定義,當然,在case陳述句中變數也只能在代碼塊內進行定義,在case之后可以執行多條陳述句,不用{}也可以,但最好加上,或者直接封裝為函式,
(4)default可以放在任意位置,可以放在case前,case中間,case最后都沒有任何的影響,但習慣上將default放在最后,
(5)case后面不要用return,雖然說編譯器不會報錯,但我們要搞清楚return 的作用,return的作用是直接退出程式,回傳值為0,而break的作用是退出回圈或者switch陳述句,我們要搞清楚這一點,如果你用了return并且成功匹配,那么程式就不會執行switch后面的陳述句,有興趣自己試一下,
(6)不要在switch后面的括號內出現bool值,雖然說程式也不會報錯,但我們并不推薦這樣,因為()里面我們通常得出的是整型數值,bool型別可以正常運行的原因是c99和c90標準下的vs 2019把true默認為是1,把false默認為是0,這些同樣是作為一個優秀程式員的自我修養!
(7)case后面要跟真的常量,const修飾的常變數是無法編譯通過的,
(8)建議case后面要有好的布局方式,從小到大,以及把最容易匹配到的放在最前面,
(9)switch后面{}內的陳述句位于case和default外面的無法進行執行,無論是定義變數的陳述句還是其它如printf()之類的輸出陳述句,
2.關鍵字總覽(不需要記,認識即可)
auto 宣告自動變數
short 宣告短整型變數或函式
int 宣告整型變數或函式
long 宣告長整型變數或函式
float 宣告浮點型變數或函式
double 宣告雙精度變數或函式
char 宣告字符型變數或函式
struct 宣告結構體變數或函式
union 宣告共用資料型別
enum 宣告列舉型別
typedef 用以給資料型別取別名
const 宣告只讀變數
unsigned 宣告無符號型別變數或函式
signed 宣告有符號型別變數或函式
extern 宣告變數是在其他檔案正宣告
register 宣告暫存器變數
1.什么樣的變數,可以采用register呢?
(1)區域的(全域會導致CPU暫存器被長時間占用,影響程式運行效率)
(2)不會被寫入的(寫入就需要寫回記憶體,后續還要讀取檢測的話,register的使用將沒有意義)
(3)高頻被讀取的(提高效率)
(4)如果要使用,不要大量使用,因為暫存器數量有限,而且并非每一次宣告計算機都將變數存入記憶體中,程式員做的只是建議
2.register修飾的變數,無法取地址,因為地址是記憶體上的概念,而暫存器上沒有地址的概念
static 宣告靜態變數
作用:
1、修飾變數
(1)修飾全域變數,該全域變數只能在本檔案內被使用,
(2)修飾區域變數,變數的生命周期變成全域周期(和全域變數將一樣,但作用域不變)(同時存盤的空間發生變化,由原來的堆疊區到了全域區(靜態區))
volatile 說明變數在程式執行中可被隱含地改變
void 宣告函式無回傳值或無引數,宣告無型別指標
if 條件陳述句
else 條件陳述句否定分支(與 if 連用)
switch 用于開關陳述句
case 開關陳述句分支
for 一種回圈陳述句
do 回圈陳述句的回圈體
while 回圈陳述句的回圈條件
goto 無條件跳轉陳述句
continue 結束當前回圈,開始下一輪回圈
break 跳出當前回圈
default 開關陳述句中的“其他”分支
sizeof 計算資料型別長度
return 子程式回傳陳述句(可以帶引數,也可不帶引數)
2、分支和回圈
1.在使用if條件判斷時需要注意一個小小的點,就是很多運算式和函式往往是由自己的回傳值的,例如if(a=0)這樣寫的話,后面的代碼塊就不會執行,因為()內的回傳值為0,所以不會執行,
2.if進行條件判斷時,把常量放在左邊
3.else匹配總是采取就近原則,與上面最近的一個if進行匹配,(所以帶花括號)
if里面得到的最好是一個bool值,不要用賦值運算式之類的,
所有的else if陳述句最好是由else結束,
4.do while陳述句建議書寫格式像這樣:
do {
}while();這個陳述句的回圈變數初始化在do之前!
5.while()執行的順序和if()執行的順序是一樣的,不同的是執行完之后會回傳到while()陳述句進行重新執行,前面的
定義并初始化是回圈田間初始化,()里的內容是回圈條件判定,{}里的內容是回圈條件更新,for()回圈使將條件初始化,條件判定,條件更新放在一個()內,,語法結構比較緊湊,
3、函式
4、陣列
1.陣列在定義的時候可以選擇不初始化,或者放0也可以,
2.if后面雖然說跟單挑陳述句時可以不帶大括號,但我們在使用的時候,必須要帶大括號,因為在條件判斷后只跟一條陳述句的情況時相當少的,
5、指標
1.指標變數的名字不帶*,我們通常所說的某某是一個指標,其實是一個指標本身,比如int *p =&a; p是變數名,而不是*p,
2.指標的大小跟系統有關,32位的環境下有32根地址線,指標大小為4個位元組,64位的環境下有64根地址線,指標大小為8個位元組,(X86:編譯出來為32位程式,X64編譯出來為64位程式),
3. * 運算子也叫解參考運算子,間接訪問運算子,
6、結構體
1.定義結構體時,結構體中[]內的數字不能省略,必須明確指定,因為初始化才不用寫,
2.給結構體變數賦初值時可以直接這樣struct Stu zhangsan = {0};后面可以進行再賦值,不然列印出來的資料都是0,
7、資料的存盤
8、字串
1.’\0'是字串的結束標志,在用sizeof進行計算時也算一個位元組,strlen()則不會把它計入(因為strlen()和printf函式在遇到'\0'就會自動停止了,(sizeof計算的的是變數所占記憶體空間的大小,而strlen()計算的是從變數的起始地址開始,到'\0'結束標志為止的字符的數目),
2.字串定義的兩種方式:
char arr1[] = "bit";([]內可以加數字限定,但不要忘記'\0'也占用一個字符(’\0'編譯器會自己加上) char arr2[4] = {'b', 'i', 't'}; char arr3[] = {'b', 'i', 't', '\0'};(2和3兩種定義方式要么在末尾加上’\0'為結束標志,要么加上字串長度限定符(加限定符不要忘了還有'\0'為字串結束標志,也占用一個位元組長度,這個結束標志在限定了字串長度后編譯器會自己加上)
9、動態記憶體管理
10、檔案操作
11、程式的編譯(預處理)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/335454.html
標籤:其他
上一篇:二叉樹的詳解(你值得擁有)
下一篇:FPGA實作按鍵切換數碼管界面
