基礎c語言 part
編程基礎知識
- 編輯器:類型記事本一樣的用來編寫代碼的工具。
- 編譯器:負責把代碼文件翻譯成可執行程序的軟件。
- gcc 是GNU社區爲編譯Linux內核開發的一款編譯器。
gcc code.c > a.out
編譯器如何工作
- 預處理
把代碼中以#開頭的指令翻譯成標準的C代碼,生成預處理文件。
gcc -E code.c -o code.i - 彙編
把預處理文件翻譯成彙編文件
gcc -S code.i -> code.s - 編譯
把彙編文件翻譯成目標文件(二進制)
gcc -c code.s -> code.o - 鏈接
把若干個目標文件合併成一個可執行文件
gcc a.o b.o c.o -> a.out
C語言的數據
爲什麼要把數據進行分類:
- 現實社會中的數據是自帶類別屬性。
- 對數據進行分類型可以節約存儲空間、提高運行效率。
C語言中數據分類兩個大類自建(程序自己設計的,如:結構、聯合、類)和內建(C語言自帶)。
整型
char、short、int、long、long long
有符號 signed : 它存儲數據的二進制位中最高位用來表示正負。
無符號 unsigned :它的所有的二進制位都用來存儲數據,只能表示正數。
浮點型
float 單精度
double 雙精度
long double 高精度
浮點型數據採用的是科學計數,可以表示較大範圍的數據,但是精確度有限。
浮點型的數據由於格式特殊,所以運算的效率不高,編程時優先選擇整型。
布爾類型
C語言中沒有真正的布爾類型,若使用必須添加頭文件stdbool.h
bool true false
字符型
字符其實就是符號或圖案,在計算機中是以整數形式存儲的,當需要顯示時會根據ASCII表中的對應關係,顯示相應的符號。
‘\0’ | 0 |
‘0’ | 48 |
‘A’ | 65 |
‘a’ | 97 |
變量
存儲數據的容器,需要先定義後使用。
定義:類型 變量名;
注意:剛定義的變量默認值是不確定的,爲了安全一定要初始化(養成良好的習慣)。
變量的取名規則(標識符的取名規則)
- 只能由字母、數字、下劃線組成。
- 不能以數字開頭。
- 不能與關鍵字重名( 32個關鍵字)。
- 儘量不要超過30個字符。
- 見名知義(功能+類型+作用域+…)。
C語言中通過使用佔位符的方式來告訴printf/scanf變量的類型。
變量的輸出:printf 類型 變量名
變量的輸入:scanf 類型 變量的地址=&變量名
sizeof 計算變量的字節數。
常量
字面值常量(代碼中能直接使用的數量:100,1000),不可被修改,存儲在一塊只有只讀權限的內存中(代碼段)。
設置字面值常量的類型:
默認是int(10)類型,或double(3.14)類型。
10u unsigned short
10U unsigned int
10u8 unsigned char
3.14f float
3.14l long double
運算符
算術運算符:+ - * / %
/ % 除數不能爲零,如果除數爲零程序會提前死亡。
關係運算符:> < >= <= == !=
運算的結果是邏輯:true=1 false=0
==使用時常量放在左邊,變量放右邊。
num == 10;
10 == num; 防止出錯
10 < num < 100; 數學中[11,99],C語言中永遠爲真。
自變運算符:++/–
可以讓變量的值自加1或自減1(只有變量才能使用)。
-
前自變:++/–num,立即有效。
-
後自變:num++/–,下一行代碼纔會生效。
一行代碼中不要多次使用自變運算符。
邏輯運算符:&& || !
在運算之前會把運算對象轉換成邏輯值:零值轉換成假,非零值轉換成真,然後再對邏輯值進行運算,得到的結果也是邏輯值。
A && B => 一假即假
A || B =>一真即真
!A =>對A的值求反
!比&&、||運算級別要高(單目運算符的級別都比較高)。
&&、|| 具有短路特性,當左邊的值已經能確定表達式的結果,右邊的值則不再計算(注意思維誤區,還可以藉此形成精簡的分支結構)。
int num = 0;
num>0 && num–;
賦值運算符及擴展:= += -= *= /= …
num += 10 <=> num = num + 10;
三目運算符:[1] ? [2] : [3];
當1的值爲真時執行2,否則執行3,類似if語句。
不能使用流程控制語句,因爲畢竟是運算符,必須要有運算結果。
字節數運算符:sizeof
- sizeof不是函數而是運算符,而且是32個關鍵字之一。
- 只是推算表達的結果是什麼類型、佔多少個字節,而不計算表達式。
位運算符:& | ~ ^ << >>
流程控制語句
分支
if(表達式)//單分支
{
表達式爲真,則執行此處代碼,如果此處代碼只有一行,則大括號可以省略(如果沒有括號,默認下一行是if的語句體,與縮進無進,但這樣會影響代碼的可擴展性和安全性)。
}
if(表達式)//雙分支
{
表達式爲真時執行
}
else
{
表達式爲假時執行
}
if(表達式1)
{
表達式1爲真時執行
}
else if(表達式2)//可以有任意多個
{
表達式1爲真時執行
}
else
{
所有表達式都爲假時執行。
}
開關語句
switch(表達式)//表達式的結果必須是整型數據
{
//val必須是常量,現階段只能是字面值,以後可以是枚舉值、宏常量。
//case的數據與表達式的結果進行匹配,如果匹配成功則打開執行開關。
//break可以關閉執行執行開關,如果每個case後都有一個break就會形成分支結構。
case val: 語句; break;
//當所有的case都沒有匹配成功,default就會打開執行開關,無論放在任何位置都最後執行。
default: 語句;
}
循環
爲了解決一些問題,需要反覆執行一些代碼,這種可以反覆執行代碼的結構叫循環結構,有兩種循環結構,當型循環(當條件爲真進入循環),直到循環(直接條件爲假退出循環)。
for循環
for循環是一種非常靈活的循環(1234位置的代碼都缺省),但也非常危險的循環,一般採用循環變量來引導for循環的執行,index->i,j,k,l。
可以寫出各種格式:
int i=0;
for(; i<10; i++)
{
…
}
for(int i=0; i<10;)
{
…
i++;
}
for( ; ; )//死循環
{
…
}
while循環
while(表達式)
{
表達式的結果爲真則執行循環體,爲假則結束while循環。
}
while可以當作是for循環的精簡版本,跟以下格式的for功能一致。
for(;表達式;)
{
}
for負責解決明確知道循環次數的問題,while負責解決只知道循環條件不確定循環次數的問題。
do while 循環
do{
先執行一次循環體,再判斷表達式,爲真繼續執行do while循環,爲假時則結束,因此do while的循環體至少執行一次,相同條件下會比for和while多執行一次,適合解決先幹活後檢查的問題。
}while(表達式);
跳轉語句
goto 只跳轉到函數內任意位置執行,是一種非靈活但也非常危險的語句,因爲它會破壞之前設計好的分支或循環結構,各公司一般禁止使用goto語句。
goto語句之所以還保留,是因爲它在驅動編程時非常適合處理異常(釋放資源),具有不可替代的作用。
標籤名:
goto 標籤;
練習
假如你和你的朋友參加了一個旅遊團去海上旅行,不幸遇到龍捲風,一行41人被吹到了一個荒無人煙的小島,由於所帶水和食物有限,只夠2個人生存下來因此大家決定了一個自殺方式,41個人排成一個圓圈,由第1個人 開始報數,每報數到3,此人就必須自殺 ,然後再由下一個重新報數,直到剩餘兩個人,爲了你和你朋友能夠生成下來,請編程計算出你們要站的位置。
#include <stdio.h>
int main()
{
// 定義arr[41]中等於0爲或者,等於1已死亡。
int arr[41] = {},count = 41,step=0,i=0;
while(count > 2)
{
if(0 == arr[i])
{
step++;
}
if(3 == step)
{
arr[i] = 1;
count--;
step = 0;
}
//41個人輪完後i清零,造成圓循環
if(i++ == 40)
{
i=0;
}
}
for(int i=0; i<41; i++)
{
if(0 == arr[i])
{
printf("%d\n",i+1);
}
}
}