c語言在編程語言中是偏底層的語言,像JavaScript,以及java。都是在c語言的基礎上編譯出來的。像操做系統:unix ,linux ,windows都是依靠c語言開發出來的,使用c語言能夠開發windows應用程序。在c語言中不像在javascript中那麼隨意,在c中每寫一條語句都必需要以 ; 進行結尾。javascript
c語言的編碼方式,在用char類型聲明的窄字符會使用到Ascll碼,用char類型聲明的窄字符串和在Wchar_t聲明的寬字符和寬字符串都不使用Ascll碼,對於wchar_t聲明的寬字符和寬字符串通常使用UTF-16和UTF-32進行編碼的,對於char類型聲明的字符串是根據編譯器或者源文件的編碼方式去編碼的因爲編譯器的不一樣使用的編碼也不一樣 。html
c語言的數據類型大致分爲如下四種:java
基本類型linux
基本類型又分爲下邊這幾種:編程
整型windows
整型用: int 進行表示在內存中佔4字節 數組
整型又分爲下這兩種:緩存
長整型編程語言
長整型用: long 進行表示在內存中佔8字節 編輯器
短整型
短整型用: short 進行表示在內存中佔2字節
浮點型
浮點型又分下邊這兩種:
單精度浮點型
單精度浮點型用: long 進行表示在內存中佔4字節
雙精度浮點型
雙精度浮點型用: short 進行表示在內存中佔2字節
字符型
字符類型使用 : char 進行表示在內存中佔1字節
這種用char代表的字符類型還有一種名稱叫窄字符。
像這個char只能處理ASCLL碼有的在字符處理不了中文以及其餘語言的字符
枚舉類型
void類型:
在javascript中void是一個運算符 它用於計算它旁白的表達式,不管表達式是什麼它老是返回的是undefined
void在C語言中它是無類型的也就是沒有類型的。
複合類型
對於數據類型轉換又分爲如下兩種:
自動類型轉換:
自動類型的轉換是不須要咱們去幹預的,好比在賦值運算中,右邊表達式的值與左邊的數據類型不一樣會自動將右邊表達式轉換爲跟左邊同樣的類型。
強制類型轉換:
強制類型轉換是咱們本身去進行的轉換轉換方式式這樣的:(新類型) 表達式
對於自動和強制類型轉換都只是根據需求時去進行的臨時轉換,它們不會實際的改變數據的類型。
c語言中聲明變量是這樣的 : 數據類型 變量名=值
還能夠 數據類型 變量名; 變量名=值
在c語言中聲明變量時的變量名不只僅表示它後邊的值它還表示它的值在內存中的地址, &變量名 這個&變量就是這個變量的值在內存中的地址。*變量名錶示一個存儲單元裏的數據。
注:字符類型的變量的值要用 '' 包裹而且只能一個字符。c語言中變量能夠從新賦值可是不能一個變量聲明兩次。(在js中的ES5的語法中用var聲明的變量能夠聲明兩次且不會報錯,在ES6語法中變量不能聲明兩次不然會報錯)
運算符基本上和js中的差很少。
基本運算符:
加法,減法,除法,乘法,取模運算,自增,自減
關係運算符:
大於,等於,全等,大於等於,非等於
邏輯運算符:
且,或,非
以上這些運算符和js中的同樣進一步瞭解可參考:juejin.im/post/5ce109…
輸入和輸出分別使用如下這幾個函數
輸入: scanf()
這個scanf輸入函數基本上跟printf差很少只不過一個是輸入一個是輸出,它裏邊也有格式控制符 。 例:scanf("%d\n" , &a) 這個就是輸入前邊用""包裹是格式控制符,後邊的是a是變量 & 是符號,意思是將輸入的值賦值給變量a,這個函數是當用戶輸入完成時會將用戶輸入的值存進緩存區,當用戶按下回車時纔會讀取
字符以及字符串的輸入使用如下這幾個函數
單個字符的輸入使用:getchar()函數它用於輸入單個字符,例:char isd=getchar(),這個函數也是當用戶輸入完成時會將用戶輸入的值存進緩存區當用戶按下回車時纔會讀取。
輸入字符串用這個函數 : gets() 括號裏寫你須要將用戶輸入的值賦值給哪一個變量。例: gets(asd) 這個表示將用戶輸入的值賦值給asd這個變量。雖然scanf()也能用於輸入字符串只需寫上格式控制符%S便可,但scanf遇到空格時會認爲輸入結束了,gets會將空格認爲字符串的一部分。
輸出: printf()
這個是格式化輸出函數,在輸出的函數中這個是最經常使用的,這個printf中格式控制符具體能夠查看printf輸出函數格式化控制符詳解,例: print("%d\n",a) 這個括號裏前邊用""包裹的就是格式控制符,後邊的是變量
c語言中的判斷語句基本上和js中的差很少,
c語言中的判斷語句大體有如下幾種:
當設置判斷的條件時就要用到上邊的關係運算符,注意:在js中有boolean值ture和false在c語言中沒有這個概念在c語言中0爲false,非0爲true。
if else
if(條件){
條件爲真時執行這裏的代碼;
複製代碼
}else{
條件爲假時執行這裏的代碼;
複製代碼
}
if else if
條件爲真時執行這裏的代碼;
複製代碼
}else if(條件2){
當條件1爲假時進行下一步判斷條件2條件2爲真時執行這裏的代碼;
複製代碼
}
switch
switch大多用於在多條件判斷時
case 1 :當變量等於1時執行這裏的代碼;break;
case 2 :當變量等於2時執行這裏的代碼;break;
case 3 :當變量等於3時執行這裏的代碼;break;
case 4 :當變量等於4時執行這裏的代碼;break;
case 5 :當變量等於5時執行這裏的代碼;break;
case 6 :當變量等於6時執行這裏的代碼;break;
default:當變量不知足以上條件時執行這裏的代碼;break;
複製代碼
}
注:例子裏邊的變量能夠是用戶輸入的變量 而後case是固定格式 case後邊必須是整數或者整數的表達式,break必須寫,break的意思是當變量知足某個時執行完代碼後講跳出判斷再也不繼續向下判斷,最後的default是可寫可不寫的default的意思是當變量不知足以上全部條件時將執行default那的代碼。
三元運算符,這個也是一種判斷語句,主要用於一個條件的判斷
c語言中的循環跟js中的循環也幾乎都同樣。
while循環
當知足條件時執行這裏的代碼,
若是條件一直知足會一直執行這裏邊的代碼直至不知足條件將跳出循環
複製代碼
}
當條件一直知足時會一直執行代碼成爲死循環。
do{}while()
要循環執行的代碼
複製代碼
}while(條件)
do while循環實際與while差很少只有一點不同,while循環會先判斷條件再去執行代碼若是條件不知足則不會執行代碼,do while循環會先執行一遍代碼而後再區進行條件的判斷,條件爲真則繼續執行代碼條件爲假則再也不繼續執行代碼。
for循環
注意:在for循環中若是不帶{},好比:for(語句1;語句2;語句3)那麼它會將下一條帶分號的語句座位循環體。
注:在循環中有一個break關鍵字用來跳出循環一般跟判斷語句結合使用。還有continue關鍵字是跟if esle 結合使用當continue會跳出當前循環強制進入下一次循環。
注:在c語言中的數組是靜態的也就是說數組不能向數組內部進行增長和刪除功能,而在js中數組向數組內部進行增長和刪除功能的這種數組叫作動態數組。
咱們把一組數據的集合叫作數組,c語言中的數組跟js中的數組略有不一樣。
數組有如下幾種類型:
例 : int a[4];這樣就聲明瞭一個整型數組它的長度爲4,它的每個元素都爲一個整型。
數組的賦值方法有如下幾種:
咱們一般還經過for循環來爲數組賦值。
注意:聲明數組時數組名前面的類型時什麼類型那麼數組裏的每一個元素就爲何類型。若是數組中的某個元素未賦值那麼他的值默認爲0。/p>
能夠把二維數組當成一個表格,它有行有列,
二維數組的賦值:
也能夠經過for循環來爲二維數組賦值。
字符數組
js中有string類型的被稱爲字符串,而c語言中沒有字符串的概念只有單個字符因此在c語言中咱們把一串字符串稱爲字符數組。
字符數組的定義是這樣的:
char 字符串名 [字符串長度]="這裏是你的字符串"
另外在c語言的字符串中要以\0去進行結尾不然這個字符數組是沒有結尾的。
咱們能夠引入< string.h >頭文件而後利用strlen(字符串名)來求出字符串的長度,另外字符串的長度不包括最後結尾的\0。
另外輸出字符串有兩種方式:printf("%s\n",字符串名)和puts(字符串名)
輸入字符串也有兩種方式scanf("%s",字符串名)和gets(字符串名)
輸入字符串的這兩種方式有必定的區別,經過scanf()輸入的字符串遇到空格就會認爲字符串結束了而gets()不會。可是scanf()能夠指定字符串輸入的類型,
c語言向咱們提供了對於字符串的處理函數不過這些函數是包含在string.h的頭文件中的咱們必需要先引入< string.h >頭文件才能使用這幾個函數這幾個函數分別是如下幾個:
strcat(x,y)
strcat(x,y)函數是用來進行字符串拼接的只要咱們在strcat的函數裏寫上兩個參數x和y那麼y的字符串就會拼接到x字符串的後邊,不過前提是x字符串在內存中所佔用的空間可以同時存放下x和y兩個字符串的空間不然會出現數組越界的問題。
strcpy(x,y)
strcpy(x,y)函數是用來拷貝字符串的只要咱們在strcpy(x,y)函數中寫上兩個參數x和y那麼x字符串的內容就會被y字符串的內容覆蓋掉。可是前提是x字符串在內存中佔用的空間可以存放下y字符串的內容不然就會拷貝的不全面。
strcmp(x,y)
strcpy(x,y)是字符串的比較函數,字符串自己是沒有大小的咱們對字符串進行比較是比較ascll值從兩個字符串的第一個字符開始一一比較若是x字符串跟y字符串相同那麼返回0若是x字符串大於y字符串那麼返回大於0的值若是x字符串小於y字符串那麼返回小於0的值。
數組的越界:
數組中的一項元素都是有它的下標的當咱們去訪問數組中沒有該下標的內容時會發生數組越界的問題,一旦數組越界編譯器在編譯時就不能進行正常編譯還會報給咱們一些徹底看不懂的報錯。
數組的溢出:
當數組的長度大於咱們定義數組時數組的長度時就會產生數組溢出的問題,當咱們的數組溢出時編譯器在編譯時會給咱們報錯,正常的數組溢出就是在輸出數組時多出去的部分會被丟棄可是若是是字符串形式的數組溢出時咱們還輸出數組時編譯器可能會正常經過可是輸出的就不是正常的了,因此咱們在定義數組和給數組賦值時要細心避免數組溢出的翁提發生。
其實c語言中的函數也基本上都跟js中的同樣可是在c語言中只有一個主函數且只會執行這一個主函數。
在c語言中函數有如下兩種:
第一種是c語言提供給咱們的函數,c語言有15個頭文件被稱爲標準庫,這些庫裏邊給咱們提供了豐富的函數供咱們能夠去直接去調用。
第二種是咱們本身去定義的一個函數咱們在.c文件中能夠本身去定義一個函數而後去進行調用。
在c語言中咱們都會見到這樣的結構
例: int main(){函數體;
return 0;
複製代碼
}
這個main函數就是c語言的主函數且c語言只會執行這一個主函數,main函數能夠去調用其餘函數可是卻不能它自身卻不能被任何函數去調用。咱們能夠在主函數上方或者主函數內部去自定義函數而後再主函數主區調用自定義函數。
c語言去定義一個函數是這樣的,函數類型 函數名(參數){
函數體
return 變量;//這個return時函數在去調用時函數的返回值,在咱們去定義函數時函數時什麼類型的那麼函數的返回值就是什麼類型的
複製代碼
}
c語言中函數去調用時這樣調用的:
函數名(參數)
另外在c語言中函數也是有做用域的全部在函數內部包括主函數聲明的變量都是局部變量,在函數函數外邊聲明的變量被稱爲全局變量。
在c語言中函數也有遞歸遞歸函數,關=關於遞歸函數通俗的解釋就是在函數內部去調用函數自己。
在咱們去編寫.c文件時都會在代碼的第一行去寫 #include <頭文件>。像這種以#開頭的命令就叫作預處理命令。咱們寫的每一個.c的文件都是一個可執行程序的源文件,只有咱們經過編譯器去將咱們的.c文件去進行編譯的時候纔會生成一個可的執行程序。#include是引入頭文件的命令一個#include只能引入一個頭文件,要引入多個頭文件就須要多個#include
在c語言的預處理命令中有宏的定義,咱們能夠把宏看成一個定義常量的用法由於咱們一旦使用了預處理指令去定義了一個值或者表達式那麼咱們在下邊是沒法改變的。宏是經過預處理指令來進行的關於預處理指令指令大體介紹如下幾種:
#include <頭文件>
這個指令是用來引入頭文件的
#define 自定義宏名字 字符串或者表達式
當咱們在代碼中用到這個自定義宏名時那麼這個自定義宏名會被替換成它後邊的字符串或者表達式。
用法:
#define 宏名(參數) 表達式或值
調用宏: 宏名(參數)
在c語言中指針是一個很重要的概念它表明了數據在內存中存儲的位置,在js中咱們的指針是this。
當咱們去聲明一個變量名爲a的變量時,int a=1; 它的值是存儲在內存中的它的變量名a就表明的是這個數據在內存中存儲的地址。而且這個變量名並非真正的地址它只是該數據在內存中存儲的地址的一種代稱罷了在咱們的編譯器去編譯的時候這些變量名都會被轉換成地址而後當咱們的編譯器去編譯時會找到這些變量名錶明的地址從而去獲取數據。
有了指針咱們能夠經過 *來定義指針變量不過*號的用法有如下幾種:
在運算符中在
在運算符中*號表示的是乘法
定義指針變量
當咱們去定義指針變量時咱們須要在變量名前加上*以表示它是一個指針變量
例:int *變量名;
給指針變量賦值:
例: int a=1; int *b=&a;
&a表示的是變量a在內存中存儲的地址。這時咱們去輸出*b那麼它的值就是變量a的數據在內存中所存儲的地址。咱們也稱爲b指向了a。
經過指針變量去修改內存中的數據
例: int a=1; int *b=&a; *b=12;
咱們知道這時候的b指向a,也就是*b表明了a的數據在內存中存儲的位置,可是當咱們去給*b從新賦值的時候咱們是給*b所表明的內存中的地址裏的數據修改了修改爲爲了給*b從新賦值的值。
數組指針:
咱們在定義數組要給出數組名和數組的長度,數組中的每一個元素在內存中的地址都是緊挨這個,一整個數組佔用的是一整快內存,這時咱們的數組名也表明的是一個地址不過它默認的是隻表明數組中下標爲0的元素所在內存中的地址。
若是一個指針指向了數據那麼咱們就稱它爲數組指針
例: int arr[10]=[1,2,3,4,5,6,7,8,9]; int *q=arr;
這時*p表明的是數組arr中的下標爲0的元素的地址咱們若是想訪問下一個元素可使*p++.在這可能會有疑問爲何在這不適用&arr,由於arr自己表明的就是一個地址了就不須要再去使用&去獲取它的地址了。
字符串數組指針:
上邊寫了字符串自己就是一種字符數組,只有用定義數組的方式能定義一個數組,可是經過指針咱們又引出了一種新的字符串的定義方式。
例:char zi="yuzhong"; printf("%s",zi);
咱們能夠經過指針的方式去定義一個字符串不過這種,這種指針叫作字符串指針,還有就是這種方式聲明的字符串稱爲字符串常量。雖然使用這種定義字符串可是它跟字符串數組上有着本質上的不一樣:1.這種方式定義的字符串叫作字符串常量它只能去讀寫但式不能去改變。2。存儲方式的不一樣使用字符串數組存儲再全局數據區或者棧區,字符串常量存儲再常量區不能進行更改。
何時能用到指針變量:(如下只是簡單的舉了兩個例子)
當作函數參數傳遞進去,咱們我已在在函數將經過指針將咱們須要的參數的地址傳遞進去,如下是一個最簡單的例子
例:int a=1,b=2; int one(int *a,int *b){
函數體
複製代碼
} one(&a,&b);
把數組傳遞給函數
咱們知道數組是一組數據的集合,它不能一次性的所有傳遞函數咱們能夠經過指針將數組傳遞進去而後對數組進行操做。
使用指針做爲函數返回值:
c語言容許函數的返回值是指針咱們將這種返回值爲指針的函數稱爲指針函數
在c語言中還有二級指針的定義,什麼是二級指針?
咱們上邊寫的那種是叫作一級指針它直接指向某個變量的地址裏邊的內容。在c語言中咱們把*變量名叫作一級指針,**變量名叫作二級指針,***變量名叫作三級指針前邊有幾個星號就是幾級指針
#include <stdio.h>
int main(){
int one =10;//這是一個變量one
int *two=&one;//變量two前邊有星號且它的值爲&one,&one表示的是變量one的值在內存中的地址而後*two指向這個變量one的地址也就至關於變量two就是one的值
int **three=&two;//變量three前邊有有兩個星號且它的值爲&two,&two表示的是變量two的值在內存中的地址而後**three指向這個變量two的地址也就至關於變量three就是two的值
int ***four=&three;//變量four前邊有有三個星號且它的值爲&three,&three表示的是變量three的值在內存中的地址而後***four指向這個變量three的地址也就至關於變量four就是three的值
printf("%d",***four); //這裏最後輸出的是變量one的值。
return 0;
}
複製代碼
在js中咱們的數據類型中有一種類型叫作null,就是表示爲空。注意在js中不要把null和undefinde搞混由於undefinde表示未定義而null表示爲空。在c語言中null也表示爲空只不過它不是數據類型而是指針,null就是表示空指針。像下面這段代碼:
#include <stdio.h>
int main(){
int *one;
gets(one)
printf("%d",one);
return 0;
}
複製代碼
像這段代碼咱們就是聲明瞭一個指針變量可是卻沒有給他賦值,這段代碼是錯誤的可是能編譯成功,若是咱們使用的是文本編輯器進行編輯的這段代碼而且使用了gcc進行編譯能編譯成功可是輸出出的東西確實未知的。若是使用VS進行編譯調試那麼會給咱們報錯。
還有就是當咱們去聲明一個變量時可是未對變量就行賦值卻選擇輸出了這個變量會給咱們報錯。咱們能夠在聲明變量時給變量賦值爲NULL,注意在js中給變量賦值爲NULL不區分大小寫可是在c語言中NULL必定要是大寫。當咱們把變量賦值爲NULL再進行輸出就會輸出(null)
void* 上邊提過void是一個沒有類型的也就是類型是不肯定的可是void*指針是一個指針它也指向了內存裏的某個地址的數據可是內存裏的數據類型是不肯定的因此咱們在使用void*指針時要進行類型轉換。