C語(yǔ)言入門(mén)
C語(yǔ)言
編程重要的是思維而不是語(yǔ)法
在開(kāi)始學(xué)習(xí)編程之前,首先我們要先明確一件事,就是學(xué)編程重要的是思維而不是語(yǔ)法。
語(yǔ)言只是工具,思維才是本質(zhì)。
工具只是便捷你的工作與提高你的效率,但真正決定你能否解決問(wèn)題的是你的思維方式.
就好比做幾何題的時(shí)候,垂直平行等那套數(shù)學(xué)符號(hào)語(yǔ)言(工具)真的重要嗎?
那只是一種表述方式而已,不會(huì)那套數(shù)學(xué)符號(hào)還可以寫(xiě)文字描述和算式。
決定你最終能否解答這道題的還是你是否有解題的思路。
編程也是如此。
模塊化概念
在編程學(xué)習(xí)開(kāi)始之前,我們還需要了解一個(gè)概念,就是模塊化。
c語(yǔ)言是一個(gè)模塊化的語(yǔ)言,這個(gè)模塊化體現(xiàn)在很多方面,比如函數(shù),比如結(jié)構(gòu)體,比如多文件。
一個(gè)c語(yǔ)言程序,就是由一個(gè)個(gè)變量拼成結(jié)構(gòu)體,一個(gè)個(gè)結(jié)構(gòu)體與函數(shù)拼成文件,最后再由一個(gè)個(gè)文件拼成最后的整個(gè)程序
任何一個(gè)C語(yǔ)言程序都是由一個(gè)或者多個(gè)程序段構(gòu)成,每個(gè)程序段分別負(fù)責(zé)各自的功能,最后由主程序段統(tǒng)合到一起形成可以執(zhí)行的程序。 ——這種負(fù)責(zé)某一部分功能的程序段我們通常稱(chēng)之為“函數(shù)”。
主函數(shù)
電腦計(jì)算機(jī)執(zhí)行程序總要有個(gè)開(kāi)始,總要有個(gè)第一行。
前面提到過(guò)c語(yǔ)言中每個(gè)程序段分別負(fù)責(zé)各自的功能,那么計(jì)算機(jī)執(zhí)行的時(shí)候又怎么能知道先執(zhí)行哪里后執(zhí)行哪里呢?
為了解決這一問(wèn)題,我們需要有一段程序來(lái)做各個(gè)程序段的統(tǒng)合
這個(gè)程序也就是main函數(shù)
也就是說(shuō),如果你寫(xiě)的程序要運(yùn)行的話(huà),一定要有一個(gè)main函數(shù)
那么main函數(shù)如何寫(xiě)呢?
為了解決這一問(wèn)題,我們需要了解一下函數(shù)的結(jié)構(gòu)。
函數(shù)的結(jié)構(gòu)
前面提到,一個(gè)c語(yǔ)言程序,就是由一個(gè)個(gè)變量拼成結(jié)構(gòu)體,一個(gè)個(gè)結(jié)構(gòu)體與函數(shù)拼成文件,最后再由一個(gè)個(gè)文件拼成最后的整個(gè)程序。
那么函數(shù)是怎么樣的呢?這里我們以不可或缺的主函數(shù)為例
void main()
{
//代碼內(nèi)容
}
這就是一個(gè)最簡(jiǎn)化的函數(shù)(當(dāng)然我們通常不用void,這里只是為了方便理解)
這個(gè)函數(shù)的結(jié)構(gòu)是這樣的
void main() // 返回值類(lèi)型 函數(shù)名(參數(shù)列表) 表示創(chuàng)建一個(gè)函數(shù)
{ //代碼塊開(kāi)始
//代碼塊可以簡(jiǎn)單理解為我們要運(yùn)行的一段代碼
} //代碼塊結(jié)束
這里的void是指返回值的類(lèi)型,void表示沒(méi)有返回值,為什么函數(shù)需要返回值呢?因?yàn)槲覀冊(cè)趫?zhí)行一個(gè)函數(shù)的時(shí)候通常是需要它來(lái)實(shí)現(xiàn)某個(gè)功能的,如果沒(méi)有返回值我們就不知道它有沒(méi)有成功執(zhí)行,或者不知道它的執(zhí)行結(jié)果了(譬如執(zhí)行開(kāi)平方以后我們沒(méi)有收到返回值,平方是開(kāi)完了,但是結(jié)果捏?????)
而且有些時(shí)候我們的系統(tǒng)在執(zhí)行函數(shù)的時(shí)候也強(qiáng)制要求返回值(一些系統(tǒng),不是所有系統(tǒng))
綜上,我們的程序最好提供一個(gè)返回值
因此在事實(shí)上我們的一個(gè)函數(shù)表達(dá)出來(lái)其實(shí)是這樣的
類(lèi)型名 main(){
//函數(shù)內(nèi)容
return 數(shù)值;
}
這里的類(lèi)型名常用的有 int char double long short float bool
分別對(duì)應(yīng)為整數(shù),字符,雙精度浮點(diǎn)數(shù),長(zhǎng)數(shù),短數(shù),浮點(diǎn)數(shù),浮點(diǎn)數(shù)就是帶小數(shù)點(diǎn)的數(shù),計(jì)算機(jī)處理浮點(diǎn)數(shù)有誤差,double比f(wàn)loat精準(zhǔn)一些
這里我們所寫(xiě)的函數(shù)名字叫main,也就是前文提到的主函數(shù)
由于是主函數(shù),所以我們的返回值自己是沒(méi)有辦法用到了,但是有的計(jì)算機(jī)系統(tǒng)可能會(huì)要求,因此通常的寫(xiě)法是返回一個(gè)0,代表程序正確執(zhí)行完成,此時(shí)我們的程序就變成了
int main() //創(chuàng)建一個(gè)返回值為整數(shù)的函數(shù) 名為main 傳入?yún)?shù)列表為空
{
//函數(shù)內(nèi)容
return 0; // 返回整數(shù) 0
}
這里我們運(yùn)行一下這個(gè)程序給大家看看結(jié)果
(展示)因?yàn)槲覀兒瘮?shù)內(nèi)容什么都沒(méi)有寫(xiě),所以也什么都沒(méi)有顯示
那么怎么證明我們的程序真的執(zhí)行成功了呢?我們?cè)僭黾右恍杏糜陲@示的指令
#include <stdio.h>
int main() //創(chuàng)建一個(gè)返回值為整數(shù)的函數(shù) 名為main 傳入?yún)?shù)列表為空
{
printf("hello world");//顯示hello world
return 0; // 返回整數(shù) 0
}
注意!C語(yǔ)言函數(shù)里的語(yǔ)句結(jié)束后需要以英文分號(hào)結(jié)尾,每一句都需要
printf是c語(yǔ)言里的打印(顯示到屏幕)語(yǔ)句,這句話(huà)的意思是顯示hello world
加上之后我們?cè)賮?lái)運(yùn)行一下(展示)程序就會(huì)顯示輸出hello world
加上以后我們的命令后就顯示出了我們要顯示的內(nèi)容,這證明本喵剛才認(rèn)真講了沒(méi)有胡說(shuō)八道(驕傲)
可能剛才有銀還意識(shí)到一個(gè)問(wèn)題,就是剛才的程序比上面說(shuō)的多了一行
#include <stdio.h>
這一句的意思又是什么呢?
后面加的字符是c語(yǔ)言里的預(yù)處理指令,就是編譯器程序執(zhí)行前預(yù)先處理的指令,用來(lái)補(bǔ)足程序運(yùn)行中需要的一些東西
這個(gè)#include就是包含頭文件的意思
#include <stdio,h>
的意思就是這個(gè)程序要包含文件stdio.h里面的內(nèi)容,stdio.h是c語(yǔ)言編譯器自帶的一個(gè)頭文件,包含了輸入輸出的函數(shù)之類(lèi)的一些常用的功能函數(shù),printf()其實(shí)也是一個(gè)函數(shù),它在stdio文件里面,我們使用的printf就是調(diào)用了程序外部文件stdio.h里面的print函數(shù)。
剛才咱們已經(jīng)說(shuō)了,c語(yǔ)言由很多函數(shù)構(gòu)成,下面咱們?cè)俣x一下別的函數(shù)來(lái)個(gè)多函數(shù)的程序
#include
int die()
{
printf(" bay~ world " );
return 0;
}
int main()
{
die();
return 0;
}
由于這個(gè)不是主函數(shù)了所以函數(shù)名就可以自己起了,不過(guò)這里要注意,函數(shù)名不能和關(guān)鍵字(c語(yǔ)言里面已經(jīng)被占用的詞)同名
這里我們起名die
這里左下角就正確顯示了
這里是先定義了die函數(shù)然后在主函數(shù)里面調(diào)用了它
die();
就醬,我們寫(xiě)了一個(gè)多個(gè)函數(shù)的c語(yǔ)言程序,(在學(xué)習(xí)編程的初期可以先不用考慮多文件,先從一個(gè)文件寫(xiě)起)
這里要注意!我們使用的程序要在使用的地方之前出現(xiàn),例如dnlm函數(shù)在main函數(shù)之前
然后下面我們講一坨選擇分支結(jié)構(gòu)
選擇分支
這個(gè)選擇分支結(jié)構(gòu)它是這個(gè)樣子的
if()
{
//如果條件成立執(zhí)行
}
else
{
//如果條件不成立執(zhí)行
}
這里我們添加一個(gè)丟乃老父并且聲明母親父親兩個(gè)整數(shù)來(lái)測(cè)試一下
#include
int dnlm()
{
int a=30;//聲明整數(shù)a等于30
int b=20; //聲明整數(shù)b等于20
if a>b) //如果a大于b
{
printf(" a" ); //顯示
}
else //否則
{
printf(" b" ); //顯示
}
return 0;
}
int main()
{
dnlm();
return 0;
}
運(yùn)行結(jié)果正確的顯示在了左下角。
這樣一來(lái)證明我們的選擇結(jié)構(gòu)發(fā)揮了它應(yīng)有的效果
剛才講完了選擇分支結(jié)構(gòu),這次我們從循環(huán)結(jié)構(gòu)開(kāi)始講,一課時(shí)之內(nèi)把c語(yǔ)言入門(mén)講完,然后看看時(shí)間能不能夠講一些其他的東西。
循環(huán)結(jié)構(gòu)
首先是while循環(huán),這是平常會(huì)經(jīng)常用到的一個(gè)循環(huán)
while(循環(huán)條件){ //代碼內(nèi)容}
while循環(huán)的結(jié)構(gòu)是這樣的,首先判斷循環(huán)條件是不是成立,例如循環(huán)條件是變量a>=2,那么當(dāng)a大于等于2的時(shí)候,就會(huì)執(zhí)行代碼內(nèi)容一次,然后再次判斷a是不是還大于等于2,如果是的話(huà)再執(zhí)行一次。直到有一次發(fā)現(xiàn)a不再大于等于2了,才結(jié)束循環(huán)開(kāi)始執(zhí)行循環(huán)外面的內(nèi)容。這樣一來(lái)的話(huà),實(shí)際上也就是說(shuō),我們?cè)趯?xiě)這種循環(huán)的時(shí)候,里面一定要寫(xiě)改變循環(huán)條件的代碼,否則循環(huán)條件一直不變就變成死循環(huán)了。
while循環(huán)是先判斷然后才決定執(zhí)不執(zhí)行的,所以while循環(huán)最少會(huì)執(zhí)行0次,也就是說(shuō)如果一開(kāi)始條件就不成立的話(huà)就一次都不執(zhí)行。
與之相對(duì)的是do。。。while循環(huán)
do
{
//代碼內(nèi)容
}while()
do。。。while和while相反,dowhile是先做了再說(shuō),做一遍到做完以后再判斷,是不是條件成立 ,條件成立的話(huà)繼續(xù)循環(huán),條件不成立的話(huà)到此為止,繼續(xù)往下執(zhí)行,do while循環(huán)是至少會(huì)執(zhí)行一次的循環(huán)。
與while系列循環(huán)用的同樣多的就是for循環(huán)了
for(i=100;i>=0;i--){ //代碼內(nèi)容}
for循環(huán)的條件分為三部分,第一部分是聲明控制循環(huán)的變量,比如聲明個(gè)i=100,第二個(gè)部分和while的控制條件一樣是用來(lái)判斷循環(huán)執(zhí)不執(zhí)行,最后一個(gè)部分是用來(lái)聲明控制變量的變化,就和while一樣,for也需要改變控制條件來(lái)防止死循環(huán),不過(guò)for直接在控制條件里就可以寫(xiě)好改變控制變量的語(yǔ)句。
以上是循環(huán)結(jié)構(gòu)的三種語(yǔ)句。
跳轉(zhuǎn)語(yǔ)句
下面進(jìn)行跳轉(zhuǎn)語(yǔ)句
c語(yǔ)言里的跳轉(zhuǎn)語(yǔ)句其實(shí)就是goto
語(yǔ)法也很簡(jiǎn)單,在任意一個(gè)地方立下flag,然后就可以隨時(shí)goto到這個(gè)地方了
lable1:
//此處省略?xún)砂偃f(wàn)億行
goto lable1
就可以直接飛回flag
goto用的好的話(huà)不僅可以跳轉(zhuǎn)還可以實(shí)現(xiàn)各種循環(huán),不過(guò)goto很容易出現(xiàn)不知道飛到了哪里去但是編譯器不報(bào)錯(cuò)導(dǎo)致查錯(cuò)人員頭比地球還大的現(xiàn)象,因此一般的來(lái)說(shuō),不建議使用goto語(yǔ)句。
數(shù)組
數(shù)組部分也很簡(jiǎn)單,其實(shí)就是把數(shù)據(jù)連起來(lái)存
我們平常聲明一個(gè)變量a,可以?xún)?chǔ)存一個(gè)數(shù)據(jù)。
我們現(xiàn)在聲明一個(gè)數(shù)組a[100],就可以?xún)?chǔ)存100個(gè)數(shù)據(jù)
數(shù)據(jù)類(lèi)型 數(shù)組名[數(shù)組長(zhǎng)度]
可以通過(guò)a[0-99]來(lái)分別使用這100個(gè)數(shù)據(jù),就不用寫(xiě)100遍聲明變量了,而且如果我們要查找的數(shù)有好幾個(gè)特點(diǎn),還可以使用二維或者多維數(shù)組。
比如a[1][2][3][4][5][6][7]就是七維數(shù)組里第二組的第三小組的第四小組的第五小組的第六小組的第七小組的第八個(gè)數(shù)
這里要注意數(shù)組里面排序序號(hào)是從零開(kāi)始的,第一個(gè)內(nèi)容的編號(hào)是0,所以數(shù)組名加數(shù)字實(shí)際訪問(wèn)到位置是數(shù)字加一的位置存的數(shù)據(jù)。例如a[0]其實(shí)是數(shù)組a的第一位。
從本質(zhì)上而言,數(shù)組其實(shí)就是一種指針的應(yīng)用方式。
指針
語(yǔ)言里面指針是核心精髓所在,所謂指針,就是指向數(shù)據(jù)儲(chǔ)存的地方。
我們平常聲明一個(gè)變量,a=100,大概就相當(dāng)于在白紙上劃了一部分叫做a區(qū),然后往里面記錄了一個(gè)數(shù)字100,100寫(xiě)在a這個(gè)地方。
這塊a區(qū)所在的位置就叫做a的地址
c語(yǔ)言里面和地址有關(guān)的有兩個(gè)符號(hào),一個(gè)是&,取地址符,一個(gè)是*,是指針的標(biāo)記(也是解引用符號(hào))
我們平常創(chuàng)建變量的時(shí)候是這樣的
int a;
我們創(chuàng)建指針變量時(shí)候是這樣的
int* p;
標(biāo)上一個(gè)*
表示這個(gè)變量p存儲(chǔ)的是int變量的地址。
注意:指針和指針變量是不同的 !指針是地址,指針變量是存放指針的變量
我們平常給變量賦值的方法是這樣的
a=100;
我們給指針變量賦值的時(shí)候是這樣的
p=&a;
這里的&a的意思就是取得a的地址
看到這里大家可能會(huì)有所疑惑,這個(gè)指針和變量到底有什么區(qū)別呢?
這里舉一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明指針和直接調(diào)用變量的區(qū)別
坐在隔壁的小明想要抄你的試卷,他看了一下a區(qū),把數(shù)字抄走了,這是b=a,
坐在隔壁的小明,他拿走了你的試卷,這是b=&a
前者只是拿走了數(shù)據(jù),后者拿走的數(shù)據(jù)的地址,那么這會(huì)導(dǎo)致什么呢?
當(dāng)小明(b)想要修改卷子的時(shí)候——
前者,b修改了卷子上的數(shù)值,a的卷子沒(méi)事,因?yàn)閎只是修改了抄走的一個(gè)數(shù)據(jù)
后者,b修改了卷子上的數(shù)值,a驚叫一聲:臥槽你把我卷子改了干啥!!!
這就是使用變量的值和使用變量的指針的區(qū)別
BUT!!!為什么我們需要使用指針呢????
當(dāng)然是因?yàn)?strong>有些時(shí)候我們必須使用指針!
舉個(gè)例子!比如我們想要在某個(gè)函數(shù)里修改函數(shù)外的值的時(shí)候,我們就必須得使用指針。
這里我們需要涉及一點(diǎn)關(guān)于函數(shù)調(diào)用、形參與實(shí)參的知識(shí)。
有些時(shí)候我們要用的函數(shù)會(huì)需要傳入一些數(shù)值,比如我們寫(xiě)一個(gè)求和的函數(shù)
int sum(int a,int b) //聲明一個(gè)返回值是整數(shù)的函數(shù),使用時(shí)需要傳入整數(shù)a和整數(shù)b
{
return a+b; //返回a+b的值
}
然后我們?cè)谑褂玫臅r(shí)候就需要傳入兩個(gè)值
sum(x,y) //x和y是之前已經(jīng)弄好的存了值的變量
sum(10,20)//或者這樣直接給兩個(gè)數(shù)值
這里面的a和b就叫形參,也可以簡(jiǎn)單粗略地理解為參數(shù)所需的形式,x和y就是實(shí)參,可以簡(jiǎn)單粗略的理解為實(shí)際傳入的參數(shù)。
在程序運(yùn)行到調(diào)用sum函數(shù)的時(shí)候就會(huì)創(chuàng)建兩個(gè)臨時(shí)的變量a和b,然后把x和y的值傳給a和b。
這里就出現(xiàn)了不使用指針無(wú)法解決的問(wèn)題——如果我們想要把存儲(chǔ)的結(jié)果還存在x里呢?
當(dāng)然,這樣其實(shí)還能解決,x=sum(x,y)就行了,但是如果我們要存到的地方不確定呢?比如根據(jù)sum計(jì)算結(jié)果的不同存到不同的地方,是不是沒(méi)有辦法啦!
而使用指針就可以很方便(才怪)的解決這個(gè)問(wèn)題,我們不傳入值,而是把地址傳過(guò)去,小明不久可以直接修改你的試卷了嗎?
#include <stdio.h>
int main(int argc, char const *argv[])
{
int x=1;
int y=2;
sum (&x,&y);
return 0;
}
int sum(int* a,int* b)
{
*a=*a+*b;
return 0;
}
這樣就完美的解決了這個(gè)問(wèn)題。
那么這里出一道小題,如果想要修改指針變量int* a的值應(yīng)該怎么辦呢?
int sum(int** a,int** b)
{
*a=*a+*b;
return 0;
}
當(dāng)然是傳入指針的指針!
指針是可以一層套一層的,int************************************************ a都可以!(當(dāng)然,沒(méi)什么大病的話(huà)一般是不會(huì)寫(xiě)太多層的)
回到剛才,講指針的時(shí)候我們有說(shuō)數(shù)組是指針的一種應(yīng)用,是什么意思呢?現(xiàn)在我們就可以解答這個(gè)問(wèn)題了,數(shù)組就是根據(jù)你的需求創(chuàng)建了好多挨在一起的空間,然后數(shù)組的名字就是一個(gè)指針,指向第一塊地方,然后數(shù)組[]里跟不同的數(shù)字就是把指針往后移不同的長(zhǎng)度,指到不同的地方。
比如a[3],其實(shí)也就是*(a+3)的意思,你把a(bǔ)[3]寫(xiě)成*(a+3),*(3+a),3[a]都可以的,都是一樣的東西。
這里也解答了為什么數(shù)組前面要加int double之類(lèi)的類(lèi)型的問(wèn)題,因?yàn)槁暶鲾?shù)組的時(shí)候需要?jiǎng)?chuàng)建出一些地方來(lái)存數(shù)據(jù),不同類(lèi)型數(shù)據(jù)大小不一眼需要的空間也不一樣,數(shù)組前面的數(shù)據(jù)類(lèi)型是用來(lái)標(biāo)識(shí)每一塊地方多大的。
追求技術(shù)是一場(chǎng)漫長(zhǎng)的旅程,很高興在這里與你們相逢。

浙公網(wǎng)安備 33010602011771號(hào)