# 2018q3 Homework4 (assessment) contributed by <`AlecJY`> ## [第 4 週測驗題(中)](https://hackmd.io/s/Syl6me49Q) ## [第 4 週測驗題(下)](https://hackmd.io/s/By7Lwz4qm) ### `ptr.c` ``` C= int main() { int *ptr = 0; return *ptr; } ``` 這段程式碼在執行時期會產生 segmentation fault 。 這段程式碼在第二行定義了一個 int 指標 `ptr` 並且賦值為 0 ,在第三行回傳 `*ptr` ,也就是將位址為 0 的指標 dereference 後回傳,由於位址 0 是一個無效的位址,所以會產生 segmentation fault。 ### `ptr1.c` ``` C int main() { return *((int *) 0); } ``` 這段程式碼在執行時期會產生 segmentation fault 。 這邊對記憶體位址為 0 的指標做 dereference 。 由於位址 0 是一個無效的位址,所以會產生 segmentation fault。 ### `ptr2.c` ``` C int main() { return &*((int *) 0); } ``` 這段程式碼跟上一段程式碼比起來只差在多了一個 `&` ,翻閱 C99 規格第 79 頁的註腳中有一段描述是 > &*E is equivalent to E (even if E is a null pointer) 所以這段程式碼只是單純的回傳 0 而已,可以正常的執行 另外如果使用 GCC 編譯的時候會產生如下的錯誤訊息 ``` warning: return makes integer from pointer without a cast ``` 因為 `main` 要求回傳 `int` ,實際上回傳的是 `int *` ,所以如果在前面再加一個 `(int)` 強制轉型為 `int` 就可以消除這個警告 ## `ptr3.c` ``` C #include <stddef.h> int main() { return &*NULL; } ``` 這段程式碼跟前一段的差別在於 `((int *) 0)` 改成了 NULL ,根據 C99 規格章節 7.17 第 254 頁 > **NULL** > which expands to an implementation-defined null pointer constant 再根據章節 6.3.2.3 第 47 頁對於 null pointer 的描述 > An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 所以這段程式碼一樣是回傳 0 ,執行上不會有問題。 ### `ptr4.c` ``` C #include <stddef.h> int main() { return &*(*main - (ptrdiff_t) **main); } ``` 參考 [你所不知道的C語言:指標篇](https://hackmd.io/s/HyBPr9WGl) 裡面的解釋 > 程式碼 (********puts) 可看作 (*(*(*(*(*(*(*(*puts)))))))),最裡面的括號 (*puts) 由 [ 6.5.3.2-4 ] 可知它是一個 function designator。再根據 [ 6.3.2.1 ],它最後會被轉為 pointer to function returning type。往外延伸一個括號 (*(*puts)) 由於最裡面的括號是一個 function designator,再多一個 * operator 它還是一個 function designator,最後也會被轉為 pointer to function returning type,依此類推最後 (********puts) 仍會是一個 function designator。 `**main` 是一個 function designator ,之後將他強制轉型成 `ptrdiff_t` ,這是一個代表指標和指標相減後得到的值的型別,將 `*main` 這個 function designator 和 `(ptrdiff_t) **main` 相減後會得到 0 ,所以問題就化簡為跟 `ptr2.c` 差不多的問題, `&*` 可以消去,因此實際上回傳的值是 0 ,執行上不會有問題。