【簡單地過一遍C語言基礎部分】所有知識點,點到為止!(僅一萬多字)

2021-09-25 18:00:02

前言:

就在前幾天,C語言入門到進階部分的專欄——《維生素C語言》終於完成了。全文共計十八個章節並附帶三張筆試練習篇,美中不足的是,第一章和第二章是以截圖形式展現的。由於本人一開始是在有道雲筆記上寫的初稿,當時想方便省事(有道雲排版個人感覺確實比較美觀)就直接以截圖的形式完成了第一章和第二章。本人考慮到因為是截圖,不能複製文中出現的程式碼,不方便讀者進行復制貼上,所以我打算重新寫一下第一章和第一章的內容,並且重新進行了排版。

本章從如何寫主函數開始講起,對C語言基礎知識點進行蜻蜓點水地介紹,想看詳細講解教學請訂閱專欄!專欄連線:《維生素C語言》


一、如何寫程式碼

0x00 首先寫主函數

❓ 何為main函數?

main函數,又稱主函數,是程式執行的起點。

1. 主函數是程式的入口

2. 主函數有且只有一個

📚 一個工程中可以有多個「.c檔案」,但是多個「.c檔案」中只能有一個「main 函數」

0x01 然後寫程式碼

💬  "你好,世界!"

#include <stdio.h> //標頭檔案
int main()
{
    printf("hello world!\n");
    return 0;
}

0x02 最後執行程式

🔨 編譯 + 連結 + 執行程式碼

快捷鍵: Ctrl + F5VS2013

[偵錯] -> [選擇' 開始執行(不偵錯)']

❓ 「是不是有什麼一閃而過了?」

因為程式執行得太快,所以沒有看到結果。

為了看到結果,我們需要設定一下 VS2013 的屬性 ( VS2019不需要設定專案屬性 )

[解決方案資源管理器] -> [右鍵專案名稱] -> [屬性] -> [連結器] -> [系統]
-> [子系統] -> [選擇' 控制檯(/SUBSYSRTEM:CONSOLE) ']

🚩 執行結果如下:

二、資料型別

0x00 基本型別

📚 這裡先做些簡單的介紹:

💬 基本資料型別的使用方法:

int main(void)
{
    char ch = 'a';
    int age = 20;
    float weight = 50.8;
    double d = 0.0;
    
    return 0;
}

0x01 格式說明

📚 格式說明由「%」和格式字元組成:

💬 演示:

int main()
{
    printf("%d\n", 100);
    printf("%c\n", 'a');

    float foo = 5.0;
    printf("%f\n", foo);

    double pi = 3.14;
    printf("%.2lf\n", pi); // .xf(x為小數點保留幾位數)

    char str1[] = "hello";
    printf("%s\n", str1);

    int a = 10;
    printf("%p\n", &a);

    return 0;
}

🚩 執行結果: 100 a 5.000000 3.14 hello 0000000000061FE04

0x03 資料型別的大小

📺 32位元系統下:

📚 sizeof 函數:獲取資料在記憶體中所佔用的儲存空間,以位元組為單位計數

💬 使用方法演示:

int main(void)
{
    char a = 'A';
    printf("%d\n", sizeof(a))
    printf("%d\n", sizeof a) //求變數時可省略括號 ✅
    
    printf("%d\n", sizeof(char));
    printf("%d\n", sizeof char); //error!但是求字元型別時不可省略 ❌

    return 0;
}

🚩 執行結果:1

💬 使用 sizeof 求元素個數:

int main(void)
{
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    printf("%d\n", sizeof(arr)); //計算的是陣列的總大小,單位是位元組
    printf("%d\n", sizeof(arr[0])); //計算的是陣列首字元大小
    int sz = sizeof(arr) / sizeof(arr[0]);
    printf("%d\n", sz);
    
    return 0;
}

🚩 執行結果: 40  4  10

📚 計算機中的單位: bit - 位元位

計算機中識別二進位制:1&0         8進位制:0-7        10進位制:0-9

 

 三、變數與常數

0x00 建立變數

 💬 程式碼演示:

#include <stdio.h>

int main(void)
{
    int age = 20;
    double weight = 62.5;

    age = age + 1;
    weight = weight - 10;
    printf("%d\n", age);
    printf("%lf\n", weight);

    return 0;
}

 

