雙倍指標,打包再打包的概念,包起 dereference 的內容。不管哪種都會讓串列變成樹。一個追趕的演算法,只是追和被追有沒有用 next 連在一起而已。下方有示意圖。[^dot_rf1]; [^dot_rf2]。或說,讓 *p 指標用來存取所有的 next,另外,prev 也可以用類似的操作。雙指標不是物件的指標,是走遍指標的指標變數。
l->1 2 3 4 5 6 7 8
be->
*p->
*p->it
l->1 2 3 4 5 6 7 8
.->it
it->4
l->1 2 3 it 4 5 6 7 8
digraph linked_list {
rankdir=LR; // 水平顯示
node [shape=record, style=rounded];
head [shape=circle, label="head", style=filled, fillcolor=lightblue];
A [label="A"];
B [label="B"];
C [label="C"];
null [shape=plaintext, label="NULL"];
head -> A;
A -> B;
B -> C;
C -> null;
}
AAAA = &l->head
BBBB = before
CCCC = &(*p)->next
DDDD = item->next
都和教材 append 的程式碼相對應,只有 DDDD 是新增的。
善用 gcc -E quiz1a.c > quiz1a.i
, gcc -g -o quiz1a quiz1a.c
處理錯誤。因為有兩個巨集,影響預編譯的結果。而且是合成影響。
main -> test_suite -> [my_run_test(test_list);] = do-while(0) -> [test()] = test_list()
說真的,一步到位我還是有點暈,但預處理器成功了。test_list 函式有三步驟。
像堆疊一樣,倒數插入 items[i] ,從 i=0 到 999,但都插入在開頭,所以從開頭會是 999 數回 0。在 list_insert_before 函式執行之前, list_reset 只是建立節點,沒有串聯成串列,所有節點都是孤單的節點。注意 do-while(0)
是假迴圈,因為不會重複執行,只剩下名字。理頭都是預留給可能的錯誤,去判斷並回傳錯誤。如果 test_list 結束,測試成功回傳 NULL。
其實仔細看,只有一個測試,最後一段是類似測試但實作。一次說明,這次插入尾端,從 0 到 9999 。檢察長度,和各節點數值。就結束了。輸出 測試成功, run 次數 1,一次成功,一杆進洞。那個巨集是模仿 assert 和 printf 實作的。最後的 return !!result;
注意是字串對布林變數的 1, 0 真假反轉。用 felo search 有詳細說明,容易邏輯死亡,小心服用。摘錄一段:
In C, the expression return !!NULL; involves the use of the logical NOT operator (!) applied twice to the NULL macro.
嘗試運用 macro 測試在 static list_t *list_setup 函式中,但 macro 會被預處理的 return 影響,就算另外新增變數儲存也沒辦法。這是設計的問題。我發現我函式呼叫,即使不傳回串列頭的指標,初始構建和測試仍然可行。於是修改回傳型別配合 macro ,也算是發現 macro 的一大缺點。
context:
#0 list_size (mylist=0x55555555bee0 <l>) at quiz1a.c:90
#1 0x000055555555532b in test_list () at quiz1a.c:55
#2 0x0000555555555422 in test_suite () at quiz1a.c:78
#3 0x00005555555554f5 in main () at quiz1a.c:107
當有錯務時,回報機制在位址的錯誤,沒有辦法存取到。應該說是分頁錯誤的問題, gdb 可以讀取錯誤訊息,但是被 printf 的錯誤訊息中斷了。也就是兩個都要回傳,但不能同時回傳。
517 ./stdio-common/vfprintf-internal.c: No such file or directory.
(gdb) frame 3
#3 0x000055555555569e in main () at merge.c:137
137 printf("ERROR: %s\n", result);
(gdb) p result
$7 = 0x5 <error: Cannot access memory at address 0x5>
(gdb) type result
Undefined command: "type". Try "help".
(gdb) ptype result
type = char *
(gdb) p *result
Cannot access memory at address 0x5
# second test
(gdb) where
#0 list_size (mylist=0x55555555bfb8 <lsa>) at merge.c:90
#1 0x000055555555526a in list_setup (l=0x55555555bfb8 <lsa>,
l_items=0x55555555bf00 <a_items>, length=5, array=0x7fffffffd7e0)
at merge.c:24
#2 0x0000555555555678 in main () at merge.c:135
(gdb) l
85 list_item_t *curr;
86 curr = mylist->head;
87 int count = 0;
88 while (curr) {
89 count++;
90 curr = curr->next;
91 }
92 return count;
93 }
94
(gdb) p count
$1 = 1
(gdb) p curr
$2 = (list_item_t *) 0x55555555bf00 <a_items>
(gdb) p curr->next
$3 = (struct list_item *) 0x55555555bf10 <a_items+16>
(gdb) p curr->next->next
$4 = (struct list_item *) 0x55555555bf20 <a_items+32>
(gdb) p *curr->next->next
$5 = {value = 5, next = 0x55555555bf30 <a_items+48>}
修改程式碼,前置處理器部分:
#define setup_run_test(test, l, l_items, length, array) \
do { \
char *message = test(l, l_items, length, array); \
tests_run++; \
if (message) \
return message; \
} while (0)
並對 list_setup 加上 return NULL
,完成回傳值,如果通過測試的話。原來直接輸入參數就可以但一定要注意資料的層數,結構都必須是全域的。
_GI__IO_puts (str=0x5555555560ac "ALL TESTS of List PASSED") at ./libio/ioputs.c:33
33 ./libio/ioputs.c: No such file or directory.
(gdb)
35 in ./libio/ioputs.c
(gdb)
__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:50
50 ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
如果 printf 正常的話,用 cont
, step
, until N
, 跳過迴圈和一些步驟。完成偵錯程序。
or
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up
Syntax | Example | Reference | |
---|---|---|---|
# Header | Header | 基本排版 | |
- Unordered List |
|
||
1. Ordered List |
|
||
- [ ] Todo List |
|
||
> Blockquote | Blockquote |
||
**Bold font** | Bold font | ||
*Italics font* | Italics font | ||
~~Strikethrough~~ | |||
19^th^ | 19th | ||
H~2~O | H2O | ||
++Inserted text++ | Inserted text | ||
==Marked text== | Marked text | ||
[link text](https:// "title") | Link | ||
 | Image | ||
`Code` | Code |
在筆記中貼入程式碼 | |
```javascript var i = 0; ``` |
|
||
:smile: | ![]() |
Emoji list | |
{%youtube youtube_id %} | Externals | ||
$L^aT_eX$ | LaTeX | ||
:::info This is a alert area. ::: |
This is a alert area. |
On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?
Please give us some advice and help us improve HackMD.
Syncing