指針和內存(01)

day 1-1

測試環境:Linux 2.6.32-279.el6.x86_64

測試代碼:pointer.cpp

#include <stdio.h>

/**
 * test code: pointer.cpp
 * test environment: Linux 2.6.32-279.el6.x86_64
 *
 * 總結:
 * 1. 所有變量在聲明時,系統都會爲其分配一個內存地址
 * 2. 普通變量在內存中存放的是值
 * 3. 指針變量在內存中存放的是該指針指向的內存地址
 * 4. 指針變量的類型與指針變量所指向的內存空間存儲的數據類型無關,
 *    使用者可以指定所需的類型去讀取這些數據
 */
int main()
{
    // 聲明一個類型爲int的變量,且賦值爲 17777
    int i = 17777;

    // 聲明一個指針變量 ip,ip 指向的內存空間的數據類型爲int
    // 指針變量存放的是其指向的內存地址,而不是值本身,此處 ip 存放的應該是變量 i 的地址
    // &i表示取變量 i 所在的內存地址
    int *ip = &i;

    // 聲明一個類型爲int的變量,且取指針變量 ip 的值並賦值給iv
    int iv = *ip;

    // 聲明一個指針變量cp,(char*)表示需要按照char類型的讀取方式去讀取cp指向的內存空間(&i)中存儲的數據
    // 此處按照char類型去讀取 &i 則會對 &i 原來的4個字節進行截斷,只讀取1個字節的長度
    char *cp = (char*)&i;

    printf("%p: i=%d\n", &i, i);
    printf("%p: ip=%p\n", &ip, ip);
    printf("%p: iv=%d\n", &iv, iv);

    printf("%p: cp=%p, *cp=%c\n", &cp, cp, *cp);

    return 0;
}

編譯 && 執行

g++ -g pointer.cpp -O0 -o pointer
./pointer

執行結果

執行結果

調試過程

調試過程


day 1-2

測試環境:Linux 2.6.32-279.el6.x86_64

測試代碼:swap.cpp

/**
 * test code: swap.cpp
 * test environment: Linux 2.6.32-279.el6.x86_64
 * 總結:
 * 1. 在調用函數傳參時,傳的是變量的拷貝,而不是原始的值
 * 2. 在修改指針指向的內存空間存儲的數據時,應使用操作符*
 * 3. 操作引用參數實際操作的是參數所引用的對象
 */

/**
 * 傳進來的是main函數中變量a和b的值的拷貝 c1, c2
 * 交換的也是值的拷貝,並沒有改變a和b內存空間中的數據,
 * 所以此函數並不能交換a和b的值
 */
void swap1(char c1, char c2)
{
    char tmp = c1;
    c1 = c2;
    c2 = tmp;
}

/**
 * 傳進來的是main函數中變量a和b的內存地址的拷貝 cp1, cp2
 * 交換的也是內存地址的拷貝,並沒有改變a和b內存空間中的數據,
 * 所以此函數並不能交換a和b的值
 */
void swap2(char *cp1, char *cp2)
{
    printf("in swap2: *cp1=%c, *cp2=%c\n", *cp1, *cp2);
    char *tmp = cp1;
    cp1 = cp2;
    cp2 = tmp;
    printf("out swap2: *cp1=%c, *cp2=%c\n", *cp1, *cp2);
}

/**
 * 傳進來的是main函數中變量a和b的內存地址的拷貝 cp1, cp2
 * 然後通過操作符*來更新內存地址中的數據,所以此函數可以成功交換a和b的值
 */
void swap3(char *cp1, char *cp2)
{
    printf("in swap3: *cp1=%c, *cp2=%c\n", *cp1, *cp2);

    // 取c1指向的內存空間中的數據賦值給臨時變量tmp
    char tmp = *cp1;
    // 取cp2指向的內存空間中的數據賦值到cp1指向的內存空間中,覆蓋原有數據
    *cp1 = *cp2;
    // 將tmp的值賦值到cp2指向的內存空間中,覆蓋原有數據
    *cp2 = tmp;

    printf("out swap3: *cp1=%c, *cp2=%c\n", *cp1, *cp2);
}