0x01 全域性變數和區域性變數

 

💬 區域性變數和全域性變數的名字相同時,區域性變數優先,對區域性影響:

int var = 100;
int main(void)
{
    int var = 10;
    printf("%d\n", var);  
    
    return 0;
}

🚩 執行結果: 10

 

0x02 scanf 函數

💬 使用方法演示:

int main(void)
{
    int a = 0;
    scanf("%d", &a);
    printf("%d", a);
    
    return 0;
}

0x03 變數的使用

💬 使用方法演示:寫一個程式碼求兩個變數的和

int main(void)
{
    int a = 0;
    int b = 0;
    int sum = 0;
    
    scanf("%d %d", &a, &b);
    sum = a + b;
    printf("sum = %d\n", sum);

    return 0;
}

❗ 如果編譯器發出了警告,說 scanf 不安全,在程式碼前面新增

#define _CRT_SECURE_NO_WANRINGS 1

即可,當然還有其他方法可以解決,這裡就不細說了。

 

🚩 執行結果如下:(假設輸入了 1 2)

sum = 3

0x04 作用域和生命週期

📚 作用域(scope)

程式設計概念,通常來說,一段程式程式碼中所用到的名字並不總是有效/可用 的 而限定這個名字的可用性的程式碼範圍就是這個名字的作用域。

全域性變數的作用域是整個工程。

區域性變數的作用域是變數所在的區域性範圍。

📚 生命週期:

變數的生命週期:變數的建立和銷燬之間的時間段

區域性變數的生命週期:進入作用域生命週期開始,出作用域生命週期結束。

全域性變數的生命週期:整個程式的生命週期。

💬 區域性變數的生命週期:

int main()
{
    {
        int a = 10;
        printf("%d\n", a);
    }
    printf("%d\n", a); //error 生命週期結束了
}

💬 全域性變數的生命週期

//宣告一下變數
extern int g_val;
int main()
{
    printf("%d", g_val);
}

0x05 常數

📚 定義:C語言中常數和變數的定義的形式有所差異

C語言的常數分為以下幾種:

① 字面常數:直接寫

const 修飾的常變數:用 const 定義

#define 定義的識別符號常數:宏定義

④ 列舉常數:可以一一列舉的常數

💬 字面常數:

int main(void)
{
    3.14;
    10;
    'a';
    "abcdef";
}

💬 const 修飾的常數:

int main(void)
{
    const int num = 10;
    num = 20; //error, 不能修改
    printf("num = %d\n", num);
}

🚩 執行結果: 10

💬 #define 定義的識別符號常數:

#define MAX 10000  // 不寫=,不加分號!

int main(void)
{
    int n = MAX;
    printf("%d\n", n);
}

🚩 執行結果:10000

💬 列舉常數:

//性別
enum Sex {
    //這種列舉型別的變數的未來可能取值
    //列舉常數
    MALE = 3, //賦初值
    FEMALE,
    SECRET
};

int main(void)
{
    enum Sex s = MALE;
    printf("%d\n", MALE);
    // MALE = 3 error 不可修改
    printf("%d\n", FEMALE);
    printf("%d\n", SECRET);

    return 0;
}

📌 注意事項:

const 只是一個有常屬性的變數,本質上仍然為變數!arr[], 陣列的大小必須是常數!

int main()
{   
    const int n = 10; //n是變數,但是又有常屬性,所以我們說n是常變數
    int arr[n] = {0}; // 仍然不可以,因為n是變數,只是有常屬性而已
    
    return 0;
}

💬 #define 定義的可以,宏定義用得最多的地方是在陣列中用於指定陣列的長度:

#define N 10
int main()
{
    int arr[N] = {0};
    
    return 0;
}

📌 注意事項:

列舉常數雖然是不能改變的,但是通過列舉常數創造出來的變數是可以改變的!

enum Color 
{
    // 列舉常數
    RED,
    YEELOW,
    BULE
};

int main(void)
{
    enum Color c = BULE; //我們建立一個變數c,並將BULE賦給它
    c = YEELOW; //這時將YEELOW賦給它,完全沒有問題 ✅
    BULE = 6; //error!列舉常數是不能改變的  ❌
    return 0;
}

