什麼是 C 語言的 swap 函式?徹底解析使用指標交換值與應用方法!

目次

1. 前言

C 語言中的 swap 函式是什麼?

C 語言中,swap 函式(值的交換) 用於交換變數的值。例如,當有兩個變數 a = 5b = 10 時,使用 swap 函式可以將它們改為 a = 10b = 5。 C++ 提供了 std::swap 這樣的標準函式庫,但 C 語言並沒有此類內建函式。因此,在 C 語言中需要自行實作 swap 函式

為什麼在 C 語言中需要自行實作 swap 函式?

與 C++ 不同,C 語言的標準並未提供通用的 swap 函式。因此,需要實作可針對特定資料型別套用的自訂 swap 函式。此外,透過指標可以安全地使用函式交換變數的值。

本文將學習的內容

本文將說明在 C 語言中實作 swap 函式的方法,並介紹其應用,包括陣列與結構體的值交換方法,以及在排序演算法中的使用範例。學習以下內容,可加深對 C 語言程式設計的理解。
  • swap 函式的基本實作方法
  • 使用指標的 swap 函式實作
  • 陣列與結構體的值交換
  • 在排序演算法中的應用方法

2. swap函式的基本實作方法

C語言中,有幾種方法可以交換變數的值(swap)。在此將介紹三種代表性的方法,並說明各自的優缺點。

2.1 使用暫存變數的swap函式

最常見且直觀易懂的方法是使用暫存變數(temporary variable)的方法。如下所示,使用暫存變數temp來交換值。

程式碼範例

#include <stdio.h>

// swap函式(使用指標)
void swap(int *a, int *b) {
    int temp = *a;  // 將 a 的值暫存於暫存變數
    *a = *b;        // 將 b 的值賦給 a
    *b = temp;      // 將暫存變數的值(原本的 a)賦給 b
}

int main() {
    int x = 5, y = 10;

    printf("交換前: x = %d, y = %dn", x, y);
    swap(&x, &y);
    printf("交換後: x = %d, y = %dn", x, y);

    return 0;
}

執行結果

交換前: x = 5, y = 10
交換後: x = 10, y = 5

說明

  1. temp 暫存 a 的值
  2. a 賦予 b 的值
  3. b 賦予 temp 的值(原本 a 的值)

優缺點

方法優點缺點
使用暫存變數可讀性高,且不易產生錯誤會消耗暫存變數的記憶體
此方法因可讀性高且安全,在一般的 C 程式中最被推薦的方式

2.2 使用 XOR 演算的swap函式

利用 XOR(排他或)運算,可在不使用暫存變數的情況下交換變數的值。

程式碼範例

#include <stdio.h>

// 使用 XOR 的 swap 函式
void swap(int *a, int *b) {
    if (a != b) {  // 防止傳入相同位址的情況
        *a = *a ^ *b;
        *b = *a ^ *b;
        *a = *a ^ *b;
    }
}

int main() {
    int x = 5, y = 10;

    printf("交換前: x = %d, y = %dn", x, y);
    swap(&x, &y);
    printf("交換後: x = %d, y = %dn", x, y);

    return 0;
}

執行結果

交換前: x = 5, y = 10
交換後: x = 10, y = 5

優缺點

方法優點缺點
使用 XOR 演算不需要暫存變數,記憶體消耗少可讀性差,且容易產生錯誤

2.3 使用加減算的swap函式

與 XOR 相同,作為不使用暫存變數交換變數值的方法,使用加減算(加法與減法)的方法也存在。

程式碼範例

#include <stdio.h>

// 使用加減算的 swap 函式
void swap(int *a, int *b) {
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
}

int main() {
    int x = 5, y = 10;

    printf("交換前: x = %d, y = %dn", x, y);
    swap(&x, &y);
    printf("交換後: x = %d, y = %dn", x, y);

    return 0;
}

執行結果

交換前: x = 5, y = 10
交換後: x = 10, y = 5

優缺點

方法優點缺點
使用加減算不需要暫存變數,記憶體消耗少有溢位的風險

2.4 各 swap 方法的比較

手法優點缺點適用情境
使用暫存變數可讀性高且安全會稍微消耗記憶體通用程式
使用 XOR 演算可節省記憶體可讀性差,且容易產生錯誤嵌入式系統
使用加減算可節省記憶體有溢位風險特殊情況(數學運算最佳化)

總結

  • C 語言中 swap 函式的三種實作方法 已介紹。
  • 一般而言,「使用暫存變數的方法」 因最安全且可讀性高而被推薦。
  • 使用 XOR 或加減算的方法,會在嵌入式系統或特殊環境中被應用。
年収訴求

3. swap函式與指標的運用

在前一節介紹的swap函式全部都是使用指標。這與C語言中函式參數的處理密切相關。本節將在把握指標基礎的同時,詳細說明為什麼swap函式需要指標

3.1 值傳遞與參照傳遞的差異

在C語言的函式中,預設會執行「值傳遞(call by)」的特性。也就是說,傳入函式的變數會被複製,因而在函式內部的變更不會影響原始變數。

