C語言簡介 C 語言是一種通用的高級語言,最初是由丹尼斯·里奇在貝爾實驗室為開發 UNIX 操作系統而設計的。C 語言最開始是於 1972 年在 DEC PDP-11 電腦上被首次實現。 原文鏈接:https://juejin.im/post/5df8c917f265da339772a5d1#he ...
C語言簡介
C 語言是一種通用的高級語言,最初是由丹尼斯·里奇在貝爾實驗室為開發 UNIX 操作系統而設計的。C 語言最開始是於 1972 年在 DEC PDP-11 電腦上被首次實現。
原文鏈接:https://juejin.im/post/5df8c917f265da339772a5d1#heading-10編輯
在 1978 年,布萊恩·柯林漢(Brian Kernighan)和丹尼斯·里奇(Dennis Ritchie)製作了 C 的第一個公開可用的描述,現在被稱為 K&R 標準。
UNIX 操作系統,C編譯器,和幾乎所有的 UNIX 應用程式都是用 C 語言編寫的。由於各種原因,C 語言現在已經成為一種廣泛使用的專業語言。
易於學習。
結構化語言。
它產生高效率的程式。
它可以處理底層的活動。
它可以在多種電腦平臺上編譯。
環境設置
這是只說明在 MAC 上怎麼使用 C 語言來進行開發,環境的話需要用到 GCC 進行編譯,你可以下載並安裝 Xcode 工具,一旦安裝上 Xcode,您就能使用 GNU 編譯器。開發工具你可以使用 Xcode 或者 CLion 都可以,看個人喜好。我這裡用的是 CLion 工具,你可以發現 CLion 頁面跟使用風格包括快捷鍵都跟 AndroidStudio 一樣。上手極其容易。
1. 程式結構
我們先來看一下最簡單的一個 C 程式,先來列印一個 “HelloWorld”。代碼如下:
#include <stdio.h>
/**
* C 語言入口程式
* @return
*/
int main() {//主函數,程式從這裡開始執行
printf("C 語言入門第一行代碼 Hello World! \n");
return 0;
}
可以看到 C 語言的入口函數跟 Java 的類似吧,都是以main來定義的入口,接下來我們講解一下上面這段程式的意思:
(1)程式的第一行#include <stdio.h>是預處理器指令,告訴 C 編譯器在實際編譯之前要包含 stdio.h 文件。
(2)下一行 /.../ 將會被編譯器忽略,這裡放置程式的註釋內容。它們被稱為程式的註釋。
(3)下一行int main()是主函數,程式從這裡開始執行。
(4)下一行printf(...)是 C 中另一個可用的函數,會在屏幕上顯示消息 "C 語言入門第一行代碼 Hello World!"。
(5)下一行return 0;終止 main() 函數,並返回值 0。
當然你可以通過命令來執行,如下所示:
編輯 1. 使用 gcc xxx.c
2. ./a.out
直接使用上面 2 個步驟就可以進行執行 C 代碼了。
2. 基本語法
上一小節我們知道了一個簡單的小應用由哪些部分組成,這將有助於我們理解 C 語言的其它基本的構建塊。
c 程式由各種令牌組成,令牌可以是關鍵字、標識符、常量、字串符值、或者是一個符號。
下麵我們來看一下 C 中的關鍵字,這些關鍵字不能作為常量名,變數名或者其它標識符名稱(跟 Java 類似)。
編輯 編輯 編輯 3. 數據類型
在 C 語言中,數據類型指的是用於聲明不同類型的變數或函數的一個廣泛的系統。變數的類型決定了變數存儲占用的空間,以及如何解釋存儲的位模式。
C 中的類型可分為以下幾種:
編輯 整數類型
下表列出了關於標準整數類型的存儲大小和值範圍的細節
編輯 註意: 各種類型的存儲大小與系統位數有關,但目前通用的以 64 為系統為主。
浮點類型
編輯 他們的位元組,精度,取值範圍都可以通過代碼列印實現,如下:
void main() {
/**
* 整數類型
*/
printf("\n\n 整數類型 \n");
//char 1 位元組
printf("char 存儲大小: %lu \n", sizeof(char));
printf("unsinged char 存儲大小: %lu \n", sizeof(unsigned char));
//short 2 位元組
printf("short 存儲大小: %lu \n", sizeof(short));
printf("unsinged short 存儲大小: %lu \n", sizeof(unsigned short));
//int 4 位元組
printf("int 存儲大小: %lu \n", sizeof(int));
printf("unsinged int 存儲大小: %lu \n", sizeof(unsigned int));
//long 4/8 位元組
printf("long 存儲大小: %lu \n", sizeof(long));
printf("unsinged long 存儲大小: %lu \n", sizeof(unsigned long));
/**
* 浮點類型
*/
printf("\n\n 浮點類型 \n");
//float 4 位元組 ,精度 6 位小數
printf("float 存儲最大位元組數:%lu \n", sizeof(float));
printf("float 最小值:%e \n", FLT_MIN);
printf("float 最大值:%e \n", FLT_MAX);
printf("float 精度值:%d \n", FLT_DIG);
//double 8 位元組
printf("double 存儲最大位元組數:%d \n", sizeof(double));
printf("double 最小值:%e \n", DBL_MIN);
printf("double 最大值:%e \n", DBL_MAX);
printf("double 精度值:%d \n", DBL_DIG);
//long double 16 位元組
printf("long double 存儲最大位元組數:%lu byte \n", sizeof(long double));
printf("long double 最小值:%lg \n", LDBL_MIN);
printf("long double 最大值:%lg \n", LDBL_MAX);
printf("long double 精度值:%d \n", LDBL_DIG);
}
可以通過 sizeof 關鍵字來獲取數據類型占用記憶體的大小。上面代碼可以看到了列印中出現了很多不識的 scanf() 格式控制符,我總結了一個表,可以參考下;
編輯 4. 變數
變數其實只不過是程式可操作的存儲區的名稱。C 中每個變數都有特定的類型,類型決定了變數存儲的大小和佈局,該範圍內的值都可以存儲在記憶體中,運算符可應用於變數上。
變數的名稱可以由字母、數字和下劃線字元組成。它必須以字母或下劃線開頭。大寫字母和小寫字母是不同的,因為 C 對大小寫敏感的。
C 中的變數定義
變數定義就是告訴編譯器在何處創建變數的存儲,以及如何創建變數的存儲。變數定義指定一個數據類型,並包含了該類型的一個或多個變數的列表,如下所示:
type list;
在這裡,type必須是一個有效的 C 數據類型,可以是 char、w_char、int、float、double 或任何用戶自定義的對象,list可以由一個或多個標識符名稱組成,多個標識符之間用逗號分隔。下麵列出幾個有效的聲明:
int a,b,c;
char c1,c2,c3;
float f,f1,f2;
double d1,d2,d3;
這裡其實跟 Java 聲明變數差不多,就不再單獨解釋了。
c 中變數聲明
變數聲明向編譯器保證變數以指定的類型和名稱存在,這樣編譯器在不需要知道變數完整細節的情況下也能繼續進一步的編譯。變數聲明只在編譯時有它的意義,在程式連接時編譯器需要實際的變數聲明。
變數的聲明有兩種情況:
1、一種是需要建立存儲空間的。例如:int a 在聲明的時候就已經建立了存儲空間。
2、另一種是不需要建立存儲空間的,通過使用 extern 關鍵字聲明變數名而不定義它。 例如:extern int a 其中變數 a 可以在別的文件中定義的。
3、除非有 extern 關鍵字,否則都是變數的定義。
extern int i;//聲明,不是定義
int a;//聲明,也是定義
例子
#include <stdio.h>
//函數外定義變數
//如果需要在一個源文件中引用另外一個源文件中定義的變數,我們只需在引用的文件中將變數加上 extern 關鍵字的聲明即可
int x;
int y;
int sum() {
//函數內聲明變數 X , Y 為外部變數
x = 10;
y = 15;
return x + y;
}
//入口函數
void main() {
//列印變數相加
int result;
result = sum();
printf("x + y = %d",result);
}
輸出:x + y =25
5. 常量
常量是固定值,在程式執行期間不會改變。這些固定的值,又叫做字面量。
常量可以是任何的基本數據類型,比如整數常量、浮點常量、字元常量,或字元串字面值,也有枚舉常量。
常量就像是常規的變數,只不過常量的值在定義後不能進行修改。
在 Java 中聲明一個常量往往是在數據類型中定義 final 關鍵字就行了,但是 c 中沒有 final 關鍵字,我們來看看怎麼定義,如下所示:
整數常量
整數常量可以是十進位、八進位或十六進位的常量。首碼指定基數:0x 或 0X 表示十六進位,0 表示八進位,不帶首碼則預設表示十進位。
整數常量也可以帶一個尾碼,尾碼是 U 和 L 的組合,U 表示無符號整數(unsigned),L 表示長整數(long)。尾碼可以是大寫,也可以是小寫,U 和 L 的順序任意。
212 /* 合法的 */
215u /* 合法的 */
0xFeeL /* 合法的 */
078 /* 非法的:8 不是八進位的數字 */
032UU /* 非法的:不能重覆尾碼 */
浮點常量
浮點常量由整數部分、小數點、小數部分和指數部分組成。您可以使用小數形式或者指數形式來表示浮點常量。
當使用小數形式表示時,必須包含整數部分、小數部分,或同時包含兩者。當使用指數形式表示時, 必須包含小數點、指數,或同時包含兩者。帶符號的指數是用 e 或 E 引入的。
3.14159 /* 合法的 */
314159E-5L /* 合法的 */
510E /* 非法的:不完整的指數 */
210f /* 非法的:沒有小數或指數 */
.e55 /* 非法的:缺少整數或分數 */
定義常量
在 C 中,有兩種簡單的定義常量的方式:
使用 #define 預處理器。
使用 const 關鍵字。
下麵是使用 #define 預處理器定義常量的形式:
#define identifier value
例子:
#define name 10L
#define age 27U
void main() {
int person;
person = name + age;
printf("values :%d",person);
}
const 關鍵字
您可以使用 const 首碼聲明指定類型的常量,如下所示:
const type variable = value;
例子:
void main() {
const int LEGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LEGTH * WIDTH;
printf("value of area: %d", area);
}
6. 存儲類
存儲類定義 C 程式中變數/函數的範圍(可見性)和生命周期。這些說明符放置在它們所修飾的類型之前。下麵列出 C 程式中可用的存儲類:
auto
register
static
extern
auto 存儲類
auto 存儲類時所有局部變數預設的存儲類。
int month;
auto int month;
上面定義了兩個帶有相同存儲類,auto 只能用在函數內,即 auto 只能修飾局部變數。
register 存儲類
register存儲類用於定義存儲在寄存器中而不是 RAM 中的局部變數。這意味著變數的最大尺寸等於寄存器的大小(通常是一個詞),且不能對它應用一元的 '&' 運算符(因為它沒有記憶體位置)。
register int miles;
寄存器只用於需要快速訪問的變數,比如計數器。還應註意的是,定義register並不意味著變數將被存儲在寄存器中,它意味著變數可能存儲在寄存器中,這取決於硬體和實現的限制。
static 存儲類
static存儲類指示編譯器在程式的生命周期內保持局部變數的存在,而不需要在每次它進入和離開作用域時進行創建和銷毀。因此,使用 static 修飾局部變數可以在函數調用之間保持局部變數的值。static 修飾符也可以應用於全局變數。當 static 修飾全局變數時,會使變數的作用域限制在聲明它的文件內。
全局聲明的一個 static 變數或方法可以被任何函數或方法調用,只要這些方法出現在跟 static 變數或方法同一個文件中。
//函數聲明
void func1(void);
static int count = 10; //全局變數 - static 預設的
void main() {
while (count--) {
func1();
}
}
void func1(void) {
// 'thingy' 是 'func1' 的局部變數 - 只初始化一次
// * 每次調用函數 'func1' 'thingy' 值不會被重置。
static int thingy = 5;
thingy++;
printf("thingy 為 %d, count 為 %d \n", thingy, count);
}
輸出:
thingy 為 6, count 為 9
thingy 為 7, count 為 8
thingy 為 8, count 為 7
thingy 為 9, count 為 6
thingy 為 10, count 為 5
thingy 為 11, count 為 4
thingy 為 12, count 為 3
thingy 為 13, count 為 2
thingy 為 14, count 為 1
thingy 為 15, count 為 0
實例中 count 作為全局變數可以在函數內使用,thingy 在局部使用 static 修飾後,不會在每次調用時重置。
extern 存儲類
extern存儲類用於提供一個全局變數的引用,全局變數對所有的程式文件都是可見的。當您使用extern時,對於無法初始化的變數,會把變數名指向一個之前定義過的存儲位置。
當您有多個文件且定義了一個可以在其他文件中使用的全局變數或函數時,可以在其他文件中使用extern來得到已定義的變數或函數的引用。可以這麼理解,extern是用來在另一個文件中聲明一個全局變數或函數。
extern 修飾符通常用於當有兩個或多個文件共用相同的全局變數或函數的時候,如下所示:
第一個文件 ndk_day1.c
#include <stdio.h> //stdio.h 是一個頭文件(標準輸入輸出頭文件),#include 是一個預處理命令,用來引入頭文件。
#include "support.h" //引入自己的頭文件
int main() {
int sum = add(2, 5);
printf("extern 使用 :%d", sum);
}
聲明 support.h 頭文件
int add(int num1,int num2){
return num1 * num2;
}
輸出:
extern 使用 :10
7. 運算符
運算符是一種告訴編譯器執行特定的數學或邏輯操作的符號。C 語言內置了豐富的運算符,並提供了以下類型的運算符:
算術運算符
關係運算符
邏輯運算符
位運算符
賦值運算符
雜項運算符
算術運算符
下表顯示了 C 語言支持的所有算術運算符。假設變數A的值為 10,變數B的值為 20,則:
編輯 例子:
void main(){
int a = 21;
int b = 10;
int c;
c = a + b;
printf("a + b = %d \n", c);
c = a - b;
printf("a - b = %d \n", c);
c = a * b;
printf("a * b = %d \n", c);
c = a / b;
printf("a / b = %d \n", c);
c = a % b;
printf("a % b = %d \n", c);
c = ++a;
printf("++a = %d , %d \n", c, a);
c = b++;
printf("b++ = %d , %d \n", c, b);
c = b--;
printf("b-- = %d \n", c);
}
輸出:
a + b = 31
a - b = 11
a * b = 210
a / b = 2
a b = 1
++a = 22 , 22
b++ = 10 , 11
b-- = 11
關係運算符
下表顯示了 C 語言支持的所有關係運算符。假設變數 A 的值為 10,變數 B 的值為 20,則:
編輯 邏輯運算符
下表顯示了 C 語言支持的所有關係邏輯運算符。假設變數 A 的值為 1,變數 B 的值為 0,則:
編輯 例子:
void main(){
int a1 = 5;
int b1 = 5;
int c1;
//如果兩個操作數都非零,則條件為真。
if (a1 && b1) {
printf("a1 && b1 %d \n", true);
} else {
printf("a1 && b1 %d \n", false);
}
//如果兩個操作數中有任意一個非零,則條件為真。
if (a1 || b1) {
printf("a1 || b1 %d \n", true);
} else {
printf("a1 || b1 %d \n", false);
}
//改變 a1 b1 的值
a1 = 0;
b1 = 10;
//如果兩個操作數都非零,則條件為真。
if (a1 && b1) {
printf("a1 && b1 %d \n", true);
} else {
printf("a1 && b1 %d \n", false);
}
if (!(a1 && b1)) {
printf("!(a1 && b1) %d \n", true);
} else {
printf("a1 || b1 %d \n", false);
}
}
輸出:
a1 && b1 1
a1 || b1 1
a1 && b1 0
!(a1 && b1) 1
位運算符
編輯 例子:
void main(){
//位運算符 & | ^ ~
int wA = 60; //0011 1100
int wB = 13; //0000 1101
int wC = 10;
//都為真,才是真 0000 1100
printf("wA & wB=?%d\n", wA & wB);
//其中一個為真,就為真 0011 1101
printf("wA | wB=?%d\n", wA | wB);
//一個為真則為真,2個為真這為假 00110001
printf("wA ^ wB=?%d\n", wA ^ wB);
printf("~wB=?%d\n", ~wB);
//二進位左移運算符 左 * 4 = 40
printf("wC<<2=?%d\n", wC << 2);
//二進位右移運算符 右 / 4
printf("wC>>2=?%d\n", wC >> 2);
}
輸出:
wA & wB=?12
wA | wB=?61
wA ^ wB=?49
~wB=?-14
wC<<2=?40
wC>>2=?2
下表顯示了 C 語言支持的位運算符。假設變數 A 的值為 60,變數 B 的值為 13,則:
編輯 賦值運算符
下表列出了 C 語言支持的賦值運算符:
編輯 例子:
void main(){
int wAA = 21;
int wBB;
wBB = wAA;
printf("= %d\n", wBB);
wBB += wAA;
printf("+= %d\n", wBB);
wBB -= wAA;
printf("-= %d\n", wBB);
wBB *= wAA;
printf("*= %d\n", wBB);
wBB /= wAA;
printf("/= %d\n", wBB);
wBB %= wAA;
printf("%= %d\n", wBB);
wBB <<= wAA;
printf("<<= %d\n", wBB);
wBB <<= wAA;
printf(">>= %d\n", wBB);
wBB &= wAA;
printf("&= %d\n", wBB);
wBB ^= wAA;
printf("^= %d\n", wBB);
wBB |= wAA;
printf("|= %d\n", wBB);
}
輸出:
= 21
+= 42
-= 21
*= 441
/= 21
= 0
<<= 0
>>= 0
&= 0
^= 21
|= 21
雜項運算符 sizeof、&、三元
下表列出了 C 語言支持的其他一些重要的運算符,包括 sizeof 和 ? :。
編輯 例子:
void main(){
int zxA = 4;
short zxB;
double zxC;
int *ptr;
//sizeOf 運算符實例 ,lu 32位無符號整數
printf("zxA sizeOf = %lu \n", sizeof(zxA));
printf("zxB sizeOf = %lu \n", sizeof(zxB));
printf("zxC sizeOf = %lu \n", sizeof(zxC));
//& 和 * 運算符實例
ptr = &zxA; //將 zxA 的地址值複製給 ptr 指針
printf("zxA 的值為:%d \n", zxA);
printf("*ptr 的值為:%d \n", *ptr);
//三元運算符
zxA = 10;
zxB = (zxA == 1) ? 20 : 30;
printf("zxb 的值為:%d \n", zxB);
zxB = (zxA == 10) ? 20 : 30;
printf("zxb 的值為:%d \n", zxB);
}
輸出:
zxA sizeOf = 4
zxB sizeOf = 2
zxC sizeOf = 8
zxA 的值為:4
*ptr 的值為:4
zxb 的值為:30
zxb 的值為:20
8. 判斷
C 語言把任何非零和非空的值假定為 true,把零或 null 假定為 false。
C 語言提供了以下類型的判斷語句。
編輯 ?:運算符
跟 Java 一樣
void main(){
int pdNumber;
printf("輸入一個數字:");
scanf("%d", &pdNumber);
(pdNumber % 2 == 0) ? printf("偶數") : printf("基數");
}
9. 迴圈
C 語言提供了以下幾種迴圈類型。
編輯 迴圈控制語句
迴圈控制語句改變你代碼的執行順序。通過它你可以實現代碼的跳轉。
C 提供了下列的迴圈控制語句。
編輯 使用方法可以參考 Java ,下麵給出迴圈的例子:
void main(){
//限制
for (int i = 0; i < 6; i++) {
printf("限制迴圈,%d \n",i);
}
//無限迴圈
for (;;) {
printf("該迴圈會一直執行下去!\n");
}
}
10. 函數
函數定義
C 語言中的函數定義的一般形式如下:
return_type function_name( parameter list )
{
body of the function
}
在 C 語言中,函數由一個函數頭和一個函數主體組成。下麵列出一個函數的所有組成部分:
**返回類型:**一個函數可以返回一個值。return_type是函數返回的值的數據類型。有些函數執行所需的操作而不返回值,在這種情況下,return_type 是關鍵字void。
**函數名稱:**這是函數的實際名稱。函數名和參數列表一起構成了函數簽名。
**參數:**參數就像是占位符。當函數被調用時,您向參數傳遞一個值,這個值被稱為實際參數。參數列表包括函數參數的類型、順序、數量。參數是可選的,也就是說,函數可能不包含參數。
**函數主體:**函數主體包含一組定義函數執行任務的語句。
例子:
/* 函數返回兩個數中較大的那個數 */
int max(int num1, int num2)
{
/* 局部變數聲明 */
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
函數聲明
函數聲明會告訴編譯器函數名稱及如何調用函數。函數的實際主體可以單獨定義。
函數聲明包括以下幾個部分:
return_type function_name( parameter list );
針對上面定義的函數 max(),以下是函數聲明:
int max(int num1, int num2);
在函數聲明中,參數的名稱並不重要,只有參數的類型是必需的,因此下麵也是有效的聲明:
int max(int, int);
當您在一個源文件中定義函數且在另一個文件中調用函數時,函數聲明是必需的。在這種情況下,您應該在調用函數的文件頂部聲明函數。
調用函數
//函數聲明
int max(int num1, int num2);
/**
*C 函數
*/
void main() {
//找出函數中最大值
printf("找出函數中最大值,%d \n",max(66,88));
}
int max(int num1, int num2) {
return (num1 > num2) ? num1 : num2;
}
輸出:找出函數中最大值,88
函數參數
如果函數要使用參數,則必須聲明接受參數值的變數。這些變數稱為函數的形式參數。
形式參數就像函數內的其他局部變數,在進入函數時被創建,退出函數時被銷毀。
編輯 本節知識將會以分節的形式向大家展示,又想要學習C語言的小伙伴可以關註筆者!一起來加油呀~
自學C/C++編程難度很大,不妨和一些志同道合的小伙伴一起學習成長!
C語言C++編程學習交流圈子,企鵝群【1121833361】微信公眾號:C語言編程學習基地
有一些源碼和資料分享,歡迎轉行也學習編程的伙伴,和大家一起交流成長會比自己琢磨更快哦!
編輯