四、字串&跳脫字元&註釋

0x00 字串

📚 定義:

"hello world."

這種由雙引號(Double Quote)引起來的一串字元稱為字串字面值(String Literal)

📚 關於斜槓零:

字串的結束標誌是一個 \0 跳脫字元。

在計算字串長度的時候 \0 是結束標誌,不算字串的內容!

💬 下面程式碼,列印的結果是什麼?為什麼?

int main(void)
{
    char arr1[] = "abc"; //陣列
    // "abc" -- 'a' 'b' 'c' '\0' 
    // 這裡面,'\0' 字串的結束標誌
    char arr2[] = {'a', 'b', 'c'};
    char arr3[] = {'a', 'b', 'c', '\0'};

    printf("%s\n", arr1);
    printf("%s\n", arr2);
    printf("%s\n", arr3);

    return 0;
}

🚩 列印結果如下:

 

0x01 計算字串長度

📚 strlen 函數:返回字串的長度

📜 使用時需引入標頭檔案 <string.h>

 

💬 程式碼演示:

#include <stdio.h>
#include <string.h>

int main()
{
    char arr1[] = "abc";
    char arr2[] = {'a', 'b', 'c'};
    printf("%d\n", strlen(arr1));
    printf("%d\n", strlen(arr2));

    return 0;
}

 🚩 執行結果如下:  3   隨機值

 

 

0x02 ASCII 碼值

📚 ASCII (American Standard Code for Information Interchange)

「是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語和其他西歐語言。它是最通用的資訊交換標準,並等同於國際標準ISO/IEC 646。ASCII第一次以規範標準的型別發表是在1967年,最後一次更新則是在1986年,到目前為止共定義了128個字元」

 

0x03 跳脫字元

📚 轉意字元顧名思義就是轉變字元的意思。

 

💬 讓斜槓就是斜槓:

int main()
{
    printf("c:\\test\\32\\test.c"); //再加一個斜槓,規避跳脫字元檢測
    
    return 0;
}

 🚩 執行結果:  c:\test\32\test.c

💬 三字母詞、輸出單引號、ddd、xdd:

int main()
{
    printf("(are you ok?\?)\n"); // ??) -- ] - 三字母詞
    printf("%c\n", '\''); //輸出一個單引號
    printf("%s\n", "\""); //輸出一個雙引號 

    printf("%c\n", '\130');//8進位制的130是10進位制的多少呢?
    //X - ASCII碼值是88
    printf("%c\n", '\101'); // A- 65 - 8進位制是:101
    printf("%c\n", '\x30'); //48 - '0'
    
    return 0;
}

🚩 執行結果:  (are you ok??) ' " X A 0

❓ 下列程式碼列印的結果是什麼?

int main()
{
    printf("%d\n", strlen("c:\test\328\test.c"));
    
    return 0;
}   

💡 答案:14

 

0x04 註釋

📚 程式碼中有不需要的程式碼可以直接刪除,也可以註釋掉

程式碼中有些程式碼比較難懂,可以加一下注釋文字

有兩種風格:

① C語言風格的註釋   /* xxxxxx */

缺陷:不能巢狀註釋

② C++風格的註釋    //xxxxxxxxx

優點:可以註釋一行也可以註釋多行

快捷鍵:Ctrl + /?

💬 演示:

/*  C語言風格註釋
int Add(int x, int y) {
    int z = 0;
    z = x + y;
    return z;
}
*/

int Add(int x, int y) {
    return x + y;
}

int main(void)
{
    // C++註釋風格
    // int a = 10;
    printf("%d\n", Add(1,2)); //呼叫Add函數

    return 0;
}

五、分支和迴圈

 0x00 if 語句