值傳遞的範例

#include <stdio.h>

// 值傳遞的swap函式(錯誤的做法)
void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 5, y = 10;

    printf("交換前: x = %d, y = %dn", x, y);
    swap(x, y);
    printf("交換後: x = %d, y = %dn", x, y);

    return 0;
}

執行結果

交換前: x = 5, y = 10
交換後: x = 5, y = 10  ← 值未被交換!

說明

  • 呼叫 swap(x, y) 時,函式會收到 xy副本
  • 因此,即使在函式內交換 ab原本的 xy 仍不會改變
要解決此問題,需要使用「參照傳遞(call by reference)」

3.2 使用指標的swap函式

透過使用指標,可將變數的位址傳遞給函式,直接修改其值。

使用指標的swap函式

#include <stdio.h>

// 正確的swap函式(使用指標)
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5, y = 10;

    printf("交換前: x = %d, y = %dn", x, y);
    swap(&x, &y);  // 傳遞位址
    printf("交換後: x = %d, y = %dn", x, y);

    return 0;
}

執行結果

交換前: x = 5, y = 10
交換後: x = 10, y = 5

說明

  1. swap(&x, &y); 這樣,傳遞變數 xy位址
  2. swap 函式中,透過指標 ab,可以直接修改原始變數的值
  3. 因此,函式內的變更也會套用到主程式。

3.3 為什麼swap函式需要指標?

如果不使用指標而嘗試執行swap,會因為值傳遞的特性而無法交換值。使用指標則能直接操作原始變數,使swap正確執行。

重點

  • 值傳遞 (swap(int a, int b)) 會傳遞變數的副本,導致swap的結果不會反映到原始變數。
  • 使用指標 (swap(int *a, int *b)) 則傳遞原始變數的位址,能直接修改。

3.4 活用指標的好處

透過使用指標,除了swap函式外,還有以下好處。
指標的活用情境說明
修改函式的參數像swap函式那樣,想在函式內修改變數的值時
陣列的操作因為陣列與指標密切相關,能有效率地操作
動態記憶體管理mallocfree 的記憶體管理
指標在C語言中是非常重要的概念,透過理解swap函式,就能學習指標的基礎

總結

  • 在C語言中,函式的參數預設為值傳遞,因此若在swap函式不使用指標,值不會被交換
  • 使用指標可傳遞變數的位址,直接修改其值
  • 指標除了在swap函式外,亦可用於陣列操作與動態記憶體管理等

4. swap 函式在陣列與結構體的應用

在前一節中,我們介紹了交換基本變數值的 swap 函式。然而,在 C 語言中,不僅可以對普通變數,還可以對 陣列的元素與結構體的成員 應用 swap 函式。本節將詳細說明這些應用方法。

4.1 陣列元素的交換

透過交換陣列的元素,可以 有效地執行排序處理或特定資料操作。為了交換陣列元素,可利用 使用指標的 swap 函式

4.1.1 交換陣列元素的 swap 函式

以下程式碼實作了交換陣列中特定兩個元素的 swap 函式。

程式範例

#include <stdio.h>

// 交換陣列元素的 swap 函式
void swapArrayElements(int arr[], int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);

    printf("交換前的陣列: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("n");

    // 交換陣列元素(第0個與第4個交換)
    swapArrayElements(arr, 0, 4);

    printf("交換後的陣列: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("n");

    return 0;
}

執行結果

交換前的陣列: 1 2 3 4 5 
交換後的陣列: 5 2 3 4 1

說明

  • 呼叫 swapArrayElements(arr, 0, 4) 後,會交換陣列 arr第0個元素與第4個元素
  • 注意點: 若指定 arr 範圍外的索引,會導致 未定義的行為(錯誤的原因),因此需要謹慎使用。

4.2 結構體成員的交換

在 C 語言中,可以使用結構體將多種不同型別的資料彙總。也可以交換這些結構體的實例。

4.2.1 交換結構體值的 swap 函式

以下程式碼實作了 交換整個結構體實例(物件) 的函式。

程式範例

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

// 結構體的定義
typedef struct {
    int id;
    char name[20];
} Person;

// 結構體的 swap 函式
void swapStruct(Person *p1, Person *p2) {
    Person temp = *p1; // 使用暫存變數進行交換
    *p1 = *p2;
    *p2 = temp;
}

int main() {
    Person person1 = {1, "Alice"};
    Person person2 = {2, "Bob"};

    printf("交換前:n");
    printf("Person 1: ID=%d, Name=%sn", person1.id, person1.name);
    printf("Person 2: ID=%d, Name=%sn", person2.id, person2.name);

    // 交換結構體的值
    swapStruct(&person1, &person2);

    printf("交換後:n");
    printf("Person 1: ID=%d, Name=%sn", person1.id, person1.name);
    printf("Person 2: ID=%d, Name=%sn", person2.id, person2.name);

    return 0;
}

執行結果

交換前:
Person 1: ID=1, Name=Alice
Person 2: ID=2, Name=Bob
交換後:
Person 1: ID=2, Name=Bob
Person 2: ID=1, Name=Alice

總結

  • 透過 swap 陣列的元素,可進行資料操作與排序處理。
  • 交換結構體的值,可有效地進行名冊與資料管理。
  • 交換陣列中的結構體,可協助整理大量資料。

5. swap函式活用的排序演算法

在前一節中,說明了使用 swap 函式交換陣列和結構體元素的方法。此 swap 函式也廣泛用於排序演算法。本節將介紹以 swap 函式活用的代表性排序演算法,泡沫排序與堆積排序

5.1 泡沫排序

5.1.1 泡沫排序是什麼?

泡沫排序(Bubble Sort)是一種比較相鄰元素並交換,以此對陣列進行排序的簡單演算法。最基本的排序方法,但因計算量為 O(n²) 且較大,對大規模資料的排序不適合

5.1.2 泡沫排序的實作

程式碼範例
#include <stdio.h>

// swap函式
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 泡沫排序函式
void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) { // 以升序排序
                swap(&arr[j], &arr[j + 1]);
            }
        }
    }
}

