一、C語言介紹
丹尼斯.裡奇和肯.湯普遜在1971~1973年美國貝爾實驗室,在開發UNIX作業系統時,在BCPL語言的基礎上(new B語言),發明第一款高階程式語言,取BCPL第二個字母作為名字,所以叫C語言
BCPL->new B->C->UNIX->Minix->Linux
它是為了開發作業系統而研發的一款程式語言,它特別擅長控制硬體,所以在伺服器開發、驅動程式設計、微控制器、嵌入式開發中使用較多
C語言的優點:
1、語法簡單、只有32個關鍵字、入門簡單
2、執行速度很快,可以媲美組合語言的執行速度、適合用於執行實現演算法、資料結構
C語言的缺點:
1、需要對記憶體、作業系統有一定的瞭解,易學難精
2、由於出現時間過早,個人計算機沒有普及,在設計時沒有為普通人做太多的考慮,有一些語法上的陷阱和缺陷
3、自由源於自律
4、沒有大型的軟體商業公司在背後支援,可用的軟體庫較少
二、第一個C程式
#include <stdio.h>
#include "stdio.h"
int main() {
printf("Hello World!\n");
}
如何編譯執行程式碼:
// 編譯程式碼,生成可執行檔案,如果程式碼沒有錯誤,會生成 a.out 可執行檔案
gcc xxx.c
// 執行程式
./a.out
// 合併執行
gcc xxx.c && ./a.out
詳解Hello World:
1、程式設計師所編寫的程式碼並不是標準C程式碼,它需要經過一段程式把它翻譯成標準C程式碼,負責翻譯的程式叫做前處理器,被翻譯的程式碼叫做預處理指令,所有預處理指令都是以“#”開頭
2、#include 是一條預處理指令,它的功能是匯入一個輔助檔案到當前檔案中
#include "filename.h"
// 先在當前工作目錄下查詢是否有filename.h這個檔案,找到則直接匯入,如果找不到,則再去系統指定路徑查詢並匯入,如果還找不到則報錯
// 一般用於匯入自定義的標頭檔案
#include <filename.h>
// 直接去系統指定路徑查詢並匯入,如果找不到則報錯
// 一般用於匯入標準庫的標頭檔案
3、C語言標準委員會會給C語言以函式的形式提供了一些基礎的功能,這些函式會被封裝在libc.so庫檔案中,並且按照功能不同在庫中分成了不同的標頭檔案,例如:stdio.h、stdlib.h、string.h等
4、stdio.h是負責對輸入、輸出資料進行功能實現,當程式需要使用輸入、輸出資料時,需要匯入該標頭檔案
5、在C語言,透過函式(function)來管理程式碼的最小單位,一個函式就是一段具有某一項功能的程式碼塊,main函式是C語言程式的預設的執行入口,入口必須有且只有一個,無論它定在任何位置都最先執行
6、函式名後面的內容是函式的呼叫者傳遞給該函式的一些資料
7、函式名前面是一種資料型別,它表示該函式的執行結果是什麼型別的資料,int表示main函式的執行結果是整數
8、C語言是使用大括號開分隔程式碼區域,被大括號包含的程式碼都屬於該函式
9、printf/scanf 屬於標準庫的函式,用於輸出、輸入資料,還可以用於除錯程式碼
printf("---------\n"); //用於除錯程式碼 \n一定要加
跳脫字元:在輸出資料時,鍵盤上有一些字元無法直接表示,透過跳脫字元來表示這些特殊字元
\n 換行
\b 退格鍵 \b \b 可以模擬backspace的效果
\\ 顯示一個\
%% 顯示一個%
\r 回到行首
\t 製表符,相當於tab鍵
\a 鈴響
10、return的兩項功能:
a、直接結束整個函式的執行,當執行到return語句時,哪怕後面還有程式碼也不會執行
b、還可以返回一個資料給函式的呼叫者,main函式的呼叫者是作業系統
11、main函式的返回值表示該程式結束時的狀態:
return 正數 表示程式執行出現異常 (別人的錯)
return 0 表示程式正常結束
return 負數 表示程式執行出現錯誤 (自己的錯)
echo $? 檢視最後一個程式的main函式的執行結果
12、C語言以分號作為一行程式碼的結束標誌,如果程式碼過長可以換行
13、C語言的語法標準:
C89語法標準,是C語言的第一套語法標準
C99語法標準,對C89的升級、擴充套件、增強,我們的系統預設使用的標準
透過 編譯引數 -std=gnu89\99 更改編譯的語法標準
C11語法標準,全新的升級
三、編譯器和gcc
1、什麼是編譯器
它是一個負責編譯程式碼的程式,它負責把人能看得懂的程式碼(文字檔案)翻譯成計算機能看懂的二進位制指令,它由前處理器、編譯器、彙編器、連結器組成,統稱編譯器
gcc是由GNU組織為了編譯Linux核心而開發的一款C語言編譯器,嵌入式開發使用的是 arm-linux-gcc(交叉編譯器)
2、gcc編譯器把C程式碼變成可執行程式的過程
1、把程式設計師所編寫的程式碼進行預處理
// 把預處理的結果直接顯示到螢幕上
gcc -E filename.c
// 會生成以.i結尾的預處理檔案
gcc -E filename.c -o filename.i
2、把預處理的結果翻譯成彙編程式碼
// 會生成以 .s 結尾的彙編檔案
gcc -S filename.i
3、把彙編程式碼翻譯成二進位制指令
// 會生成以 .o 結尾的目標檔案
gcc -c filename.s
4、把若干個目標檔案、庫檔案合併成最終的可執行檔案(預設名字a.out)
// 合併連結若干個目標檔案,生成a.out可執行檔案
gcc aa.o bb.o cc.o ...
// 合併連結若干個目標檔案,生成名為filename可執行檔案
gcc aa.o bb.o cc.o ... -o filename
注意:gcc filename.c 就包含了以上四個步驟,目前瞭解這些步驟為了後序學習預處理指令、多檔案程式設計、靜態庫、共享庫打下基礎
3、gcc、arm-linux-gcc編譯器常用的引數(瞭解):
-E 預處理
-S 生成彙編檔案
-c 生成目標檔案\只編譯不連結
-o 設定編譯結果的名字
-I 設定要匯入的標頭檔案的路徑 <> ""
-l 設定要連結的庫名,例如:使用sqrt、pow等數學函式時就需要連結數學庫 -lm
-L 設定要連結的庫的路徑,一般用於連線第三方庫,或自定義的庫
-D 在編譯時定義宏
-g 編譯時新增除錯資訊,這樣編譯出的程式可以用gdb除錯。
-Wall 顯示所有警告,編譯器會以更嚴格的標準檢查程式碼
-Werror 把警告當錯誤處理
-std 指定編譯器要遵循的語法標準,c89,c99,c11,當前系統預設的是c99標準。
-std=c89\gnu89\gnu99\c99
4、C語言的檔案型別(瞭解):
.h 標頭檔案,裡面是一些對.c檔案的說明
.c 原始檔,裡面是一些功能型程式碼
.i 預處理檔案
.s 彙編檔案
.o 目標檔案
.gch 標頭檔案的編譯結果,用於檢查自定義的標頭檔案是否有語法錯誤,建議立即刪除 gcc -c xxx.h
.a 靜態庫檔案,相當Windows系統下的.lib檔案
.so 動態庫檔案,相當Windows系統下的.dll檔案
四、C語言中基礎的資料型別
C語言為什麼要把資料分成不同的型別:
資料儲存在計算機中需要耗費儲存空間(記憶體、硬碟),在程式語言中把資料按照實際需要:範圍、特點劃分成不同的種類,解決什麼問題就使用合適的型別,這樣可以節約儲存空間、提高運算速度,因此這是程式設計師的基本功,對於嵌入式開發這點尤為重要。
C語言中資料型別分為兩大類:自建類(程式設計師自己設計的型別:結構、聯合、類C++)、內建類(C語言自帶的型別)
儲存空間的單位:
Bit 位元\位元位\位 一個bit儲存一個0\1 計算機中的儲存資料的最小單位
Byte 位元組 儲存8個位元 計算機中儲存資料的基本單位
Kb 1024位元組
Mb 1024Kb
Gb 1024Mb
Tb 1024Gb
Pb 1024Tb
整型:
有符號整型:
最高位的二進位制位用於表示0正數、1負數
由於有符號整數使用頻繁,所以編譯器預設signed可以不加,不加就代表了加
型別名 所佔用位元組數 取值範圍
signed char 1 -128~127
signed short 2 -32678~32767
signed int 4 正負21億左右
signed long 4/8
signed long long 8 正負9開頭19位整數
注意:signed long的位元組數取決於從作業系統的位數 32位下是4 64位是8
無符號整數:
所有的二進位制位都用來表示資料,只能表示正數
型別名 所佔用位元組數 取值範圍
unsigned char 1 0~255
unsigned short 2 0~65535
unsigned int 4 0~40億左右
unsigned long 4/8
unsigned long long 8 0~2開頭21位整數
注意:unsigned long的位元組數取決於從作業系統的位數 32位下是4 64位是8
無符號型別一般用於計數,注意:unsigned不能省略,使用會比較麻煩,C語言標準庫為了讓我們使用簡單,在<stdint.h>標頭檔案中對這些型別名進行重定義
uint8_t uint16_t uint32_t uint64_t
int8_t int16_t int32_t int64_t
size_t time_t
浮點型:
小數點是浮動的,也就是帶有小數部分的資料,採用科學計數法儲存資料,由符號位+指數域+小數域組成,這種儲存格式,導致儲存速度、執行速度比整數要慢得多,又不太準確,所以儘量不使用
單精度:float 4
雙精度:double 8
高精度:long double 12\16
注意:編譯器只對小數點後六位有效
字元型:
char字元型,字元就是符號或圖案,但是在計算機中都是隻能以整數儲存(以整數來模擬字元),當需要顯示成字元時,會根據ASCII表中的對應關係顯示出相應的符號或圖案
'0' ASCII值 48
'A' 65
'a' 97
'\0' 0 結束標誌
bool布林型:
C語言沒有真正的布林型別,先有的C語言後才出現的布林型別,在C89之後使用類似打補丁的方式增加布林型別,需要包含<stdbool.h>
bool 1位元組
true 4位元組 實際就是整數1
false 4位元組 實際就是整數0
注意:bool型別也是使用整型模擬的
注意:一般用於表示只有兩種狀態(對\錯)的資料
五、變數
什麼是變數:
在程式執行過程中可以變化的資料,它就是儲存資料的容器,需要先定義才能使用
定義變數:
資料型別 <變數名>;
1、變數所佔用的記憶體位元組數、儲存資料的範圍、使用的規則都由變數的資料型別決定。並且確定後無法改變
2、變數名也叫做識別符號,變數的定義本質上就是作業系統把一個識別符號與記憶體之間建立一種對映關係,作業系統不會對對映好的記憶體進行初始化清理,所以變數的預設值是不確定,所以我們要對一些有特殊用途的變數必須進行初始化,例如:求和、計數、平均值、累加。
3、定義好的變數,出了它所在的大括號就不能再使用了。
變數名的取名規則:
1、必須由數字、字母、下劃線組成
2、必須不不能以數字開頭
3、必須不能與C語言32關鍵字重名
合法:printf scanf num_1 true bool
非法:32_num *num
4、見名知意,瞭解型別、功能、作用範圍、歸屬模組
unsigned int num_u_i; // 駝峰法命名
不要出現拼音、單個字母
變數的使用:
num = 10; // 被賦值,儲存資料、修改資料,當成容器使用
num*3/4; // 參與運算,此時變數名代表它儲存的資料
變數的輸出:
#include <stdio.h>
int printf(const char *format, ...);
功能:它C標準庫函式,把若干個資料輸出顯示到螢幕終端上
format:"提示資訊+變數的型別資訊+跳脫字元"
...: 可變長引數,若干個變數名,變數名之間使用逗號隔開
返回值:表示printf輸出到終端上的字元個數 一般不會用
在C語言中使用佔位符來表示變數的型別:
%hhd %hd %d %ld %lld 有符號整型的佔位符
%hhu %hu %u %lu %llu 無符號整型的佔位符
%f %lf %LF 浮點型的佔位符
%c 字元型的佔位符
布林型別用於邏輯運算的,不參與輸入、輸出,沒有專屬的佔位符,如果想要強行輸入輸出、當成整數處理即可(0\1)
練習1:定義出各種型別的變數並任意初始化,使用printf顯示
變數的初始化
int num;
num = 10; // 賦值操作
int sum = 0; // 初始化
sum = 0; // 賦值
變數的輸入:
int scanf(const char *format, ...);
功能:在終端讀取資料值並賦值給變數
format:"只放佔位符
...: 變長引數,提供變數的地址 &變數名 獲取該變數的地址
返回值:成功讀取到的變數個數,一般不使用
錯誤使用:
scanf("請輸入:%d\n",&num);
#include <stdio.h>
正確使用:
int main() {
int num = 0;
printf("請輸入num的值:");
int ret = scanf("%d",&num);
printf("num=%d ret=%d\n",num,ret);
}