📚 定義:if 語句是指程式語言(包括c語言、C#、VB、java、組合語言等)中用來判定所給定的條件是否滿足,根據判定的結果(真或假)決定執行給出的兩種操作之一。

 

💬 選擇語句程式碼演示:

int main(void)
{
    int a = 10;
    int b = 20;
    
    if(a>b) {
        printf("a比b大\n") ;
    } else {
        printf("b比a大\n");
    }

    return 0;
}

🚩 執行結果:  b比a大

❓  C語言中如何實現迴圈呢?

1. while 語句

2. for 語句

3. do ... while 語句

這裡我們著重先了解下 while 語句。

📚 while 迴圈的基本概念:while是計算機的一種基本回圈模式。當滿足條件時進入迴圈,進入迴圈後,當條件不滿足時,跳出迴圈。

 

💬 演示程式碼:敲三萬行程式碼

#include <stdio.h>

int main(void)
{
    int line = 0;
    while(line < 30000) {
        printf("敲程式碼: %d\n", line);
        line++;
    }
    if(line == 30000) {
        printf("恭喜你敲滿30000行程式碼!\n");
    }

    return 0;
}

六、函數

❓ 什麼是函數?

數學中的函數 f(x) = 2×x+5,C語言中的函數也是一樣的。

📚 函數的特點就是:簡化程式碼,程式碼複用。

 

💬 程式碼演示:

int Add (int x, int y) {
    int z = 0;
    z = x + y;
    return z;
}

int main(void)
{
    int num1 = 0;
    int num2 = 0;
    scanf("%d%d", &num1, &num2);

    // int sum = num1 + num2;
    // 函數的方式解決
    int sum = Add(num1, num2);
    printf("%d\n", sum);

    return 0;
}

 

七、陣列

📚 要儲存1-10的數位,怎麼儲存?

「C語言給了陣列的定義:一組相同型別元素的集合」

定義一個整型陣列,最多放十個元素:

 

💬 程式碼演示:

int main()
{
    int a = 0;
    int b = 0;
    int c = 0;
    int d = 0;
    //...

    // 10個整型1-10存起來
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    char ch[5] = {'a', 'b', 'c'}; // 不完全初始化,剩餘的預設為0
    
    // 用下標就可以存取元素
    printf("%d\n", arr[0]);
    
    // 列印整個陣列
    int i = 0;
    while(i<10) {
        printf("%d ", arr[i]);
        i++;
    }
    
    return 0;
}

 

八、操作符簡單介紹

0x00 算數操作符

❓ 什麼是算數操作符?

📚 算術運運算元即算術運運算元號。是完成基本的算術運算 (arithmetic operators) 符號,就是用來處理四則運算的符號。

 

💬 程式碼演示:

int main()
{
    int add = 1 + 1;
    int sub = 2 - 1;
    int mul = 2 * 3;
    float div = 9 / 2.0; //只要有浮點數出現,執行的就是浮點數除法
    int mod = 123 % 10;

    return 0;
}

0x01 移位元運算符

❓ 什麼是移位元運算符?

📚 移位運運算元在程式設計中,是位元運算運運算元的一種。移位運運算元可以在二進位制的基礎上對數位進行平移。

 

💬 程式碼演示:

int main()
{   
    // 移位元運算符 移動的是它的二進位制位
    // << 左移
    // >> 右動
    int a = 1;
    // 整形1佔4個位元組-32bit位
    // 0000000000000000000000000000001
    int b = a<<1;
   // 0000000000000000000000000000010  左邊丟棄,右邊補0
    printf("%d\n", b);
    printf("%d\n", a);

    return 0;
}

🚩  執行結果: 2 1

0x02 位元運算符

❓ 什麼是位元運算符?

📚 位元運算是程式設計中對位元型樣按位元或二進位制數的一元和二元操作

💬 程式碼演示:

#include <stdio.h>

int main()
{
    //位元運算 依然是二進位制位

    // & 按位元與   都為真,則返回真,只要出現假,就返回假
    int a = 3; //真
    int b = 5; //真
    int c = a&b; //按位元與
    // 011
    // 101
    // 001
    // R→ 1 //真
    printf("%d\n", c);
    
    int d = a|b;// 按位元或  有真則為真,無則假,只要出現真,就返回真
    // 011
    // 101
    // 111
    // R→ 7
    printf("%d\n", d);

    int e = a^b;// 按位元互斥或  相同為假,相異為真   11\ 00-> 0   10 -> 1
    //互斥或的計算規律
    //對應的二進位制位相同,則為0
    //對應的二進位制位相異,則為1
    // 011
    // 101
    // 110
    // R→
    printf("%d\n", e);
    
    return 0;
}

0x03 賦值操作符

❓ 什麼是賦值操作符?

📚 賦值運運算元是雙目運運算元,用在賦值表示式中。賦值運運算元將值儲存在運運算元左邊運算元指定的變數中。

 

💬 程式碼演示:

#include <stdio.h>

int main()
{
    int a = 10;
    a = 20; // 「=」 賦值  「==」 判斷相等

    a = a+10; //1
    a += 10; // 2
    
    a = a-20;
    a -= 20;

    a = a & 2;
    a &= 2;
    //這些操作叫做 複合賦值符
    
    return 0;
}

0x04 單目操作符

❓ 什麼是單目操作符?

📚 單目操作符,也就是隻接受一個運算元的操作符。

 

💬 邏輯反操作

int main()
{
    //0表示假,非0就是真
    int a = 5;
    printf("%d\n", !a);

    if(a) {
        //如果a為真,做事
    }
    if(!a) {
        //如果a為假,做事
    }

    while(a); //a != 0,做事
    while(!a); //a=0,做事

    return 0;
}

 

💬 按位元取反 ~

int main()
{
    int a = 0;
    printf("%d\n", ~a);
    // ~ 按(二進位制)位取法 
    //把所有二進位制位的數位,1變成0,0變成1

    //整數a
    // 0
    // 00000000000000000000000000000000
    // 11111111111111111111111111111111  ~a
    // 資料在記憶體中儲存的是二補數
    // 一個整數的二進位制表示有三種: 原碼 反碼 二補數
    // 負數的計算  -1:
    // 10000000000000000000000000000001 (原碼)
    // 11111111111111111111111111111110 (反碼)
    // 11111111111111111111111111111111 (二補數) -> 在記憶體中存的

    // 正的整數: 原碼、反碼、二補數相同

    return 0;
}

💬 前置++

int main()
{
    int a = 10;
    int b = ++a; //前置++, 先++後使用
    
    printf("%d\n", b); //11
    printf("%d\n", a); //11

    return 0;
}

💬 後置++

int main()
{
    int a = 10;
    int b = a++; //後置++,先使用再++

    printf("%d\n", b);
    printf("%d\n", a);

    return 0;
}

💬 強制型別轉換:

int main()
{
    int a = (int)3.14; //強制型別轉換
    printf("%d\n", a);

    return 0;
}

0x05 邏輯操作符

📚 邏輯運運算元或邏輯聯結詞把語句連線成更復雜的複雜語句

邏輯與:兩個都為真即為真(and)

邏輯或:一個為真即為真(or)

 

💬 邏輯與 &&

int main()
{
    int a = 3;
    int b = 5;
    int c = a && b;
    printf("%d\n", c); //1

    return 0;
}

 

💬 邏輯或 ||

int main()
{
    int a = 3;
    int b = 0;
    int c = a||b;
    printf("%d\n", c); //1
    
    return 0;
}

0x06 條件操作符

📚 條件操作符就是三目操作符

exp1成立,exp2計算,整個表示式的結果是:exp2的結果。

exp1不成立,exp2計算,整個表示式的結果是:exp3的結果。

 

💬 條件操作符的用法:

int main()
{
    //exp1成立,exp2計算,整個表示式的結果是:exp2的結果
    //exp1不成立,exp3計算,整個表示式的結果是exp3的結果
    int a = 0;
    int b = 3;
    int max = 0;

    /* 等價於
    if(a>b) {
        max = a;
    } else {
        max = b;
    }
    */

    max = a>b ? a : b;

    return 0;
}

0x07 逗號表示式

📚 逗號表示式:逗號隔開的一串表示式。

逗號表示式是從左向右依次計算的。

整個表示式的結果是最後一個表示式的結果。

 

💬 逗號表示式的用法演示:

int main()
{
    (2, 3+5, 6);
    int a = 0;
    int b = 3;
    int c = 5;
            // a=5   c=5-4  b=1+2
    int d = (a=b+2, c=a-4, b=c+2);
    printf("%d\n", d); // 3

    return 0;
}

0x08 下標參照操作符

📚  [] 就是下標參照操作符。

💬 演示:

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    printf("%d\n", arr[5]); // 6

    return 0;
}

