2018q3 Homework2 (lab0)

contributed by <plusline>

  • 請補上實驗環境
  • 中英文字間請以空白隔開

課程助教

  • fixed
  • 助教這次作業我已經完成,但還是收到進度落後的通知
  • 請問是哪部分寫得不完整嗎?

plusline

作業要求還有提到需「解釋自動評分系統運作的原理」、「提及 qtest 的行為和裡頭的技巧」這兩部份,因為沒看到你的紀錄,而且多天未更新,所以才寄信通知。
應該是你漏掉這部份了XD
還有時間,GOGO!
課程助教

我漏掉那部分的要求,所以開始在看下一周的作業,難怪都沒有共筆可以參考,我會繼續補齊的

plusline

測試環境

plusline@plusline-System-Product-Name:~$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
plusline@plusline-System-Product-Name:~$ cat /proc/version
Linux version 4.15.0-34-generic (buildd@lgw01-amd64-047) (gcc version 7.3.0 (Ubuntu 7.3.0-16ubuntu3)) #37-Ubuntu SMP Mon Aug 27 15:21:48 UTC 2018

git

  • 先到你要 fork 的專案按下 fork 按鈕,它會產生一個副本到你的 github 帳號。
  • 回到自己 github 首頁,可以找到剛剛 fork 過來的 repositories 。
  • git clone https://github.com/plusline/lab0-c.git 把 repositories 拉到你的linux,這段網址是你的 repositories 的位置。
  • git checkout -b slow-blink slow-blink 是你要創建的分枝。
  • 在你的電腦做完所有修改後
  • git commit -a -m 'What you have done' 寫一點註解
  • git push origin slow-blink 提交
    git

自動評分系統

注意:需要安裝 python 而不是 python3 才能執行 driver.py。我一直以為是bug,直到打開 driver.py 發現print的格式和我印象中不一樣,才知道原來 python 有兩個分枝。

clang-format -i queue.c 用來排版
make用來編譯,修改完 queue.h 和 queue.c 後執行。
make test 用來呼叫 driver.py 會幫你的程式評分。

---	TOTAL		0/100

什麼都沒做,所以拿了0分。

Implementation

free

void q_free(queue_t *q)
{
    /* How about freeing the list elements and the strings? */
    /* Free queue structure */
    if (q == NULL)
        return;
    list_ele_t *temp, *current;
    current = q->head;
    while (current != NULL) {
        temp = current;
        current = current->next;
        // free(temp->value);
        free(temp);
    }
    if (q != NULL)
        free(q);
}

用 for 迴圈遍歷,並將所有的節點和字串刪掉,最後再刪掉 queue 。
一直搞不懂為什麼不需要刪掉字串的空間?


insert head

bool q_insert_head(queue_t *q, char *s)
{
    if (q == NULL)
        return false;
    list_ele_t *newh;
    /* What should you do if the q is NULL? */
    newh = malloc(sizeof(list_ele_t));
    /* Don't forget to allocate space for the string and copy it */
    /* What if either call to malloc returns NULL? */
    if (newh == NULL)
        return false;
    newh->value = strdup(s);
    newh->next = q->head;
    q->head = newh;
    if (q->size == 0)
        q->tail = newh;
    q->size += 1;
    return true;
}

我總覺得直接給 *value 一個給定的大小不太好,但不知道怎做,先將就一下。後來已經修正成用 strdup ,就不用擔心空間大小的問題。


commit 時出現錯誤,但編譯沒報錯:已修正,似乎是 q_insert_head 隨意離開函式引起的。

[queue.c:71]: (error) Memory leak: newh

Fail to pass static analysis.

plusline@plusline-System-Product-Name:~/lab0-c$ make
gcc -O0 -g -Wall -Werror -o qtest qtest.c report.c console.c harness.c queue.o
queue.o: file not recognized: File format not recognized
collect2: error: ld returned 1 exit status
Makefile:15: recipe for target 'qtest' failed
make: *** [qtest] Error 1

後來發現是不小心輸入 clang-format -i queue.o ,在輸出 queue.o 的檔案( queue.c queue.h )還沒更新前,使用 makefile 並不會執行 gcc -O0 -g -Wall -Werror -c queue.c  ,只需要刪掉 queue.o 就可以了。


remove head

bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
    /* You need to fix up this code. */
    if (q == NULL || q->size == 0)
        return false;
    list_ele_t *dummy;
    dummy = q->head;
    if (sp == NULL)
        return false;
    strncpy(sp, q->head->value, bufsize - 1);
    sp[bufsize - 1] = '\0';
    q->head = q->head->next;
    free(dummy);
    q->size -= 1;
    return true;
}

第六個測資是檢測 truncated strings ,測資會故意截斷字串,導致沒有 null terminator ,需要自己將後面一個字元改成'\0'


大功告成

其他的部份照著註解做,都沒有遇到太大的問題。

---	TOTAL		100/100

自動評分系統運作的原理

依照作業手冊,我們知道要評分的時候要在 lab0-c 下執行 make test,我從這裡開始 trace 。打開 Makefile ,找到 test: ,可以知道它呼叫 scripts/driver.py 。

接下來就是 trace driver.py ,從 if __name__ == "__main__": 進入,呼叫 run ,在 run 裡會設定參數,並創建 class Tracer ,並執行 class 中 run 的方法,在這裡它會呼叫放在 traces 資料夾底下所有要測試的題目,其中 subprocess.call 就是用來呼叫這些題目的方式,舉個例子:在15個測資,它需要傳入的參數就是 ['./qtest', '-v', '1', '-f', './traces/trace-15-perf.cmd']這等於直接在命令列打上./qtest -v 1 -f ./traces/trace-15-perf.com這個指令執行完,如果這部份的測資答對就會回傳0,答錯就會回傳1,一此判斷加分與否,將所有題目測試完就完成自動評分了。其中 qtest.c 是評分系統判斷作答正確與否的核心,


qtest 的行為和裡頭的技巧

當不確定輸入的參數數量的時候,可以使用下列這種語法。va_start

       void
       foo(char *fmt, ...)
       {
           va_list ap;
           int d;
           char c, *s;

           va_start(ap, fmt);
           while (*fmt)
               switch (*fmt++) {
               case 's':              /* string */
                   s = va_arg(ap, char *);
                   printf("string %s\n", s);
                   break;
               case 'd':              /* int */
                   d = va_arg(ap, int);
                   printf("int %d\n", d);
                   break;
               case 'c':              /* char */
                   /* need a cast here since va_arg only
                      takes fully promoted types */
                   c = (char) va_arg(ap, int);
                   printf("char %c\n", c);
                   break;
               }
           va_end(ap);
       }

要操作這個語法需要宣告一個 va_list 的物件,然後用 va_start 初始化,之間用 va_arg 取值,最後在用 va_list 解構。

練習

void too(char *fmt, ...){
    va_list ap;
    va_start(ap,fmt);
    char *s;
    int count=*fmt-48;
    printf("%d\n",count);
    s=va_arg(ap,char *);
    while(count--){
        printf("%s\n",s);
        s=va_arg(ap,char *);
    }
}

int main(){

    too("4","lion","tigre","mouton","oiseau");

    return 0;

}

4
lion
tigre
mouton
oiseau

要小心用 va_arg 不能取超過參數數量,不然會發生錯誤。

Select a repo