S SmartDocs
Series: C++ cpp 177 lines · Updated 2026-06-15

advanced_pointers.cpp

C++/Part1_基礎入門/Ch06_指標與參考/advanced_pointers.cpp

// ============================================================
// Ch06 — 進階指標主題(Advanced Pointer Topics)
// C 風格字串、二維陣列、qsort/std::sort callback、指向成員的指標
// 編譯:g++ -std=c++17 -Wall -o advanced_pointers advanced_pointers.cpp
// ============================================================

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <functional>
#include <string>

// ── 函式原型 ──
void demonstrateCStrings();
void demonstrate2DArray();
void demonstrateQsort();
void demonstrateStdSort();
void demonstratePointerToMember();

// ── 主程式 ────────────────────────────────────────
int main() {
    std::cout << "===== Ch06:進階指標主題 =====\n\n";

    demonstrateCStrings();
    demonstrate2DArray();
    demonstrateQsort();
    demonstrateStdSort();
    demonstratePointerToMember();

    return 0;
}

// ── 1. C 風格字串與 char* ──
// C 字串是以 '\0' 結尾的 char 陣列;字串字面量退化為 const char*
void demonstrateCStrings() {
    std::cout << "【1】C 風格字串與 char*\n";

    const char* msg = "Hello";        // 指向唯讀字串字面量
    std::cout << "  msg = " << msg << ",長度 = " << std::strlen(msg) << "\n";

    // 用指標逐字元走訪,直到遇到 '\0'
    std::cout << "  逐字元:";
    for (const char* p = msg; *p != '\0'; ++p) {
        std::cout << *p << " ";
    }
    std::cout << "\n";

    // 用雙指標反轉可修改的 char 陣列(不使用 <algorithm>)
    char buf[] = "ABCDEF";
    char* left  = buf;
    char* right = buf + std::strlen(buf) - 1;
    while (left < right) {
        char tmp = *left;
        *left = *right;
        *right = tmp;
        ++left;
        --right;
    }
    std::cout << "  反轉 \"ABCDEF\" → " << buf << "\n\n";
}

// ── 2. 二維陣列與指標 ──
void demonstrate2DArray() {
    std::cout << "【2】二維陣列與指標\n";

    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};

    // matrix[i][j] 等同 *(*(matrix + i) + j)
    std::cout << "  matrix[1][2] = " << matrix[1][2]
              << " = *(*(matrix + 1) + 2) = " << *(*(matrix + 1) + 2) << "\n";

    // 指向「含 3 個 int 的陣列」的指標
    int (*rowPtr)[3] = matrix;
    std::cout << "  用 row 指標走訪:\n";
    for (int i = 0; i < 2; ++i) {
        std::cout << "    第 " << i << " 列:";
        for (int j = 0; j < 3; ++j) {
            std::cout << rowPtr[i][j] << " ";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

// ── 3. qsort:C 標準庫排序,以函式指標傳入比較規則 ──
int ascendingCmp(const void* a, const void* b) {
    int x = *static_cast<const int*>(a);
    int y = *static_cast<const int*>(b);
    return (x > y) - (x < y);    // 回傳 -1 / 0 / 1
}

int descendingCmp(const void* a, const void* b) {
    int x = *static_cast<const int*>(a);
    int y = *static_cast<const int*>(b);
    return (y > x) - (y < x);
}

static void printArr(const int* arr, int size) {
    for (int i = 0; i < size; ++i) std::cout << arr[i] << " ";
    std::cout << "\n";
}

void demonstrateQsort() {
    std::cout << "【3】qsort(C 風格 callback)\n";

    int data[] = {5, 2, 8, 1, 9, 3};
    int size = sizeof(data) / sizeof(data[0]);

    std::cout << "  原始:";
    printArr(data, size);

    std::qsort(data, size, sizeof(int), ascendingCmp);
    std::cout << "  升序:";
    printArr(data, size);

    std::qsort(data, size, sizeof(int), descendingCmp);
    std::cout << "  降序:";
    printArr(data, size);
    std::cout << "\n";
}

// ── 4. std::sort:型別安全的現代替代,接受 lambda / functor ──
void demonstrateStdSort() {
    std::cout << "【4】std::sort(型別安全 + lambda)\n";

    int data[] = {5, 2, 8, 1, 9, 3};
    int size = sizeof(data) / sizeof(data[0]);

    std::sort(data, data + size, [](int a, int b) { return a < b; });
    std::cout << "  升序:";
    printArr(data, size);

    // 也可用 std::function 儲存比較器
    std::function<bool(int, int)> cmp = [](int a, int b) { return a > b; };
    std::sort(data, data + size, cmp);
    std::cout << "  降序:";
    printArr(data, size);
    std::cout << "\n";
}

// ── 5. 指向成員的指標(Pointer to Member) ──
struct Calculator {
    int value = 0;

    int add(int x)      { return value + x; }
    int multiply(int x) { return value * x; }
};

void demonstratePointerToMember() {
    std::cout << "【5】指向成員函式的指標\n";

    Calculator calc;
    calc.value = 10;

    // 宣告指向成員函式的指標:回傳型別 (類別::*名稱)(參數)
    int (Calculator::*opPtr)(int) = &Calculator::add;

    // 透過物件呼叫用 .*,透過指標呼叫用 ->*
    std::cout << "  (calc.*opPtr)(5)  = " << (calc.*opPtr)(5) << "\n";

    Calculator* pc = &calc;
    opPtr = &Calculator::multiply;
    std::cout << "  (pc->*opPtr)(5)   = " << (pc->*opPtr)(5) << "\n";

    // 成員函式指標陣列:常用於選單 / 狀態機
    using MemberOp = int (Calculator::*)(int);
    MemberOp ops[] = {&Calculator::add, &Calculator::multiply};
    const char* names[] = {"add", "multiply"};
    for (int i = 0; i < 2; ++i) {
        std::cout << "  " << names[i] << "(3) = " << (calc.*ops[i])(3) << "\n";
    }

    // std::mem_fn 把成員函式包成可呼叫物件
    auto fn = std::mem_fn(&Calculator::add);
    std::cout << "  std::mem_fn add(7) = " << fn(calc, 7) << "\n";
}

Related articles