C中的多维数组:它们是锯齿状的吗?

时间:2021-01-18 21:32:25

A simple question about the C programming language (ANSI-C):

关于C编程语言(ANSI-C)的一个简单问题:

Are the multi-dimensional arrays in C jagged?

在C中多维数组是锯齿状的吗?

I mean - are we talking about "array of arrays" (one array of pointers to other addresses in the memory) , or this is just "long one-dimensional array" (which is stored sequentially in the memory)?

我的意思是——我们讨论的是“数组数组”(指向内存中其他地址的一个数组),还是仅仅是“长一维数组”(按顺序存储在内存中)?

What that bothers me is that I'm kinda sure that:

让我烦恼的是我确信

matrix[i][j] is equivalent to * ( * (matrix + i) + j)

矩阵[i][j]等价于*(*(矩阵+ i) + j)

6 个解决方案

#1


13  

A multidimensional array in C is contiguous. The following:

C中的多维数组是连续的。以下几点:

int m[4][5];

consists of 4 int[5]s laid out next to each other in memory.

由4个相互排列在内存中的整数[5]组成。

An array of pointers:

一个数组的指针:

int *m[4];

is jagged. Each pointer can point to (the first element of) a separate array of a different length.

是锯齿状的。每个指针可以指向(第一个元素)不同长度的单独数组。

m[i][j] is equivalent to *(*(m+i)+j). See the C11 standard, section 6.5.2.1:

m[i][j]等于*(*(m+i)+j)。参见C11标准第6.5.2.1节:

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))

