本文針對三種字符串排序實現進行深度剖析:指針數組冒泡排序、指針數組選擇排序、二維數組直接交換冒泡排序。重點解釋為什麼第一段代碼運行錯誤,而後兩段卻正確,並給出修正後的標準寫法。
| 版本 | 數據結構 | 交換對象 | 循環邊界 | 結果 |
|---|---|---|---|---|
| 冒泡+指針 | char *p[N] 指向 char ptr[N][80] | 交換指針 p[j]、p[j+1] | j < N-i ❌ | 越界/錯誤 |
| 選擇+指針 | 同上 | 交換指針 p[i]、p[j] | j = i+1; j < N ✅ | 正確 |
| 冒泡+直接交換 | char ptr[N][80] 二維數組 | strcpy 交換整行字符串 | j < N-i ❌ | 正確(因緩衝區足夠大) |
原錯誤代碼:
for(i=0; i<N-1; i++)
for(j=0; j<N-i; j++) // ❌ 當 j = N-i-1 時,j+1 = N-i 越界訪問 p[N]
if(strcmp(p[j], p[j+1]) > 0) swap(p[j], p[j+1]);
修正邊界:內層循環應為 j < N-1-i(或 j < N-i-1),確保 j+1 最大為 N-1。
#include <stdio.h>
#include <string.h>
#define N 5
int main() {
char ptr[N][80] = { "how ", "are ", "you ", "i", "fine" };
char *p[N];
char *temp;
int i, j;
for (i = 0; i < N; i++) p[i] = ptr[i];
// 冒泡排序:每輪將最大值「冒泡」到末尾
for (i = 0; i < N - 1; i++) {
for (j = 0; j < N - 1 - i; j++) { // ✅ 正確邊界
if (strcmp(p[j], p[j+1]) > 0) {
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
for (i = 0; i < N; i++) puts(p[i]);
return 0;
}
選擇排序內層循環 for(j=i+1; j<N; j++) 只訪問 p[i] 與 p[j],不存在 j+1 越界,邏輯天然安全。
strcpy(temp, ptr[j]);
strcpy(ptr[j], ptr[j+1]);
strcpy(ptr[j+1], temp);
每次交換需複製整行字符(最長 80 字節),而指針交換僅 4/8 字節。**大數據量時指針版本優勢明顯**。
qsort(p, N, sizeof(char*), (int(*)(const void*,const void*))strcmp);j+1 訪問時。j, p[j], p[j+1] 觀察越界情況。掌握指針排序的邊界條件與交換策略,是 C 語言進階的必修課。