/**
 * 傳進來的是main函數中變量a和b的引用cr1, cr2
 * cr1, cr2直接操作的是其引用的對象,所以此函數可以成功交換a和b的值
 */
void swap4(char &cr1, char &cr2)
{
    char tmp = cr1;
    cr1 = cr2;
    cr2 = tmp;
}

int main()
{
    char a = 'A';
    char b = 'B';
    printf("origin: a=%c, b=%c\n\n", a, b);

    swap1(a, b);
    printf("swap1: a=%c, b=%c\n\n", a, b);

    swap2(&a, &b);
    printf("swap2: a=%c, b=%c\n\n", a, b);

    swap3(&a, &b);
    printf("swap3: a=%c, b=%c\n", a, b);

    // 重置 a, b 爲swap3交換之前的原值
    a = 'A';
    b = 'B';
    swap4(a, b);
    printf("swap4: a=%c, b=%c\n", a, b);

    return 0;
}

編譯 && 執行

g++ -g swap.cpp -O0 -o swap
./swap

執行結果:

執行結果

掃盲:

[k&r第1章第8節] In C, all function arguments are passed “by value.” This means that the called function is given the values of its arguments in temporary variables rather than the originals.
意思就是說在c語言裏,所有的函數傳參都是通過值傳遞:調用函數的時候傳遞過去參數值都是存放在臨時變量中,而不是存放在原來的變量中。
所以在調用函數的時候,會根據參數列表創建相應的一些臨時變量,然後將參數的值拷貝一份到臨時變量中,也就是說被調用的函數不能直接修改主調函數中變量的值。

分析過程:

  • 變量a和b的在內存中的情況:
    a和b

  • swap1中各個變量在內存中的情況:
    swap1
    調用swap1(char c1, char c2)時,會產生和變量a, b對應的臨時變量c1, c2(注意觀察上圖,這兩個變量所佔的內存空間的地址明顯和a, b不一樣),然後系統會將a, b的值分別賦值給c1, c2,此時不管swap1中如何操作c1, c2,都不會影響main函數中的變量a, b的值。
    -gdb調試過程:
    swap1-gdb

  • swap2中各個變量在內存中的情況:
    swap2
    在調用swap2(char *cp1, char *cp2)時,會產生對應的兩個臨時指針變量cp1, cp2,然後系統會將&a, &b的值分別賦值給c1, c2,後續的一些操作在交換的是cp1和cp2指向的地址,並沒有操作cp1和cp2指向的地址的值,因此不會影響main函數中的變量a, b的值。
    -gdb調試過程:
    swap2-gdb

  • swap3中各個變量在內存中的情況:
    swap3
    在調用swap3(char *cp1, char *cp2)時,

    1. 會產生對應的兩個臨時指針變量cp1, cp2,程序會將&a, &b的值分別賦值給cp1, cp2
    2. 使用*cp1讀取到cp1指向的內存空間中的數據賦值給臨時變量tmp,此時tmp的值變爲變量a的值
    3. 使用*cp2讀取到cp2指向的內存空間中的數據(b的值),並將數據寫到cp1指向的內存空間(&a)中,
      覆蓋掉原來的數據(原來存放的是變量a的值),此時cp1指向的內存空間中存儲的就是b的值了,
      也就是說變量a裏存放的數據變成了變量b的值
    4. 將tmp的值寫到cp2指向的內存空間(&b)中,覆蓋掉原來的數據(原來存放的是變量b的值),此時cp2
      指向的內存空間中存儲的就是tmp的值了,也就是說變量b裏存放的數據變成了最開始的變量a的值
      -gdb調試過程:
      swap3-gdb
  • swap4中各個變量在內存中的情況比較簡單,就不畫圖了,直接上gdb調試的圖:
    -gdb調試過程:
    swap4-gdb

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章