[英]Why does this code to randomize a list of song names generate a segmentation fault?
[英]Why does this generate a segmentation fault?
#include<stdio.h>
void foo(int **arr) {
arr[1][1]++;
}
main() {
int arr[20][20];
printf("%d\n",arr[1][1]);
foo((int**)arr);
printf("%d\n",arr[1][1]);
}
假設您聲明:int arr [10] [20];
什么是arr?
您可能會認為它是int **
,但這是不正確的。它衰減時實際上是
int (*)[20]
類型的(例如,當您將其傳遞給函數時);
數組衰減僅應用一次。
現在考慮以下內容,
#include<stdio.h>
#include<stdlib.h>
void foo(int arr[][20]) {
arr[1][1]++;
}
main() {
int (*arr)[20];
arr = malloc(sizeof(int (*)[]) * 2); //2 rows & malloc will do implicit cast.
printf("%d\n",arr[1][1]);
foo(arr);
printf("%d\n",arr[1][1]);
}
輸出:
$ gcc fdsf.c && ./a.out
0
1個
arr和arr + 1指向20個整數的數組。
arr + 0-> int int int ... int(20個整數,連續)
[0] [0] [0] [1]
arr + 1-> int int int ... int(20個整數,連續)
[1] [0] [1] [1]
這是一個int[2][2]
在內存中的樣子:
int[2] int[2]
也就是說,一個數組緊跟着另一個數組。
這是一個int[2]
在內存中的樣子:
int int
也就是說,一個int緊跟着另一個int。
因此,這也是int[2][2]
在內存中的樣子:
int int int int
^ ^
| |___ this is arr[1][1]
|
|____ this is p[1], assuming sizeof(int*) == sizeof(int)
如果將arr
轉換為int**
,則將結果稱為p
。 然后它指向相同的內存。 當您執行p[1][1]
您不會得到arr[1][1]
。 程序要做的是,讀取p[1]
處的值,將其調整為int的大小,然后取消引用 。 如果第二個int包含值“ 21”,則您剛剛嘗試取消引用指針“ 25”(如果int
為4個字節)。 那是不對的。
數組與指針不一樣,二維數組與指針到指針當然也不一樣。
因為foo期望有一個指向int的指針,並且您正在向它傳遞一個指向20個int數組的指針。 強制轉換它不會改變它不是正確類型的事實。
如果您這樣更改它,您將獲得預期的結果:
#include<stdio.h>
void foo(int arr[][20]) {
arr[1][1]++;
}
int
main() {
int arr[20][20];
arr[1][1] = 1;
printf("%d\n",arr[1][1]);
foo(arr);
printf("%d\n",arr[1][1]);
}
foo
需要知道數組的大小(嗯,至少不需要第二個數組的維,第一個是不需要的),否則它不能為[1][1]
做必要的指針運算。
問題是2d數組的int arr[20][20]
意味着此數組存儲為1d數組,並且一行接一行地存儲行。 當您索引到int **arr
,實際上是從數組的第一行獲取第二個元素,然后取消引用它,然后從那里獲取第一個元素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.