0x09 函數參照操作符

📚 呼叫函數時,函數名後面的()就是函數呼叫操作符

💬 演示:

int main()
{   
    printf("hehe\n");
    printf("%d", 100);

    return 0;
}

九、關鍵字

0x00 常見關鍵字

📚 C語言提供的關鍵字:

1. C語言提供的,不能自己建立關鍵字

2. 關鍵字不能做變數名

 這裡我們來簡單地介紹幾個:

💬 auto - 自動的

int main()
{
    {
        int a = 10; //自動建立,自動銷燬的 - 自動變數
        // auto省略掉了
        auto int a = 10;
        // auto新的C語言中也有其它用法 - 暫時不考慮
    }

    return 0;
}

💬 register - 寄存關鍵字

int main()
{
    // 大量/頻繁使用的資料,想放在暫存器中,提升效率
    register int num = 100; //建議num的值存放在暫存器中
    //是不是最終放到暫存器中是編譯器說的算

    // 其實現在編輯器已經很聰明瞭,
    // 就算你不主動加register,它也會幫你存到暫存器中。
    return 0;
}

💬 typedef - 型別重新命名

// 這種羅裡吧嗦的變數我們可以把它重新命名一下
typedef unsigned int u_int;
int main()
{
    unsigned int num = 100;
    u_int num2 = 100; //和上面是等價的

    return 0;
}

