contributed by < unknowntpo
>
“If I had eight hours to chop down a tree, I’d spend six hours sharpening my axe.” – Abraham Lincoln
「如果我有 8 小時可以砍 1 棵樹,我會花 6 小時把斧頭磨利。」 – 亞伯拉罕.林肯 (類似漢語「工欲善其事,必先利其器」)
實驗初稿 lab0-c SandBox
lab0-c 架構是什麼?
What's the relationship of queue and linked list?
how to install git hook using shell script?
how to explain the structure of Makefile?
TODO: 改善 rio_package 使 rio_readlineb() 能在一次讀完一整個 單字時,就判斷是否該停止讀取,而不是每讀一個 byte
就要判斷是否為 \n
or EOF
queue.c
實作:q_size()
Return 時順便做 null queue 的檢查
q_new()
NULL_PTR_GUARD()
macro 來簡化對 NULL pointer 的檢查code: 解釋:
Step1:
q
為 NULL queuestrlen()
求得字串長度,儲存在型態為 size_t
的變數 len
內Step2:
newh
配置記憶體空間,
NULL_PTR_GUARD
做 null pointer 檢查,
newh->value
配置記憶體空間,以便之後把輸入的字串 s
複製到新的 node 上
newh
結構體的記憶體空間才能 return false, 所以沒辦法用 NULL_PTR_GUARD
, 只能手動寫一個。Step3:
s
到 newh->value
的字串複製,並在結尾手動加入 \0
strncpy()
是否會自動補 0 的討論
TODO: 參考 你所不知道的C語言:技巧篇 中的文章 停止使用 strncpy 函數 ,使用 strdup()
來改寫 code
Step4:
q->head
與 q->tail
所指向的位置
q->tail
要分成兩種情況討論
q_insert_head()
執行前節點數量為 0,
q->tail
指向新的 node newh
,q_insert_head()
執行前節點數量為 1,
q->tail
的位置Step5:
newt
代表新插入的 nodeq_insert_head()
相同,不同的地方是,必須考慮到兩種情況
q->head
與 q->tail
都指向 NULL
q->head
與 q->tail
時必須 讓他們同時指向newt
q->head
與 q->tail
都不為 NULL
, 分別指向 queue 的 開頭與結尾
q->tail
的位置q->tail->next = newt
來把新的 node 接在尾端q->tail
的位置讓他指向新的尾端,也就是 newt
q->remove_head()
實作先確認是否為下列3種狀況
!sp
!q
!q->head
再來決定 要 copy 的字元數量
如果 bufsize == strlen(q->head->value)
呢?
/* FIXME: verify if bufsize == strlen(q->head->value) */
make test
fail, 待解決commit:
Fix the boundary bug of sp in q_remove_head()
Consider the condition when
bufsize == strlen(q->head->value)
implies that
ncopy == strlen(q->head->value) == bufsize
, there's no place for
placing '\0'
at last of the sp
.
It may cause error.
如果 bufsize - 1
大於等於要刪除的字串長度
ncopy
就是 要刪除的字串長度
\0
的字串長度就好如果 bufsize
小於要刪除的字串長度
ncopy
就是 bufsize - 1
\0
q_reverse()
實作一開始先把 q->head
, q->tail
交換位置,再來使用 for-loop 把箭頭一個個反向,
最後把 q->tail
設為 0
後結束 function
假設一開始為
一開始先 swap q->head
與 q->tail
,避免移動指標到下一個 node 時不小心 dereference NULL pointer (在 nxt = nxt->next
這一行, 如果 nxt->next == NULL
時就會出錯)
再來就是使用 for-loop
把 linked list 的箭頭反向,
一開始初始化迴圈時,
q->head
與 q->tail
接起來,
nxt = nxt->next
這一行, 如果 nxt->next == NULL
時就會出錯)pre cur nxt
指標的位置code: reverse arrow
cur->next = pre;
code:
pre = cur
code: inside if statement
cur = nxt; nxt = nxt->next;
code: reverse arrow
cur->next = pre;
code:
pre = cur
code: inside if statement
cur
, nxt
cur = nxt; nxt = nxt->next;
code: reverse arrow
cur->next = pre;
code:
pre = cur
code: inside if statement
cur
, nxt
cur = nxt; nxt = nxt->next;
code: reverse arrow
cur->next = pre;
code:
pre = cur
code: inside if statement
tail->next
to NULL
and return
q->tail->next = NULL; return;
參考 makefile build 出檔案的方式來學習
q_size
tutorialqtest
命令直譯器的實作課內學習資源:
須具備基礎知識:
可行的宣告方式:
or
It's important to note that:
struct_tag
is optionalstruct_variable
is declared, system will allocate memory to it.To access the member member1
in a structure struct_tag
, we can use:
For example,
Consider following code mysqrt.c
which calculate the distance between origin and point pt
:
compile it.
Output:
初步猜測 ld
可能與 linker 有關
透過 google 搜尋關鍵字:
undefined reference to sqrt
有人問一樣的問題
Answer:
The math library must be linked in when building the executable. How to do this varies by environment, but in Linux/Unix, just add
-lm
to the command. The math library is namedlibm.so
, and the-l
command option assumes alib
prefix and.a
or.so
suffix.wallyk
我的理解 linker 在連結的時候沒有找到
libm.so
這個檔案裡的sqrt()
function
修改 gcc 指令:
得到正確結果
libm.so
是什麼呢?
跟 <math.h>
有什麼關係?
如何解釋 undefined reference
?
請參閱 你所不知道的 C 語言:動態連結器篇 和 你所不知道的 C 語言:連結器和執行檔資訊,有對應的解說。
收到,待補上心得 unknowntpo7:55 March 7 2020
參考 ISO / IEC 98996.7.7 Type definitions:
In a declaration whose storage-class specifier is
typedef
, each declarator defines an identifier to be a typedef name that denotes the type specified for the identifier in the way described in 6.7.5. Any array size expressions associated with variable length array declarators are evaluated each time the declaration of the typedef name is reached in the order of execution. A typedef declaration does not introduce a new type, only a synonym for the type so specified. That is, in the following declarations:
type_ident
is defined as a typedef name with the type specified by the declaration specifiers inT
(known as T), and the identifier in D has the type derived-declaratortype-list T where the derived-declarator-type-list is specified by the declarators of D. A typedef name shares the same name space as other identifiers declared in ordinary declarators.
(Page 135).
Keywords:
我的理解: consider the code below:
int
myint
x
typedef
does not introduce a new type, only a synonym of the type so specified.typedef
name shares the same name space as other identifiers declared in ordinary declarators.參照 Example 2:
After the declarations:
t1
and the type pointed to by tp1
are compatible.t1
is also compatible with type struct s1
,struct s2
,t2
,tp2
,int
.關於 typedef 的 namespace, 如果 typedef 的宣告放在所有 function 外面,那他的 scope 就是 global ,那所有的 function 都能使用這個 typedef. 但如果 typedef 的宣告放在某個 function 裡面,他的 scope 就是 local ,那在其他地方就不能使用它。
e.g. Consider the code below,
因為在
的 scope 沒有包含foo()
,
所以出現以下 error:
namespace 是什麼? scope 是什麼?
這些詞彙是 Programming Language Theory (PLT) 的術語,可簡易理解為:
變數 i
的數值取決於在哪裡取得 (evaluate),顯然在 foo
, main
, for
都會不同,而且參照的物件也不同,有 local 也有 global。
The full code is in gist.
參考資料 你所不知道的 C 語言:前置處理器應用篇
在 Linux Kernel 開發日誌 2020.3.9 中,
K&R p.130 的 canonrect()
function
macro 作動不對 導致數值比較錯誤
Debug 後發現
relational operator >
寫反了。
gdb debug 後發現
在 cononrect()
內, temp 一開始的數值是
推測是因為沒有被初始化的關係,所以有非預期的數值
出現
所以
在 gdb 內 assign variable 給 temp
模擬 line 95 如果我們已經初始化 temp 的狀況。
之後再修改程式碼:
再使用 gdb 來測試
發現到我們成功初始化 temp
了!
但其實我們不需要初始化,畢竟不管 temp
內的 member 是什麼數字,之後都會馬上被 assign 成別的數。
consider a structure
murmur: 這個宣告是否合法? unknowntpo
then,
++p -> len
:
len
,len
(++p)->len
:
p
and then access structure member len.*p->str++
:
str
: (p->str)
str
: (p->str)++
str
.++
: increment the value that str
point to.查詢 imcrement operator increment 的時間
*p->str++
: 解釋可能錯誤,該如何更好地用英文解釋這些運算的行為呢? 我對用詞的掌握好像不太精準,可能會造成別人誤解
(*p->str)++
:
str
:(p->str)
str
: *(p->str)
str
pointed to. *(p->str)++
*p++->str
:
p++
: 先 evaluate p++, 在下一個 sequence point 前 increment p;p++->str
: get access to str
str
遇到 segmentation fault.
segmentation fault: 查詢 Core Dump (Segmentation fault) in C/C++
推測可能是
*p
的 scope, 所以存取了不能沒有存取權限的記憶體。閱讀 K&R 6.4 Pointers to Structures 後再修改程式。
小心得: 基礎觀念還是要仔細學習,不能輕率, 不然到最後還是要繞一大圈,反而更花時間 unknowntpoThu, Mar 12, 2020 11:08 AM