天天看點

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

數組元素作為函數參數

  做一道最常見的題目,問 ary[0] 和 ary[1] 的值是否進行交換?

#include <stdio.h>
#include <stdlib.h>

void swap(int x, int y)
{
  int nTmp = 0;
  nTmp = x;
  x = y;
  y = nTmp;
}

int main()
{
  int ary[2] = {7, 8};

  swap(ary[0], ary[1]);
  printf("%08x,%08x\r\n", ary[0], ary[1]);

  system("pause");
  return 0;
}
           

  大家都知道,調用方的傳參稱為實參,被調方接受的參數稱為形參。形參的值改變,不影響實參的值,是以 ary[0] 和 ary[1] 的值沒有進行交換。但是好多人卻隻會背這句話,并不是真正的了解。

  通過函數的設計原則以及機制這篇文章中的知識,分析函數的棧結構,仔細觀察記憶體的分布,來解決這一問題。

  按 F10 進入單步調試,從下到上,可以看到橙色部分是 main 函數的參數,綠色部分是 main 函數的傳回位址是,藍色部分是 main 函數調用方的棧底,紫色部分是 main 函數的局部變量,淺藍色是寄存器變量。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  再按 F10 ,位址 0019ff28 寫入了 main 函數的 ary[0] 的值 7 ,位址 0019ff2c 寫入了 main 函數的 ary[1] 的值 8。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  main 函數棧的範圍從位址 0019fedc 到位址 0019ff44。esp 的值就是專門指向棧頂的,它的值是位址 0019fedc 。ebp 的值就是專門指向棧底的,他的值是位址 0019ff30。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  位址 0019fedc 上面是空閑區。根據函數傳參原則,反向傳參,先傳 ary[1],再傳 ary[0],可以看到,位址0019fed8 寫入了 swap 函數的 y 的值 8 ,位址 0019fed4 寫入了 swap 函數的 x 的值 7,位址004125d3 是 swap 函數的傳回位址。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  再按 F10 ,main 函數的棧底被寫入,然後一大片的 cccccccc 作為局部變量,紫色框部分作為寄存器變量。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  再按 F10 ,位址 0019fec8 處寫入了 nTmp 的值 0。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  再按 F10 ,x 的值等于 ary[0] 等于 7,是以 nTmp = x,位址 0019fec8 寫入了 7。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

 再按 F10 ,y 的值等于 ary[1] 等于 8,是以 x = y,位址 0019fed4 寫入了 8。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  再按 F10 ,nTmp 的值等于 7,是以 y = nTmp,位址 0019fed8 寫入了 7。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  函數執行完畢,可以看到 main 函數中位址 0019ff28 和位址 0019ff2c 中的值 ary[0] 和 ary[1],并沒有被修改。

  計算機中的傳參是拷貝,不是剪切。傳參之後原記憶體内容不變,複制了一份副本,放在了其他棧空間。棧空間的一切操作,隻針對這個函數所占有的棧空間的記憶體的一切操作,并不影響其他函數棧空間的記憶體中的值的改變。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

數組位址作為函數參數

  将上面的程式稍作修改,問 ary[0] 和 ary[1] 的值是否進行交換?

#include <stdio.h>
#include <stdlib.h>

void swap(int a[])
{
  int nTmp = 0;
  nTmp = a[0];
  a[0] = a[1];
  a[1] = nTmp;
}

int main()
{
  int ary[2] = {7, 8};

  swap(ary);
  printf("%08x,%08x\r\n", ary[0], ary[1]);

  system("pause");
  return 0;
}
           

  同樣通過調試,深入了解這個程式。

  按 F10 進入單步調試,數組名 ary 代表,第 0 個元素的位址常量。觀察框中顯示 ary 的值是 0019ff28。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  再按 F10 ,位址 0019ff28 寫入了 ary[0] 的值 7 ,位址 0019ff2c 寫入了 ary[1] 的值 8。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  按 F11 進入 swap ,數組 ary 第 0 個元素的位址常量 0019ff28 ,作為實參傳入了 swap 函數的形參記憶體中。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  再按 F10 ,swap 函數的局部變量區,位址 0019fecc 寫入了 nTmp 的值 0。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

  在下一步,單步調試之前,需要說明幾個知識點。

  是否影響實參,主要看函數内有沒有對實參的位址進行“間接通路”,有間接通路,就會影響到函數外,沒間接通路,怎麼做都不影響。

  []下标運算可實作間接通路,根據數組這篇文章的知識點,通過下标運算求出位址後,按照數組元素類型去解釋這個位址,就是下标通路。

  a 的值是 0019ff28。

  a[0] 做下标運算 &a[0] = (int)a + sizeof(int)*0 = 0019ff28,對 位址 0019ff28 解釋為數組元素的類型(整形),就是 7。

  a[1] 做下标運算 &a[1] = (int)a + sizeof(int)*1 = 0019ff2c,對 位址 0019ff2c 解釋為數組元素的類型(整形),就是 8。

  再按 F10 ,進行單步調試,通過間接通路,位址 0019ff28 的值 7。複制給 nTmp。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

 再按 F10,通過間接通路,位址 0019ff2c 的值 8 。再通過間接通路,将 8 寫入到 0019ff28 的位址中。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

 再按 F10,nTmp 的值 7 ,通過間接通路,寫入到位址 0019ff2c 中。

 成功實作了 ary[0] 和 ary[1] 的互換。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

 好多人會以為,傳入的是位址,就會影響到實參,其實隻說對了一半。真正影響到實參,是進行了間接通路。

 為了更直覺的在程式中展現,傳入的實參是常量。将第 0 個元素的位址常量 0x0019ff28 直接寫入程式。程式修改為, swap(ary) 換為 swap(0x0019ff28)。

#include <stdio.h>
#include <stdlib.h>

void swap(int a[])
{
  int nTmp = 0;
  nTmp = a[0];
  a[0] = a[1];
  a[1] = nTmp;
}

int main()
{
  int ary[2] = {7, 8};

  swap(0x0019ff28);
  printf("%08x,%08x\r\n", ary[0], ary[1]);

  system("pause");
  return 0;
}
           

 同樣可以,交換 ary[0] 和 ary[1] 的值。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

 傳入數組 ary 第 0 個元素的位址常量,但不進行間接通路。形參是變量,可以進行 ++,是以 a++。

#include <stdio.h>
#include <stdlib.h>

void swap(int a[])
{
  int nTmp = 0;
  a++;
}

int main()
{
  int ary[2] = {7, 8};

  swap(ary);
  printf("%08x,%08x\r\n", ary[0], ary[1]);

  system("pause");
  return 0;
}
           

 就好比,現實中打電話。知道電話号碼,叫出這個人(間接通路),在這個人臉上畫圖案,寫字都可以(間接通路後修改值)。但是,知道電話号碼,在電話号碼上進行加一,不呼叫這個人,那麼對這個人不能造成任何影響。

 并沒有改變 ary[0] 和 ary[1] 的值,輸出結果仍為 7, 8。

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

數組作為函數參數更多精彩文章,關注公衆号。想了解更多 C/C++ 或 網絡安全知識,請關注公衆号:大人物小城夢

繼續閱讀