📚 static - 靜態的

1. static修飾區域性變數

2. static修飾全域性變數

3. static修飾函數

💬 static修飾區域性變數

函數中區域性變數:

宣告週期延長:該變數不隨函數結束而結束

初始化:只在第一次呼叫該函數時進行初始化

記憶性:後序呼叫時,該變數使用前一次函數呼叫完成之後儲存的值

儲存位置:不會儲存在棧上,放在資料段

void test() {
    static int a = 1; //不銷燬,生命週期變長了
    a++;
    printf("%d ", a);
}

int main()
{
    int i = 0;
    while(i<10) {
        test();
        i++;
    }

    return 0;
}

🚩 執行結果: 2 3 4 5 6 7 8 9 10 11

 

 

💬 static修飾全域性變數

改變該變數的連結屬性,讓該變數具有檔案作用域,即只能在當前檔案中使用。

① Global.c:

static int g_val = 2021;
// static 修飾全域性變數,
// 使得這個全域性變數只能在自己所在的原始檔(.c)內部可以使用
// 其他的原始檔不能使用!

// 全域性變數,在其他原檔案內部可以被使用,是因為全域性變數具有外部連結屬性
// 但是被static修飾之後,就變成了內部連結屬性,
// 其他的原始檔就不能連結到這個靜態的全域性變數了!

② test.c:

extern int g_val;

int main()
{
	printf("%d\n", g_val);

	return 0;
}

🚩 執行結果: test.obj : error LNK2001: 無法解析的外部符號 _g_val

 

💬 static修飾函數

改變該函數的連結屬性,讓該函數具有檔案作用域,即只能在當前檔案中使用。

① Add.c:

//static修飾函數,
static int Add(int x, int y) {
	return x + y;
}

💬 test1.c:

extern int Add(int, int); //宣告外部函數

int main()
{
	int a = 10;
	int b = 20;
	int sum = Add(a, b);
	printf("sum = %d\n", sum);

	return 0;
}

🚩 執行結果:

test.obj : error LNK2019: 無法解析的外部符號 _Add,該符號在函數 _main 中被參照

 

0x01 define

📚 define 是一個預處理指令:

1. define 定義識別符號常數

2. define 定義宏

💬 define 定義識別符號常數:

#define MAX 1000
int main()
{
    printf("%d\n", MAX);
    return 0;
}

💬 define 定義宏:

#define ADD(X, Y) X+Y
#define ADD1(X, Y) ((X)+(Y))
int main()
{
    printf("%d\n", 4*ADD(2, 3));
    //             4*2+3 = 11
    printf("%d\n", 4*ADD1(2, 3));
    //             4*(2+3) = 20
    
    return 0;
}

十、指標初探

0x00 指標介紹

❓ 什麼是指標?

指標就是地址,地址就是指標。