下标运算符[]的定义是E1[E2]与(*((E1)+(E2))相同

Thus, m[i][j] is equivalent to (*(m+i))[j], which is equivalent to *(*(m+i)+j).

因此,m[i][j]等于(*(m+i))[j],等于*(*(*(m+i)+j)。

This equivalence exists because in most contexts, expressions of array type decay to pointers to their first element (C11 standard, 6.3.2.1). m[i][j] is interpreted as the following:

这种等价之所以存在,是因为在大多数情况下,数组类型的表达式会衰减到指向第一个元素的指针(C11标准,6.3.2.1)。m[i][j]的解释如下:

  • m is an array of arrays, so it decays to a pointer to m[0], the first subarray.
  • m是数组的数组,因此它衰减为指向第一个子数组m[0]的指针。
  • m+i is a pointer to the ith subarray of m.
  • m+i是指向m的第i个子数组的指针。
  • m[i] is equivalent to *(m+i), dereferencing a pointer to the ith subarray of m. Since this is an expression of array type, it decays to a pointer to m[i][0].
  • m[i]等价于*(m+i),去引用一个指向m的第i个子数组的指针。由于这是一个数组类型的表达式,它会衰减到一个指向m[i][0]的指针。
  • m[i][j] is equivalent to *(*(m+i)+j), dereferencing a pointer to the jth element of the ith subarray of m.
  • m[i][j]等于*(*(*(m+i)+j),撤销指向m的第i个子数组第j个元素的指针。

Note that pointers to arrays are different from pointers to their first element. m+i is a pointer to an array; it is not an expression of array type, and it does not decay, whether to a pointer to a pointer or to any other type.

注意,指向数组的指针不同于指向第一个元素的指针。m+i是指向数组的指针;它不是数组类型的表达式,它不会衰变,无论是指针指向指针还是其他类型。

#2


3  

A consecutive memory area:

一个连续的内存区域:

int arr[N][M];

A non-consecutive memory area:

一个连任的内存区域:

int** arr = malloc(N*sizeof(int*));
for (int i=0; i<N; i++)
    arr[i] = malloc(M*sizeof(int));

You can use arr as a 2-dimensional array (e.g., arr[1][2] = 3) in both cases. But you can safely apply larger copy operations, such as memset(arr,0,N*M*sizeof(int)), only in the first case.

在这两种情况下,都可以使用arr作为二维数组(例如,arr[1][2] = 3)。但是您可以安全地应用较大的复制操作,例如memset(arr,0,N*M*sizeof(int)),仅在第一个例子中。

#3


2  

This would depend.

这将取决于。

Multidimensional arrays in C are sequentially arranged.

C中的多维数组是按顺序排列的。

You can create jagged arrays if you want using pointers.

如果需要使用指针,可以创建交错数组。

#4


1  

If you declare a multi-dimensional array, you get "long one-dimensional array" (which is stored sequentially in the memory).

如果声明一个多维数组,就会得到“长一维数组”(它按顺序存储在内存中)。

If you declare a pointer to pointer (to pointer....) you get arrays of arrays.

如果你声明一个指针的指针(指针....)得到数组的数组。

This difference is a source of much confusion for beginner C programmers.

对于初学者C程序员来说,这种差异造成了很多困惑。

#5


0  

An array or arrays, such as int matrix[A][B] is not jagged, as each element of matrix is an array of B int.

数组或数组(如int矩阵[A][B])没有锯齿状,因为矩阵的每个元素都是B int的数组。

You want to know that the outcome of *(*(matrix+i)+j) is and compare it to the outcome of matrix[i][j].

你想知道*(*(矩阵+i)+j)的结果与矩阵[i][j]的结果相比较。

Since the type of matrix is array of A array of B int, then the expression matrix+i is a pointer that points to the ith array of B int of matrix, and its type is int (*)[B]. Dereferencing this expression results in an array of B int. The expression *(matrix+i)+j) results in a pointer to the jth int of that array. Dereferencing that expression results in an int. This is equivalent to what the expression matrix[i][j] would do.

由于矩阵的类型是一个B int数组的数组,那么表达式矩阵+i是指向矩阵B int的第i个数组的指针,其类型是int (*)[B]。取消这个表达式的引用会产生一个B int的数组,表达式*(matrix+i)+j)会产生一个指向该数组第j个int的指针。去引用那个表达式会产生一个int数,这等价于表达式矩阵[i][j]的作用。

An array of pointers, such as int *matrix[A], may be jagged, as each element of matrix may point to a different sized allocation.

指针数组,如int *matrix[A],可能会出现锯齿状,因为矩阵的每个元素可能指向不同大小的分配。

#6


0  

You are right, that matrix[i][j] is equivalent to *(*(matrix + i) + j), since arr[i] is equivalent to *(arr + i). However, please keep in mind, that if arr is declared as

你是对的,这个矩阵[i][j]等于*(*(矩阵+ i) + j),因为arr[i]等于*(arr + i),但是请记住,如果arr被声明为。

int arr[64];

then any reference to arr may be implicitly converted to &arr[0], that is a pointer to the first element. Same thing happens with arrays of arrays:

那么对arr的任何引用都可以隐式地转换为&arr[0],这是指向第一个元素的指针。数组的数组也一样:

int matrix[8][8];

Here matrix has type int[8][8], which is automatically converted to int (*)[8] when you add an integer to it, as in matrix + i. Then *(matrix + i) has type int[8], which is again converted to int * when you add j, so *(matrix + i) + j has type int *, therefore *(*(matrix + i) + j) has type int as expected.

这里矩阵类型int[8][8],这是自动转换为int(*)[8]当你添加一个整数,如矩阵+我。那么*(矩阵+ i)类型int[8],这是再转换为int *当你加入j,所以*(矩阵+ i)+ j类型int *,因此*(*(矩阵+ i)+ j)类型int作为预期。

So the point is, that arrays are not pointers, it is just that they can be implicitly casted to a pointer to their first element.

关键是,数组不是指针,只是可以隐式地将它们转换为指向第一个元素的指针。

So if you allocate arrays of arrays like above (int matrix[8][8];), then then all elements are consecutive in memory.

因此,如果你像上面那样分配数组(int matrix[8][8];),那么所有元素在内存中都是连续的。

#1


13  

A multidimensional array in C is contiguous. The following:

C中的多维数组是连续的。以下几点:

int m[4][5];

consists of 4 int[5]s laid out next to each other in memory.

由4个相互排列在内存中的整数[5]组成。

An array of pointers:

一个数组的指针:

int *m[4];

is jagged. Each pointer can point to (the first element of) a separate array of a different length.

是锯齿状的。每个指针可以指向(第一个元素)不同长度的单独数组。

m[i][j] is equivalent to *(*(m+i)+j). See the C11 standard, section 6.5.2.1:

m[i][j]等于*(*(m+i)+j)。参见C11标准第6.5.2.1节:

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))

