《Head First C 中文版》審讀筆記(二)
《Head First C 中文版》第 327 頁:
假設有一個整型陣列,你想升序排列它們,比較器函式應該長什麼樣子?
int scores[] = { 543, 323, 32, 554, 11, 3, 112 };
觀察 qsort() 接收的比較器函式的簽名,會發現它接收兩個 void*,也就是兩個 void 指標。我們在使用 malloc() 時碰到過它,void 指標可以儲存任何型別資料的地址,但使用前必須把它轉換為特定的型別。
qsort() 函式兩兩比較陣列元素,然後以正確的順序排列它們。qsort() 通過呼叫傳給它的比較器函式來比較兩個元素的大小。
int compare_scores(const void* score_a, const void* score_b) { ... }
值以指標的形式傳給函式,因此要做的第一件事就是從指標中提取整型值。
int a = *(int*)score_a; // 你需要把 void 指標轉換為整型指標。 int b = *(int*)score_b; // 第一個 * 就能得到儲存在地址 score_b 中的整型值了。
如果 a 大於 b,需要返回正數;如果 a 小於 b,就返回負數;如果相等,返回 0 值。對整型來講這很簡單,只要將兩數相減就行了:
return a - b; // 如果 a > b,就是正數;如果 a < b,就是負數;如果 a、b 相等,就是 0 。
下面是用 qsort() 排序這個陣列的方法:
qsort(scores, 7, sizeof(int), compare_scores);
然後,根據本書第 330~332 頁的程式碼,得到以下 test_drive.c:
1: #include <stdio.h>
2: #include <string.h>
3: #include <stdlib.h>
4:
5: // 升序排列整型得分。
6: int compare_scores(const void *score_a, const void *score_b)
7: {
8: int a = *(int *)score_a;
9: int b = *(int *)score_b;
10: return a - b;
11: }
12:
13: // 降序排列整型得分。
14: int compare_scores_desc(const void *score_a, const void *score_b)
15: {
16: int a = *(int *)score_a;
17: int b = *(int *)score_b;
18: return b - a; // 如果用第二個數減第一個,可以反轉最終的排序
19: }
20:
21: // 矩形型別。
22: typedef struct {
23: int width;
24: int height;
25: } rectangle;
26:
27: // 按面積從小到大排列矩形。
28: int compare_areas(const void *a, const void *b)
29: {
30: rectangle *ra = (rectangle *)a;
31: rectangle *rb = (rectangle *)b;
32: int area_a = (ra->width * ra->height);
33: int area_b = (rb->width * rb->height);
34: return area_a - area_b;
35: }
36:
37: // 按字母序排列名字,區分大小寫
38: int compare_names(const void *a, const void *b)
39: {
40: char **sa = (char **)a;
41: char **sb = (char **)b;
42: return strcmp(*sa, *sb);
43: }
44:
45: // 按面積從大到小排列矩形。
46: int compare_areas_desc(const void *a, const void *b)
47: {
48: return compare_areas(b, a); // 或者也可以寫 -compare_areas(a, b)。
49: }
50:
51: // 按逆字母序排列名字,區分大小寫
52: int compare_names_desc(const void *a, const void *b)
53: {
54: return compare_names(b, a); // 或者也可以寫 -compare_names(a, b)。
55: }
56:
57: int main()
58: {
59: int scores[] = { 543, 323, 32, 554, 11, 3, 112 };
60: int i;
61: qsort(scores, 7, sizeof(int), compare_scores_desc);
62: puts("These are the scores in order:");
63: for (i = 0; i < 7; i++) {
64: printf("Score = %i\n", scores[i]);
65: }
66: char *names[] = {"Karen", "Mark", "Brett", "Molly"};
67: qsort(names, 4, sizeof(char *), compare_names);
68: puts("These are the names in order:");
69: for (i = 0; i < 4; i++) {
70: printf("%s\n", names[i]);
71: }
72: return 0;
73: }
編譯和執行程式碼,將得到:
> gcc test_drive.c -o test_drive && ./test_drive
These are the scores in order:
Score = 554
Score = 543
Score = 323
Score = 112
Score = 32
Score = 11
Score = 3
These are the names in order:
Brett
Karen
Mark
Molly
>
這個結果和本書中第 333 頁是一致的。但是,如果我們把上述程式碼第 59 行改為:
int scores[] = { 543, 323, 32, 554, 11, 3, -2147483648 };
再次編譯和執行程式碼,將得到:
> gcc test_drive.c -o test_drive && ./test_drive
These are the scores in order:
Score = -2147483648
Score = 554
Score = 543
Score = 323
Score = 32
Score = 11
Score = 3
These are the names in order:
Brett
Karen
Mark
Molly
>
這個結果當然不對。這是因為上述程式碼中第 18 行的b - a
運算溢位了。要得到正確的比較器函式,只需將上述程式碼中第 13~19 行的compare_scores_desc
函式修改如下:
// 降序排列整型得分。
int compare_scores_desc(const void *score_a, const void *score_b)
{
int a = *(int *)score_a;
int b = *(int *)score_b;
if (a > b) return -1; // 注意:是降序
if (a < b) return 1;
return 0;
}
再次編譯並執行程式碼,將得到:
> gcc test_drive.c -o test_drive && ./test_drive
These are the scores in order:
Score = 554
Score = 543
Score = 323
Score = 32
Score = 11
Score = 3
Score = -2147483648
These are the names in order:
Brett
Karen
Mark
Molly
>
我們得到了正確結果。當然,就這本書討論的問題來說,不可能發生溢位的情況。
相關文章
- 《Head First Java》20201017讀書筆記Java筆記
- 《Head First Java》20200927讀書筆記Java筆記
- 《Head First Java》20201009讀書筆記Java筆記
- Head First設計模式讀書筆記設計模式筆記
- Head First HTML 與 CSS(第二版)學習筆記HTMLCSS筆記
- Head first PHP & MySQL 中文版pdfPHPMySql
- Head First Java學習筆記(7):繼承與多型Java筆記繼承多型
- Head First 設計模式筆記 3.裝飾者模式設計模式筆記
- Head First C 電子書pdf下載
- Head First Python (一)Python
- Head First HTML and CSS (八)HTMLCSS
- 《Head First Android》讀後感,電子書PDF下載Android
- elasticsearch-head 筆記Elasticsearch筆記
- c++ primer 第二章閱讀筆記C++筆記
- 《深度探索c++記憶體模型》讀書筆記 (二)C++記憶體模型筆記
- [head first 設計模式]第二章 觀察者模式設計模式
- 《Head First 設計模式》:策略模式設計模式
- 「HEAD-FIRST」之觀察者模式模式
- 《Head First 設計模式》:模板方法模式設計模式
- 《Head First 設計模式》:單件模式設計模式
- 《Head First 設計模式》:外觀模式設計模式
- 《Head First 設計模式》:狀態模式設計模式
- 《Head First 設計模式》:剩下的模式設計模式
- 《Head First 設計模式》:組合模式設計模式
- Head First 設計模式(1)-----策略模式設計模式
- 【記】《.net之美》之讀書筆記(二) C#中的泛型筆記C#泛型
- 《Head First 設計模式》:工廠方法模式設計模式
- 《Head First 設計模式》:觀察者模式設計模式
- 《Effective C++》讀書筆記C++筆記
- C++讀書筆記:字串C++筆記字串
- Head First 設計模式(3)----裝飾者模式設計模式
- Head First 設計模式 —— 13. 代理 (Proxy) 模式設計模式
- 《C缺陷與陷阱》讀書筆記筆記
- 《人月神話》閱讀筆記二筆記
- Head First 設計模式(2)---觀察者(Observer)模式設計模式Server
- head first java第一章的學習Java
- 《Head First 設計模式》:與設計模式相處設計模式
- Head First 設計模式 —— 14. 複合 (Compound) 模式設計模式
- 《分散式快取》讀書筆記二分散式快取筆記