指標,是C語言中的一個重要概念及其特點,也是掌握C語言比較困難的部分。指標也就是記憶體地址,指標變數是用來存放記憶體地址的變數,不同型別的指標變數所佔用的儲存單元長度是相同的,而存放資料的變數因資料的型別不同,所佔用的儲存空間長度也不同。有了指標以後,不僅可以對資料本身,也可以對儲存資料的變數地址進行操作。

 

💬 變數都有地址,取出變數的地址如下:

int main()
{
    int a = 10; // a在記憶體中要分配空間 - 4個位元組
    &a; // 取出num的地址
    printf("%p\n", &a); //%p - 以地址的形式列印
    
    return 0;
}

🚩 列印出來的是a的地址

 

💬 定義指標變數,儲存地址

* 說明 pa 是指標變數

int 說明 pa 執行的物件是 int 型別的

int main()
{
    int a = 10;
    int* pa = &a; // pa是用來存放地址的,在C語言中叫pa的是指標變數
    
    char ch = 'w';
    char* pc = &ch;
    
    return 0;
}

0x01 解除參照操作

如果把定義指標理解為包裝成快遞,那麼「解除參照操作」就可以理解為是拆包裹

拆出來的值就是那個變數的值,甚至還可以通過「解除參照」來修改它的值。

💬 解除參照操作用法:

int main()
{
    int a = 10;
    int* pa = &a;

    *pa = 20; // * 解除參照操作   *pa就是通過pa裡邊的地址,找到a
    printf("%d\n", a); //20
    
    return 0;
}

0x02 指標的大小

📚 指標的大小

「指標的大小是相同的」

❓ 為什麼相同?

「因為指標是用來存放地址的,指標需要多大空間,取決於地址的儲存需要多大空間」

📺 指標是一種複合資料型別,指標變數內容是一個地址,因此一個指標可以表示該系統的整個地址集合,故按照32位元編譯程式碼,指標占4個位元組,按照64位元編譯程式碼,指標占8個位元組(注意:不是64位元系統一定佔8個位元組,關鍵是要按照64位元方式編譯)。

32位元 - 32bit - 4byte

64位元 - 64bit - 8byte

💬 sizeof 計算指標的大小:

int main()
{
    printf("%d\n", sizeof(char*));
    printf("%d\n", sizeof(short*));
    printf("%d\n", sizeof(int*));
    printf("%d\n", sizeof(long*));
    printf("%d\n", sizeof(long long*));
    printf("%d\n", sizeof(float*));
    printf("%d\n", sizeof(double*));

    return 0;
}

32位元下都是 4         64位元下都是 8

十一、結構體

0x00 什麼是結構體

📚 結構體可以讓C語言建立出新的型別

「結構體是C語言中特別重要的知識點,結構體使得C語言有能力描述複雜的型別」

💬 使用結構體描述學生 / 描述書:

// 建立一個學生的型別
struct Stu {
    char name[20]; // 姓名
    int age; // 年齡
    double score; // 分數
};  // ← 不要忘了加分號

// 建立一個書的型別
struct Book {
    char name[20];
    float price;
    char id[30];
};

💬 結構體的初始化:

點操作符和箭頭操作符

. 結構體變數.成員

-> 結構體指標->成員

struct Stu {
    char name[20]; // 姓名
    int age; // 年齡
    double score; // 分數
};

struct Book {
    char name[20];
    float price;
    char id[30];
};

int main()
{
    struct Stu s = {"張三", 20, 85.5}; // 結構體的建立和初始化
    // 點操作符
    printf("1: %s %d %lf\n", s.name, s.age, s.score);

    struct Stu* ps = &s;
    printf("2: %s %d %lf\n", (*ps).name, (*ps).age, (*ps).score); // ❎
    // 箭頭操作符
    printf("3: %s %d %lf\n", ps->name, ps->age, ps->score); // ✅

    return 0;
}


參考文獻 / 資料

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

俞甲子 / 石凡 / 潘愛民. 《程式設計師的自我修養》[M]. 電子工業出版社, 2009-4.

百度百科[EB/OL]. []. https://baike.baidu.com/.

位元科技. C語言基礎[EB/OL]. 2021[2021.8.31]. .

本章完。