下标运算符[]的定义是E1[E2]与(*((E1)+(E2))相同

Thus, m[i][j] is equivalent to (*(m+i))[j], which is equivalent to *(*(m+i)+j).

因此,m[i][j]等于(*(m+i))[j],等于*(*(*(m+i)+j)。

This equivalence exists because in most contexts, expressions of array type decay to pointers to their first element (C11 standard, 6.3.2.1). m[i][j] is interpreted as the following:

这种等价之所以存在,是因为在大多数情况下,数组类型的表达式会衰减到指向第一个元素的指针(C11标准,6.3.2.1)。m[i][j]的解释如下:

  • m is an array of arrays, so it decays to a pointer to m[0], the first subarray.
  • m是数组的数组,因此它衰减为指向第一个子数组m[0]的指针。
  • m+i is a pointer to the ith subarray of m.
  • m+i是指向m的第i个子数组的指针。
  • m[i] is equivalent to *(m+i), dereferencing a pointer to the ith subarray of m. Since this is an expression of array type, it decays to a pointer to m[i][0].
  • m[i]等价于*(m+i),去引用一个指向m的第i个子数组的指针。由于这是一个数组类型的表达式,它会衰减到一个指向m[i][0]的指针。
  • m[i][j] is equivalent to *(*(m+i)+j), dereferencing a pointer to the jth element of the ith subarray of m.
  • m[i][j]等于*(*(*(m+i)+j),撤销指向m的第i个子数组第j个元素的指针。

Note that pointers to arrays are different from pointers to their first element. m+i is a pointer to an array; it is not an expression of array type, and it does not decay, whether to a pointer to a pointer or to any other type.

注意,指向数组的指针不同于指向第一个元素的指针。m+i是指向数组的指针;它不是数组类型的表达式,它不会衰变,无论是指针指向指针还是其他类型。

#2


3  

A consecutive memory area:

一个连续的内存区域:

int arr[N][M];

A non-consecutive memory area:

一个连任的内存区域:

int** arr = malloc(N*sizeof(int*));
for (int i=0; i<N; i++)
    arr[i] = malloc(M*sizeof(int));

You can use arr as a 2-dimensional array (e.g., arr[1][2] = 3) in both cases. But you can safely apply larger copy operations, such as memset(arr,0,N*M*sizeof(int)), only in the first case.

在这两种情况下,都可以使用arr作为二维数组(例如,arr[1][2] = 3)。但是您可以安全地应用较大的复制操作,例如memset(arr,0,N*M*sizeof(int)),仅在第一个例子中。

#3


2  

This would depend.

这将取决于。

Multidimensional arrays in C are sequentially arranged.

C中的多维数组是按顺序排列的。

You can create jagged arrays if you want using pointers.

如果需要使用指针,可以创建交错数组。

#4


1  

If you declare a multi-dimensional array, you get "long one-dimensional array" (which is stored sequentially in the memory).

如果声明一个多维数组,就会得到“长一维数组”(它按顺序存储在内存中)。

If you declare a pointer to pointer (to pointer....) you get arrays of arrays.

如果你声明一个指针的指针(指针....)得到数组的数组。

This difference is a source of much confusion for beginner C programmers.

对于初学者C程序员来说,这种差异造成了很多困惑。

#5


0  

An array or arrays, such as int matrix[A][B] is not jagged, as each element of matrix is an array of B int.

数组或数组(如int矩阵[A][B])没有锯齿状,因为矩阵的每个元素都是B int的数组。

You want to know that the outcome of *(*(matrix+i)+j) is and compare it to the outcome of matrix[i][j].

你想知道*(*(矩阵+i)+j)的结果与矩阵[i][j]的结果相比较。

Since the type of matrix is array of A array of B int, then the expression matrix+i is a pointer that points to the ith array of B int of matrix, and its type is int (*)[B]. Dereferencing this expression results in an array of B int. The expression *(matrix+i)+j) results in a pointer to the jth int of that array. Dereferencing that expression results in an int. This is equivalent to what the expression matrix[i][j] would do.

由于矩阵的类型是一个B int数组的数组,那么表达式矩阵+i是指向矩阵B int的第i个数组的指针,其类型是int (*)[B]。取消这个表达式的引用会产生一个B int的数组,表达式*(matrix+i)+j)会产生一个指向该数组第j个int的指针。去引用那个表达式会产生一个int数,这等价于表达式矩阵[i][j]的作用。

An array of pointers, such as int *matrix[A], may be jagged, as each element of matrix may point to a different sized allocation.

指针数组,如int *matrix[A],可能会出现锯齿状,因为矩阵的每个元素可能指向不同大小的分配。

#6


0  

You are right, that matrix[i][j] is equivalent to *(*(matrix + i) + j), since arr[i] is equivalent to *(arr + i). However, please keep in mind, that if arr is declared as

你是对的,这个矩阵[i][j]等于*(*(矩阵+ i) + j),因为arr[i]等于*(arr + i),但是请记住,如果arr被声明为。

int arr[64];

then any reference to arr may be implicitly converted to &arr[0], that is a pointer to the first element. Same thing happens with arrays of arrays:

那么对arr的任何引用都可以隐式地转换为&arr[0],这是指向第一个元素的指针。数组的数组也一样:

int matrix[8][8];

Here matrix has type int[8][8], which is automatically converted to int (*)[8] when you add an integer to it, as in matrix + i. Then *(matrix + i) has type int[8], which is again converted to int * when you add j, so *(matrix + i) + j has type int *, therefore *(*(matrix + i) + j) has type int as expected.

这里矩阵类型int[8][8],这是自动转换为int(*)[8]当你添加一个整数,如矩阵+我。那么*(矩阵+ i)类型int[8],这是再转换为int *当你加入j,所以*(矩阵+ i)+ j类型int *,因此*(*(矩阵+ i)+ j)类型int作为预期。

So the point is, that arrays are not pointers, it is just that they can be implicitly casted to a pointer to their first element.

关键是,数组不是指针,只是可以隐式地将它们转换为指向第一个元素的指针。

So if you allocate arrays of arrays like above (int matrix[8][8];), then then all elements are consecutive in memory.

因此,如果你像上面那样分配数组(int matrix[8][8];),那么所有元素在内存中都是连续的。