在開始學習程式設計之前,首先我們要先明確一件事,就是學程式設計重要的是思維而不是語法。
語言只是工具,思維才是本質。
工具只是便捷你的工作與提高你的效率,但真正決定你能否解決問題的是你的思維方式.
就好比做幾何題的時候,垂直平行等那套數學符號語言(工具)真的重要嗎?
那只是一種表述方式而已,不會那套數學符號還可以寫文字描述和算式。
決定你最終能否解答這道題的還是你是否有解題的思路。
程式設計也是如此。
在程式設計學習開始之前,我們還需要了解一個概念,就是模組化。
c語言是一個模組化的語言,這個模組化體現在很多方面,比如函數,比如結構體,比如多檔案。
一個c語言程式,就是由一個個變數拼成結構體,一個個結構體與函數拼成檔案,最後再由一個個檔案拼成最後的整個程式
任何一個C語言程式都是由一個或者多個程式段構成,每個程式段分別負責各自的功能,最後由主程式段統合到一起形成可以執行的程式。 ——這種負責某一部分功能的程式段我們通常稱之為「函數」。
電腦計算機執行程式總要有個開始,總要有個第一行。
前面提到過c語言中每個程式段分別負責各自的功能,那麼計算機執行的時候又怎麼能知道先執行哪裡後執行哪裡呢?
為了解決這一問題,我們需要有一段程式來做各個程式段的統合
這個程式也就是main
函數
也就是說,如果你寫的程式要執行的話,一定要有一個main函數
那麼main
函數如何寫呢?
為了解決這一問題,我們需要了解一下函數的結構。
前面提到,一個c語言程式,就是由一個個變數拼成結構體,一個個結構體與函數拼成檔案,最後再由一個個檔案拼成最後的整個程式。
那麼函數是怎麼樣的呢?這裡我們以不可或缺的主函數為例
void main()
{
//程式碼內容
}
這就是一個最簡化的函數(當然我們通常不用void,這裡只是為了方便理解)
這個函數的結構是這樣的
void main() // 返回值型別 函數名(參數列) 表示建立一個函數
{ //程式碼塊開始
//程式碼塊可以簡單理解為我們要執行的一段程式碼
} //程式碼塊結束
這裡的void是指返回值的型別,void表示沒有返回值,為什麼函數需要返回值呢?因為我們在執行一個函數的時候通常是需要它來實現某個功能的,如果沒有返回值我們就不知道它有沒有成功執行,或者不知道它的執行結果了(譬如執行開平方以後我們沒有收到返回值,平方是開完了,但是結果捏?????)
而且有些時候我們的系統在執行函數的時候也強制要求返回值(一些系統,不是所有系統)
綜上,我們的程式最好提供一個返回值
因此在事實上我們的一個函數表達出來其實是這樣的
型別名 main(){
//函數內容
return 數值;
}
這裡的型別名常用的有 int char double long short float bool
分別對應為整數,字元,雙精度浮點數,長數,短數,浮點數,浮點數就是帶小數點的數,計算機處理浮點數有誤差,double比float精準一些
這裡我們所寫的函數名字叫main,也就是前文提到的主函數
由於是主函數,所以我們的返回值自己是沒有辦法用到了,但是有的計算機系統可能會要求,因此通常的寫法是返回一個0,代表程式正確執行完成,此時我們的程式就變成了
int main() //建立一個返回值為整數的函數 名為main 傳入參數列為空
{
//函數內容
return 0; // 返回整數 0
}
這裡我們執行一下這個程式給大家看看結果
(展示)因為我們函數內容什麼都沒有寫,所以也什麼都沒有顯示
那麼怎麼證明我們的程式真的執行成功了呢?我們再增加一行用於顯示的指令
#include <stdio.h>
int main() //建立一個返回值為整數的函數 名為main 傳入參數列為空
{
printf("hello world");//顯示hello world
return 0; // 返回整數 0
}
注意!C語言函數裡的語句結束後需要以英文分號結尾,每一句都需要
printf是c語言裡的列印(顯示到螢幕)語句,這句話的意思是顯示hello world
加上之後我們再來執行一下(展示)程式就會顯示輸出hello world
加上以後我們的命令後就顯示出了我們要顯示的內容,這證明本喵剛才認真講了沒有胡說八道(驕傲)
可能剛才有銀還意識到一個問題,就是剛才的程式比上面說的多了一行
#include <stdio.h>
這一句的意思又是什麼呢?
這個#include就是包含標頭檔案的意思
#include <stdio,h>
的意思就是這個程式要包含檔案stdio.h裡面的內容,stdio.h是c語言編譯器自帶的一個標頭檔案,包含了輸入輸出的函數之類的一些常用的功能函數,printf()其實也是一個函數,它在stdio檔案裡面,我們使用的printf就是呼叫了程式外部檔案stdio.h裡面的print函數。
剛才咱們已經說了,c語言由很多函數構成,下面咱們再定義一下別的函數來個多函數的程式
#include
int die()
{
printf(" bay~ world " );
return 0;
}
int main()
{
die();
return 0;
}
由於這個不是主函數了所以函數名就可以自己起了,不過這裡要注意,函數名不能和關鍵字(c語言裡面已經被佔用的詞)同名
這裡我們起名die
這裡左下角就正確顯示了
這裡是先定義了die函數然後在主函數裡面呼叫了它
die();
就醬,我們寫了一個多個函數的c語言程式,(在學習程式設計的初期可以先不用考慮多檔案,先從一個檔案寫起)
這裡要注意!我們使用的程式要在使用的地方之前出現,例如dnlm函數在main函數之前
然後下面我們講一坨選擇分支結構
這個選擇分支結構它是這個樣子的
if()
{
//如果條件成立執行
}
else
{
//如果條件不成立執行
}
這裡我們新增一個丟乃老父並且宣告母親父親兩個整數來測試一下
#include
int dnlm()
{
int a=30;//宣告整數a等於30
int b=20; //宣告整數b等於20
if a>b) //如果a大於b
{
printf(" a" ); //顯示
}
else //否則
{
printf(" b" ); //顯示
}
return 0;
}
int main()
{
dnlm();
return 0;
}
執行結果正確的顯示在了左下角。
這樣一來證明我們的選擇結構發揮了它應有的效果
剛才講完了選擇分支結構,這次我們從迴圈結構開始講,一課時之內把c語言入門講完,然後看看時間能不能夠講一些其他的東西。
首先是while迴圈,這是平常會經常用到的一個迴圈
while(迴圈條件){ //程式碼內容}
while迴圈的結構是這樣的,首先判斷迴圈條件是不是成立,例如迴圈條件是變數a>=2,那麼當a大於等於2的時候,就會執行程式碼內容一次,然後再次判斷a是不是還大於等於2,如果是的話再執行一次。直到有一次發現a不再大於等於2了,才結束迴圈開始執行迴圈外面的內容。這樣一來的話,實際上也就是說,我們在寫這種迴圈的時候,裡面一定要寫改變回圈條件的程式碼,否則迴圈條件一直不變就變成死迴圈了。
while迴圈是先判斷然後才決定執不執行的,所以while迴圈最少會執行0次,也就是說如果一開始條件就不成立的話就一次都不執行。
與之相對的是do。。。while迴圈
do
{
//程式碼內容
}while()
do。。。while和while相反,dowhile是先做了再說,做一遍到做完以後再判斷,是不是條件成立 ,條件成立的話繼續迴圈,條件不成立的話到此為止,繼續往下執行,do while迴圈是至少會執行一次的迴圈。
與while系列迴圈用的同樣多的就是for迴圈了
for(i=100;i>=0;i--){ //程式碼內容}
for迴圈的條件分為三部分,第一部分是宣告控制迴圈的變數,比如宣告個i=100,第二個部分和while的控制條件一樣是用來判斷迴圈執不執行,最後一個部分是用來宣告控制變數的變化,就和while一樣,for也需要改變控制條件來防止死迴圈,不過for直接在控制條件裡就可以寫好改變控制變數的語句。
以上是迴圈結構的三種語句。
下面進行跳轉語句
c語言裡的跳轉語句其實就是goto
語法也很簡單,在任意一個地方立下flag,然後就可以隨時goto到這個地方了
lable1:
//此處省略兩百萬億行
goto lable1
就可以直接飛回flag
goto用的好的話不僅可以跳轉還可以實現各種迴圈,不過goto很容易出現不知道飛到了哪裡去但是編譯器不報錯導致查錯人員頭比地球還大的現象,因此一般的來說,不建議使用goto語句。
陣列部分也很簡單,其實就是把資料連起來存
我們平常宣告一個變數a,可以儲存一個資料。
我們現在宣告一個陣列a[100],就可以儲存100個資料
資料型別 陣列名[陣列長度]
可以通過a[0-99]來分別使用這100個資料,就不用寫100遍宣告變數了,而且如果我們要查詢的數有好幾個特點,還可以使用二維或者多維陣列。
比如a[1][2][3][4][5][6][7]就是七維陣列裡第二組的第三小組的第四小組的第五小組的第六小組的第七小組的第八個數
這裡要注意陣列裡面排序序號是從零開始的,第一個內容的編號是0,所以陣列名加數位實際存取到位置是數位加一的位置存的資料。例如a[0]
其實是陣列a的第一位。
從本質上而言,陣列其實就是一種指標的應用方式。
語言裡面指標是核心精髓所在,所謂指標,就是指向資料儲存的地方。
我們平常宣告一個變數,a=100,大概就相當於在白紙上劃了一部分叫做a區,然後往裡面記錄了一個數位100,100寫在a這個地方。
這塊a區所在的位置就叫做a的地址
c語言裡面和地址有關的有兩個符號,一個是&
,取地址符,一個是*
,是指標的標記(也是解除參照符號)
我們平常建立變數的時候是這樣的
int a;
我們建立指標變數時候是這樣的
int* p;
標上一個*
表示這個變數p儲存的是int變數的地址。
注意:指標和指標變數是不同的 !指標是地址,指標變數是存放指標的變數
我們平常給變數賦值的方法是這樣的
a=100;
我們給指標變數賦值的時候是這樣的
p=&a;
這裡的&a的意思就是取得a的地址
看到這裡大家可能會有所疑惑,這個指標和變數到底有什麼區別呢?
這裡舉一個簡單的例子來說明指標和直接呼叫變數的區別
坐在隔壁的小明想要抄你的試卷,他看了一下a區,把數位抄走了,這是b=a,
坐在隔壁的小明,他拿走了你的試卷,這是b=&a
前者只是拿走了資料,後者拿走的資料的地址,那麼這會導致什麼呢?
當小明(b)想要修改卷子的時候——
前者,b修改了卷子上的數值,a的卷子沒事,因為b只是修改了抄走的一個資料
後者,b修改了卷子上的數值,a驚叫一聲:臥槽你把我卷子改了幹啥!!!
這就是使用變數的值和使用變數的指標的區別
BUT!!!為什麼我們需要使用指標呢????
當然是因為有些時候我們必須使用指標!
舉個例子!比如我們想要在某個函數裡修改函數外的值的時候,我們就必須得使用指標。
這裡我們需要涉及一點關於函數呼叫、形參與實參的知識。
有些時候我們要用的函數會需要傳入一些數值,比如我們寫一個求和的函數
int sum(int a,int b) //宣告一個返回值是整數的函數,使用時需要傳入整數a和整數b
{
return a+b; //返回a+b的值
}
然後我們在使用的時候就需要傳入兩個值
sum(x,y) //x和y是之前已經弄好的存了值的變數
sum(10,20)//或者這樣直接給兩個數值
這裡面的a和b就叫形參,也可以簡單粗略地理解為引數所需的形式,x和y就是實參,可以簡單粗略的理解為實際傳入的引數。
在程式執行到呼叫sum函數的時候就會建立兩個臨時的變數a和b,然後把x和y的值傳給a和b。
這裡就出現了不使用指標無法解決的問題——如果我們想要把儲存的結果還存在x裡呢?
當然,這樣其實還能解決,x=sum(x,y)
就行了,但是如果我們要存到的地方不確定呢?比如根據sum計算結果的不同存到不同的地方,是不是沒有辦法啦!
而使用指標就可以很方便(才怪)的解決這個問題,我們不傳入值,而是把地址傳過去,小明不久可以直接修改你的試卷了嗎?
#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;
}
這樣就完美的解決了這個問題。
那麼這裡出一道小題,如果想要修改指標變數int* a的值應該怎麼辦呢?
int sum(int** a,int** b)
{
*a=*a+*b;
return 0;
}
當然是傳入指標的指標!
指標是可以一層套一層的,int************************************************ a
都可以!(當然,沒什麼大病的話一般是不會寫太多層的)
回到剛才,講指標的時候我們有說陣列是指標的一種應用,是什麼意思呢?現在我們就可以解答這個問題了,陣列就是根據你的需求建立了好多挨在一起的空間,然後陣列的名字就是一個指標,指向第一塊地方,然後陣列[]裡跟不同的數位就是把指標往後移不同的長度,指到不同的地方。
比如a[3],其實也就是*(a+3)的意思,你把a[3]寫成*(a+3)
,*(3+a)
,3[a]
都可以的,都是一樣的東西。
這裡也解答了為什麼陣列前面要加int double之類的型別的問題,因為宣告陣列的時候需要建立出一些地方來存資料,不同型別資料大小不一眼需要的空間也不一樣,陣列前面的資料型別是用來標識每一塊地方多大的。
追求技術是一場漫長的旅程,很高興在這裡與你們相逢。