# 2018q3 Homework1 contributed by < `jeremycheng0715` > :::danger 你的提問呢?回顧你過去開發的程式,難道沒想到概念上有衝突或者激發出更多想法嗎? :notes: jserv ::: ## 為什麼要深入學習 C 語言? * C語言一開始是用來開發 UNIX 系統 * C語言是高階語言,卻有一些低階語言的特徵 * C語言可以透過指標對記憶體進行控制 ### C的一些基本名詞 * `&` : Address-of operator * `*` : Indirection operator * `** ` : Pointer to pointer * cdecl : C語言宣告翻譯 Linux系統下全部都是 cdecl,這種特性體現了 Linux追求作為一個 "很純 C" 極致的作業系統,假如用 Linux 的話,基本上不太用煩惱呼叫慣例的問題。 cdecl 呼叫慣例也存在很久了,正如其名"C 呼叫慣例",它的參數傳遞規則也是很簡單,與 stdcall 相同是由右至左。 * GDB : GNU Debugger,是GNU軟體系統中的標準偵錯器,此外GDB也是個具有移攜性的偵錯器 * rr : 負責將 crash 當下的狀態記錄起來,丟到GDB裡面 ### 提問: 老師在影片中以及課堂中不斷提及C語言規格書的重要性,像C Operator Precedence這部分在規格書講得非常清楚,於是便去找了規格書來看,原本自認為有C的基礎知識了,但我實際去念規格書發現裡面的內容難以從文字中理解,裏頭有些也缺少實例可以測試,讀起來有點吃力,想請問如果以讀規格書是否有搭配的其他必須要同時上手的書籍或資源呢? ## 你所不知道的 C 語言: 指標篇 ### 指標基本操作 ```clike= #include <stdio.h> int main(void) { int num = 87 ; int *pointer = &num ; //存放pointer printf("the value of num: %d\n", num); printf("the address of num : %p\n", &num); printf("the value of pointer : %p\n", pointer); printf("the value of *pointer : %d\n", *pointer); printf("the address of pointer : %p\n\n", &pointer); *pointer = 8787 ; printf("the value of num: %d\n", num ); printf("the address of num : %p\n", &num); printf("the value of pointer : %p\n", pointer); printf("the value of *pointer : %d\n", *pointer); printf("the address of pointer : %p\n", &pointer); return 0; } ``` Result: ``` the value of num: 87 the address of num : 0060FF0C the value of pointer : 0060FF0C the value of *pointer : 87 the address of pointer : 0060FF08 the value of num: 8787 the address of num : 0060FF0C the value of pointer : 0060FF0C the value of *pointer : 8787 the address of pointer : 0060FF08 ``` ### 關於`void *` * void 一開始在C並不存在,而是到C89才確立 * void *從本質上講是一種指標的類型,就像(char *)、(int *)類型一樣.但是他的特殊性在於它可以存放其他任何類型的指標類型:例如: ```clike char *array="the pointer of string"; void * temp; temp=array; cout<<array<<endl; cout<<temp<<endl; cout<<(char *)temp<<endl; ``` Result: ``` the pointer of string 0x0042510C the pointer of string ``` * 但是不能將void *類型的值賦給其他既定的類型: 例如: ```clike int a=20; int * pr=&a; void *p; pr=p //error pr=(int *)p; //ok,已經經過轉換型態即可 ``` void真正發揮的作用在於: (1)對函數返回的限定 (2)對函數參數的限定 ### 沒有「雙指標」只有「指標的指標」 「雙」有對稱的意思,實際上是同質且獨立的,老師上課特別強調沒有"雙重"指標,只有指標的指標 * 第二週測驗題 第5題 ```c int **arr = malloc(3 * sizeof(int *)); for (int i = 0; i < 3; i++) arr[i] = malloc(4 * sizeof(int)); ``` 如果要 free() 時,是否需要兩層的迴圈呢?倘若有人只是 free(arr); 會發生什麼事?又,該如何改善? 這便是用到指標的指標,不需要用到兩層迴圈,只需先用一層迴圈free陣列裡的內容,再free(arr)即可,若只有free(arr)裡面內容無法清除。 但更好的解法是用 malloc a two-dimensional array ```c int (*arr)[M] = malloc(sizeof(int[N][M])); arr is pointer to int[M]. use like arr[0][M-1]; and free(arr); ``` 這題便是展開成3*4的二維陣列避免使用for迴圈 ```c int (*arr)[M] = malloc( sizeof *arr * N ); //如果arr的類型發生變化也不用修改sizeof表達式 ``` * In C everything is value! 所以在C語言是call by value ### Pointers vs. Arrays * C語言中若使用多維陣列則以 row-major方式計算轉換成一維陣列 * 在表達上array與pointer可以調換 ### qsort * 不一定要用 quicksort 來實做 * 是利用 function pointer 所指到的函式來決定排序 ## 你所不知道的 C 語言: 函式呼叫篇