簡體   English   中英

C語言中指針和數組的工作

[英]Working of Pointers and Arrays in C

我正在使用Visual Studio 2013 for C.

main.c中

int main()                          
{
    int arr[2][3] = { { 10, 20, 30 }, { 15, 25, 35 } };
    int **pArr = arr;

    printf("\n\n----SIZE OF----");
    printf("\nSizeOf(arr) = %d", sizeof(arr));
    printf("\nSizeOf(pArr) = %d", sizeof(pArr));

    printf("\n\n----DEREFERENCING THE ADDRESS----");
    printf("\narr = %d   *arr = %d   **arr = %d", arr, *arr, **arr);
    printf("\npArr = %d   *pArr = %d   **pArr = %d", pArr, *pArr, **pArr);    //EXCEPTION thrown here

    return 0;
}

檢出此圖像以查找拋出的異常:

例外

使用斷點時,將顯示指針pArr和數組arr中的值:

關於調試

但是,當我從代碼的第二行中刪除**pArr部分時,程序將輸出以下內容:

----SIZE OF----
SizeOf(arr) = 24
SizeOf(pArr) = 4

----DEREFERENCING THE ADDRESS----
arr = 5569760   *arr = 5569760   **arr = 10
pArr = 5569760   *pArr = 10

指針pArr的類型為“指向int的指針”,因此它是arr的地址。 那為什么在使用int **pArr = arr;后為什么不能訪問**pArr int **pArr = arr;

因為*pArr產生2D數組的第一個元素10,所以會出現錯誤。
然后,通過在最后一個printf寫入**pArr ,您嘗試取消引用以十六進制0xa表示的10,從而出現錯誤消息。

更改

int **pArr = arr;

int *Arr = arr;
int **pArr = &Arr;

由於pArr是一個指向int類型的指針的指針,因此您試圖將其僅指向一個指針。 因此,當嘗試取消引用未知的內存位置時,會導致Segmentation fault

編輯:
考慮int arr[] ;
這里&arrarr是內存位置。 (arr + 2)來獲取arr [2]的地址,而不是((&arr)+2)來獲取相同的地址。 同樣, pArr指向arr 當您編寫*pArr它與**arr相同

請參閱差異以了解更多信息

您的數組arrpArr包含地址0x60f914 您已初始化的內存中包含6個整數。

當您執行*pArr ,它將在地址0x60f914處包含10 當您執行**pArr ,它將在地址10處包含您的內容。

因此,得出的結論是二維數組未完全按照_pointer-to-pointer-int的形式排列。


更新:

這類似於類型轉換。 如果您有一些內存地址(例如void * ),則可以將其類型轉換為任何內容( int *my_struct * )並訪問其中的內容。 但這不能保證該結構及其包含的內存對於您嘗試執行的類型轉換有效。

如果使用一維數組,則arr是指向數組arr的基值的指針。 &arr[0]一樣好。

使用二維數組時,arr表示指向基值的指針,即arr[0] ,它是(*arr)[3]

所以你應該使用

int (*pArr)[3] = arr;

代替

int **ptr = arr;

多維數組是編譯器構造。 它是一個連續的內存區域,其位置由編譯器提取。 計算機的物理內存布局純粹是一維的(巨大的數組)。

因此,以下代碼:

int **pArr = arr;

它翻譯為以下程序集:

   6:hhh1.c         ****     int **pArr = arr;
  41                    .loc 1 6 0
  42 0032 488D45E0      leaq    -32(%rbp), %rax
  43 0036 488945D8      movq    %rax, -40(%rbp)

和以下(正確)代碼:

 int (*pArr)[3] = arr;

在以下程序集中翻譯:

   6:hhh2.c         ****     int (*pArr)[3] = arr;
  41                    .loc 1 6 0
  42 0032 488D45E0      leaq    -32(%rbp), %rax
  43 0036 488945D8      movq    %rax, -40(%rbp)

驚訝的是它翻譯的完全一樣!? 這是因為第二個代碼更改了編譯器稍后在代碼上獲取內存的方式。

讓我們看一下最后一個或您自己的printf的匯編,第一個是錯誤的代碼,第二個是正確的代碼:

  14:hhh1.c         ****     printf("\npArr = %d   *pArr = %d **pArr = %d", pArr, *pArr, **pArr);    //EXCEPTION thrown here
  71                    .loc 1 14 0
  72 00a0 488B45D8      movq    -40(%rbp), %rax
  73 00a4 488B00        movq    (%rax), %rax
  74 00a7 8B08          movl    (%rax), %ecx
  75 00a9 488B45D8      movq    -40(%rbp), %rax
  76 00ad 488B10        movq    (%rax), %rdx
  77 00b0 488B45D8      movq    -40(%rbp), %rax
  78 00b4 4889C6        movq    %rax, %rsi
  79 00b7 BF000000      movl    $.LC5, %edi
  79      00
  80 00bc B8000000      movl    $0, %eax
  80      00
  81 00c1 E8000000      call    printf

現在,通過使用第二種樣式生成:

  14:hhh2.c         ****     printf("\npArr = %d   *pArr = %d **pArr = %d", pArr, *pArr, **pArr);    //EXCEPTION thrown here
  71                    .loc 1 14 0
  72 00a0 488B45D8      movq    -40(%rbp), %rax
  73 00a4 8B08          movl    (%rax), %ecx
  74 00a6 488B55D8      movq    -40(%rbp), %rdx
  75 00aa 488B45D8      movq    -40(%rbp), %rax
  76 00ae 4889C6        movq    %rax, %rsi
  77 00b1 BF000000      movl    $.LC5, %edi
  77      00
  78 00b6 B8000000      movl    $0, %eax
  78      00
  79 00bb E8000000      call    printf

哇! 現在看到嗎 這不一樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM