Difference between int* a and int (*a)[N] in functions?*
While int* a is a pointer to int , int (*b)[N] is a pointer to an array of Nint s. These are different types, and are not compatible. b can only point to an array of Nint s while a can only point to an int wether it's an array or not, and can't (souldn't) point to b . When you pass an array as argument you are really passing a pointer to its first element. Another difference is that if you increment b it will point to the next block of Nint s whereas if you increment a it will just point to the next int .
I have a program where I want to pass 2d int arrays to functions. Which is the better one to use and does it matter?*
It matters, for foo , it hints to a flat array with cols width, of course with some arithmetic you can treat it as a 2D array, bar is a more natural use for a 2D array. The memory layout will probably be the similar, and using a flat array to store elements in such a way that you can use it as a 2D array is perfectly fine. I personally find it less messy and more clear to use a pointer to array, instead of pointer to int , when I need a 2D array. Example:
#include <stdio.h>
#include <stdlib.h>
#define N 5
#define M 5
void bar(int (*a)[N]) {
// prints 20, 4 bytes * 5 (can be different deppending on the size of int)
printf("Size of a is %zu\n\n", sizeof *a);
// populate the array
int c = 1;
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
a[i][j] = c++;
// will print the initial element on each array line
for(int i = 0; i < N; i++){
printf("a[%d][0] = %2d\n", i, **a);
a++;
}
putchar('\n');
}
int main() {
int(*a)[N] = malloc(sizeof *a * M);
bar(a);
// prints the complete array
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
printf("%2d ", a[i][j]);
}
putchar('\n');
}
free(a);
}
In this code a is a 2D array N x M which is passed to bar to be populated. I added some handy prints and comments for clarification. See it live: https://godbolt.org/z/zhKcb96ob Output:
如果编译器想要例如访问arr[1][2],则它将需要知道每行有多少列,即每个子数组有多大。如果编译器不知道每行有4列,则编译器没有办法知道在哪里找到arr[1][2]。然而,如果编译器知道每行有4列,它将知道2D阵列的第5个元素是第二行的开始,因此它将知道arr[1][2]是2D阵列的第7个元素。 我可以将int数组传递给这两个函数(一维和二维数组)。 虽然在大多数编译器上可以将2D数组作为1D数组访问,但根据ISO C标准,它是undefined behavior。有关详细信息,请参阅以下问题: One-dimensional access to a multidimensional array: is it well-defined behaviour? 哪一个更好用,有关系吗? 第一种方法更好,因为它允许您在运行时指定列数,而第二种方法必须在编译时设置列数,因此灵活性较差。 但是,如上所述,根据您的编译器,将2D数组作为1D数组访问可能不安全。因此,最好将1D数组传递给第一个函数,将2D数组传递给第二个函数。 但是,第二个函数如何知道二维数组包含多少行并不清楚,因为该信息没有作为参数传递给函数。也许函数假设的行数是固定的,或者它根本不用于二维数组。您在问题中提供的信息不足以回答这个问题。
3条答案
按热度按时间0h4hbjxa1#
int* a
and int(*a)[N]
in functions?*While
int* a
is a pointer toint
,int (*b)[N]
is a pointer to an array ofN
int
s. These are different types, and are not compatible.b
can only point to an array ofN
int
s whilea
can only point to anint
wether it's an array or not, and can't (souldn't) point tob
. When you pass an array as argument you are really passing a pointer to its first element. Another difference is that if you incrementb
it will point to the next block ofN
int
s whereas if you incrementa
it will just point to the nextint
.It matters, for
foo
, it hints to a flat array withcols
width, of course with some arithmetic you can treat it as a 2D array,bar
is a more natural use for a 2D array.The memory layout will probably be the similar, and using a flat array to store elements in such a way that you can use it as a 2D array is perfectly fine. I personally find it less messy and more clear to use a pointer to array, instead of pointer to
int
, when I need a 2D array.Example:
In this code
a
is a 2D array N x M which is passed tobar
to be populated. I added some handy prints and comments for clarification. See it live: https://godbolt.org/z/zhKcb96obOutput:
hmae6n7t2#
对于二维矩阵,这两种方法之间存在显著差异
int
的指针,即使在隐式衰减之后,它也不是矩阵的正确类型。cols
在第一个原型中是int
参数,而在第二个原型中是常数N
。在这两种情况下,都没有指定列数,所以它必须是隐含的,因为它是常数或因为矩阵是方形的。a[row][col]
,这将更简单、更可读,并编译为更高效的代码。请注意,从C99开始,还有第三种可能性允许您使用数组语法,即使是对于可变数量的列也是如此。下面是一个示例:
ki1q1bka3#
第二个函数需要指定数组的大小。为什么?
您不必指定整个2D数组的整个大小,但必须指定列数,即子数组的大小。
编译器必须知道子数组大小的原因是偏移量计算需要此信息。
例如,如果定义一个2D数组,如下所示
则数组元素将按以下顺序存储在存储器中:
如果编译器想要例如访问
arr[1][2]
,则它将需要知道每行有多少列,即每个子数组有多大。如果编译器不知道每行有4列,则编译器没有办法知道在哪里找到arr[1][2]
。然而,如果编译器知道每行有4列,它将知道2D阵列的第5个元素是第二行的开始,因此它将知道arr[1][2]
是2D阵列的第7个元素。我可以将int数组传递给这两个函数(一维和二维数组)。
虽然在大多数编译器上可以将2D数组作为1D数组访问,但根据ISO C标准,它是undefined behavior。有关详细信息,请参阅以下问题:
One-dimensional access to a multidimensional array: is it well-defined behaviour?
哪一个更好用,有关系吗?
第一种方法更好,因为它允许您在运行时指定列数,而第二种方法必须在编译时设置列数,因此灵活性较差。
但是,如上所述,根据您的编译器,将2D数组作为1D数组访问可能不安全。因此,最好将1D数组传递给第一个函数,将2D数组传递给第二个函数。
但是,第二个函数如何知道二维数组包含多少行并不清楚,因为该信息没有作为参数传递给函数。也许函数假设的行数是固定的,或者它根本不用于二维数组。您在问题中提供的信息不足以回答这个问题。