Lab 5-1: Pointer exercises

 
實習目標 練習指標宣告
 
步驟一 請寫一個 readMagnitude 函式, 利用 scanf 函式由鍵盤讀取一個整數, 求取其絕對值, 並且在函式中直接更改下面主函式中的變數 x
    #include <stdio.h>
    
    void main()
    {
        int x;
        readMagnitude(&x); 
        printf("magnitude of x is %d\n", x);
    }
因為要確定你能夠靈活地使用指標變數, 請不要用 iostream 完成上面的函式

範例程式 testPtr1.exe

步驟二 請寫一個 reverseStr 函式, 將傳進函式的字元陣列反轉過來, 直接更改傳進來的陣列, 以下面程式為例, x 字元陣列內之資料將變成 "!tset esrever rof si sihT", 並且將陣列指標傳回去, 在主程式中可以直接利用 printf 列印反轉過的陣列:
    #include <stdio.h>
    
    void main()
    {
        char x[] = "This is for reverse test!";
        printf("x=\"%s\"\n", reverseStr(x));
    }

範例程式 testPtr2.exe

步驟三 在下面的程式中, 希望利用上一步驟所完成的 reverseStr 函式將 12 個字串都反轉過來, 並且請依照規定的 countChar 函式的參數型態完成一個能夠計算傳進來陣列內有多少字元的函式, 請完成下列程式中 ... 的部份
    #include <stdio.h>

    int countChar(...)
    {
       ...
    }

    void main()
    {
        int i;
        char y[12][10] = {"January", "Februrary",
                          "March", "April",
                          "May", "June",
                          "July", "August",
                          "September", "October",
                          "November", "December"};
        for (i=0; i<12; i++)
            printf("%s %d\n", reverseStr(...), countChar(&y[i]));
    }
為了清楚地了解指標的定義, 請不要用強制指標型態轉換, 可以用 string.h 裡的函式, 例如: strcpy, strlen, strrev 等等

範例程式 testPtr3.exe

步驟四 下面這個程式中我們為了 debug 的需求, 希望寫一個函式將所傳進來的記憶體指標 處指定的位元組 (byte) 個數都以 16 進位方式列印在螢幕上, 請完成下面的程式
    #include <stdio.h>

    typedef struct
    {
        char   cField;
        double dField;
        short  sField[3];
        char   *ptrField;
    } DataRecord;
    
    void dumpMemory(void *ptr, int size)
    {
        ...
    }

    void main()
    {
        DataRecord data={'0', 1.2345, -1, 1, 32767, "string"};
        int iDataArray[]={1,2,3,4,5,6};
        char *bufPtr = "This is a buffer pointer.";
        char buffer[30] = "This is a character buffer.";
        char month[12][10] = {"January", "Februrary",
                              "March", "April",
                              "May", "June",
                              "July", "August",
                              "September", "October",
                              "November", "December"};
        dumpMemory(&data, sizeof(data));
        dumpMemory(iDataArray, sizeof(int)*6); 
        dumpMemory(&bufPtr, ...); // 請印出 4 個 bytes
        dumpMemory(buffer, ...); // 請印出 30 個 bytes
        dumpMemory(month, ...); // 請印出 120 bytes
        dumpMemory(dumpMemory, sizeof(void (*)(void *, int)));
    }
上面 main 函式中 dumpMemory 的第二個參數請用 sizeof 完成

範例程式 testPtr4.exe

執行結果範例 (這個結果和你自己執行的應該會有相當的差異, 例如下面的紅字和青字的部份, 應該都和你自己執行的結果不同, 為什麼??? 因為紅色的部份是 VC6 沒有用到的地方, 這些內容基本上是記憶體裡面原有的東西, 每一台機器在執行 testPrt4.exe 之前做的工作都一定不同, 記憶體裡面的狀態也一定不同; 青色的部份則是指標的內容, 當然也是每一個機器都不一樣的)

30 01 00 00 50 72 65 73 8d 97 6e 12 83 c0 f3 3f
ff ff 01 00 ff 7f 00 00 4c 90 40 00 20 18 38 00

01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
05 00 00 00 06 00 00 00

54 90 40 00

54 68 69 73 20 69 73 20 61 20 63 68 61 72 61 63
74 65 72 20 62 75 66 66 65 72 2e 00 00 00

4a 61 6e 75 61 72 79 00 00 00 46 65 62 72 75 72
61 72 79 00 4d 61 72 63 68 00 00 00 00 00 41 70
72 69 6c 00 00 00 00 00 4d 61 79 00 00 00 00 00
00 00 4a 75 6e 65 00 00 00 00 00 00 4a 75 6c 79
00 00 00 00 00 00 41 75 67 75 73 74 00 00 00 00
53 65 70 74 65 6d 62 65 72 00 4f 63 74 6f 62 65
72 00 00 00 4e 6f 76 65 6d 62 65 72 00 00 44 65
63 65 6d 62 65 72 00 00

55 8b ec 51
提示: 在函式裡你必須要將 (void*) 型態指標強制轉換為 (unsigned char *) 型態的指標來取出記憶體裡面的資料

如果你用 (char *) 的話會有 sign extension 的問題, 因為將一個有正負號, 8 個位元的資料傳入 printf() 函式時, C/C++ 會自動將 8 個位元的資料轉換為 32 位元的資料, 此時如果你的資料是 0x10 就會轉換為 0x00000010, 如果是 0x90 就會轉換為 0xFFFFFF90, 這樣子以 2's complement 去解釋時兩個數字是相同的, 如果你是 unsigned char, 則在轉換時 0x10 會換成 0x00000010, 0x90 會換成 0x00000090

請注意 VC 在編譯時為了促進結構裡欄位存取的效率, 預設會將每一個欄位都放在 8 位元的記憶體邊界上, 所以上面的 DataRecord 雖然只需要 19 個位元組就可以存放所有的資料, 但是實際上在記憶體裡佔了 32 個位元組, 其中有 13 個位元組裡的資料是沒有特別意義的, 所以你的程式和範例程式的結果比較時, 會發現有 13 個位元組是不可能一樣的, 另外記憶體的位址也是不會一樣的。

必要的時候你可以在 Project/Setting, C/C++, Category:Code Generation, Struct Member Alignment 的地方更改 (在命令列用 /Zp1 /Zp2 /Zp4 /Zp8 來更改)

步驟五 請完成下面程式中的 arrayCopy 的定義與內容
    #include <stdio.h>
    #include <string.h>
    
    void arrayCopy(..., ...)
    {
        ...
    }
    
    void main()
    {
        int i;
        char *month[12] = {"January", "Februrary",
                           "March", "April",
                           "May", "June",
                           "July", "August",
                           "September", "October",
                           "November", "December"};
        char newMonth[12][10];
    
        arrayCopy(newMonth, month);
        for (i=0; i<12; i++)
            printf("%s\n", newMonth[i]);
    }
請不要用強制指標轉換, 可以用 strcpy 函式

範例程式 testPtr5.exe

步驟六 請助教檢查後, 將所完成的 project (去掉 debug/ 資料匣下的所有內容) 壓縮起來, 選擇 Lab5-1 上傳, 後面的實習課程可能需要使用這裡所完成的程式

C++ 物件導向程式設計課程 首頁

製作日期: 03/16/2004 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@cs.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程系 Lagoon

tml>