int main() {
    int arr[] = {5, 2, 9, 1, 5, 6};
    int size = sizeof(arr) / sizeof(arr[0]);

    printf("排序前的陣列: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("n");

    bubbleSort(arr, size);

    printf("排序後的陣列: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("n");

    return 0;
}

執行結果

排序前的陣列: 5 2 9 1 5 6
排序後的陣列: 1 2 5 5 6 9

5.2 堆積排序

5.2.1 堆積排序是什麼?

堆積排序(Heap Sort)是一種利用稱為堆積的資料結構來重新排列元素的排序演算法。計算量為 O(n log n),效率高,適合對大量資料進行排序。

5.2.2 堆積排序的實作

程式碼範例
#include <stdio.h>

// swap函式
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 調整堆積的函式
void heapify(int arr[], int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && arr[left] > arr[largest])
        largest = left;

    if (right < n && arr[right] > arr[largest])
        largest = right;

    if (largest != i) {
        swap(&arr[i], &arr[largest]);
        heapify(arr, n, largest);
    }
}

// 堆積排序函式
void heapSort(int arr[], int n) {
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    for (int i = n - 1; i > 0; i--) {
        swap(&arr[0], &arr[i]);
        heapify(arr, i, 0);
    }
}

int main() {
    int arr[] = {5, 2, 9, 1, 5, 6};
    int size = sizeof(arr) / sizeof(arr[0]);

    printf("排序前的陣列: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("n");

    heapSort(arr, size);

    printf("排序後的陣列: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("n");

    return 0;
}

執行結果

排序前的陣列: 5 2 9 1 5 6
排序後的陣列: 1 2 5 5 6 9

總結

  • swap函式作為排序演算法的基本要素被活用。
  • 泡沫排序 是簡單的演算法,但不適合大規模資料。
  • 堆積排序 計算量為 O(n log n),作為實用的排序方法被使用。

6. 總結

本篇文章詳細說明了C語言中swap函式的實作方法與應用。在此,我們回顧各章節內容,整理swap函式的重要性與最佳使用方式。

6.1 本篇文章回顧

本篇文章詳細說明了以下主題。
章節內容摘要
1. 前言swap函式的基本概念,以及與C++的std::swap的差異
2. swap函式的基本實作方法使用暫存變數、XOR、加減法實作swap
3. swap函式與指標的運用為何需要指標,值傳遞與參照傳遞的差異
4. 陣列與結構體的swap交換陣列元素與結構體成員的方法及其應用
5. 利用swap函式的排序演算法冒泡排序與堆積排序的實作與比較

6.2 swap函式的最佳使用方式

為了適當運用swap函式,請掌握以下要點。

基本變數的交換

  • 在一般程式中,使用暫存變數的方法最安全
  • 在記憶體受限的環境中,使用XOR或加減法也是有效的(但可讀性會下降)

陣列與結構體元素的交換

  • 交換陣列元素時,利用指標與索引
  • 在交換結構體時,若成員大小較大,使用指標會更有效率

在排序演算法中的運用

  • 在冒泡排序中,頻繁使用swap函式
  • 在堆積排序等高階演算法中,swap函式也是不可或缺的

6.3 進一步學習的內容

在理解swap函式的基礎上,為了進一步提升C語言的程式設計技能,建議學習以下主題。
  • 指標的應用(指標陣列、函式指標)
  • 動態記憶體管理(利用malloc/free的資料管理)
  • 高階排序演算法(快速排序、合併排序)
  • C++中swap函式的運用std::swap 的機制與用法)

6.4 總結

  • C語言中,需要自行實作swap函式。
  • 透過使用指標,swap函式才能正確運作。
  • 在交換陣列或結構體的值時,也能應用swap函式。
  • 在排序演算法(冒泡排序、堆積排序)中,swap函式也發揮作用。
  • 了解C語言的基本概念(指標、記憶體管理、演算法),即可擴大swap函式的應用範圍。
辛苦了。請深化對swap函式的理解,並在實際程式中加以運用!
年収訴求