首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过指向不完全数组类型的指针将多维数组传递到没有最右边大小的函数。

通过指向不完全数组类型的指针将多维数组传递到没有最右边大小的函数。
EN

Stack Overflow用户
提问于 2015-07-15 18:18:29
回答 3查看 419关注 0票数 4

据我所知,数组总是作为指针传递。例如,声明:

代码语言:javascript
复制
void foo(int array[2][5]);

编译器的方法与以下内容完全相同:

代码语言:javascript
复制
void foo(int (*array)[5]);

你可以说这两种形式是等价的。现在,我想知道为什么允许它宣布它为:

代码语言:javascript
复制
void foo(int (*array)[]);

虽然不是这样:

代码语言:javascript
复制
void foo(int array[][]);

举个例子:

代码语言:javascript
复制
#include <stdio.h>

void foo(int (*p)[3]);
void bar(int (*p)[]);

int main(void)
{
    int a[2][3] = {{1, 2, 3}, {4, 5, 6}};

    foo(a);
    bar(a);

    return 0;
}

// The same as int p[][3] or int p[N][3] where N is a constant expression
void foo(int (*p)[3]) 
{

}

// Would it the same as int p[][] or int p[N][] (by analogy)?
void bar(int (*p)[])
{

}

它编译得很好,没有警告,但如果我将bar的声明更改为:

代码语言:javascript
复制
void bar(int p[][]);

那就是个错误。

为什么C允许这样“模糊”的方式传递数组?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-07-15 18:44:34

您被C语言对“未指定”大小数组的支持绊倒了,您可以声明这些数组,但通常不能直接使用,除非您在某个地方给它一个更具体的大小。

在您的示例中,如果您实际尝试对bar中的数组执行任何操作,则会得到一个错误:

代码语言:javascript
复制
void bar(int (*p)[])
{
    printf("%d\n", p[1][1]);
}

% gcc -Wall t.c
t.c: In function ‘bar’:
t.c:23:5: error: invalid use of array with unspecified bounds
     printf("%d\n", p[1][1]);
     ^

在bar中使用p的唯一方法是将其转换为具有显式大小的某种类型,或者将其传递给其他函数,该函数接受指向数组的指针(大小为指定或未指定大小),如果使用错误的显式大小尝试访问数组,则会得到未定义的行为,没有任何警告。

票数 2
EN

Stack Overflow用户

发布于 2015-07-15 18:21:43

数组不是指针,如果您声明一个不指定大小的指针数组,这是可以的,因为它将连续地存储在诗器中的地址,并且每个元素的大小都是已知的,但是p[][]将要求数组是连续的,而不是它们的地址,而且数组的大小是未知的,所以这就是问题所在。

为了说明清楚,如果您说int p[][],您不知道p[0]p[1]有多远,而在int (*p)[]中,您知道距离是指针的大小。

数组被转换为指针,但不是指针。

票数 5
EN

Stack Overflow用户

发布于 2015-07-15 18:32:12

数组可以作为指针使用,但它们不仅仅是指针;它们指向一些具有大小的东西。这样,您就可以告诉编译器您对数组的第三个或第五个元素感兴趣,它将通过将一个元素的大小乘以三或五个来找到偏移量,并将该偏移量添加到数组的地址来计算该元素的位置。

C实际上没有多维数组。它所拥有的是数组,这几乎是一回事。说你有这个:

代码语言:javascript
复制
int a[4][5];

在记忆中,这个应该是这样的:

代码语言:javascript
复制
  [0]                 |[1]                |[2]                |[3]
  +-------------------|-------------------|-------------------|-------------------+
a |   |   |   |   |   |   |   |   |   |   |   |   | X |   |   |   |   |   |   |   |
  +-------------------|-------------------|-------------------|-------------------+
    0   1   2   3   4 | 0   1   2   3   4 | 0   1   2   3   4 | 0   1   2   3   4 |

然后尝试访问索引[2][2]上的元素,然后系统需要执行以下计算(概念上):

  • 取int的大小,乘以5,得到内部数组的大小。
  • 取内部数组的大小,乘以2,得到外部数组中第二个元素的偏移量。
  • 再取int的大小,乘以2,得到内部数组中第二个元素的偏移量。
  • 添加两个偏移量;这是您的内存地址

在本例中,计算是*(a + (2 * 5 * sizeof(int)) + (2 * sizeof(int))),给出了*(a + 12*sizeof(int)),这确实是起始指针的正确偏移量。

这意味着需要定义内部数组的大小,以便编译器能够进行计算。如果不定义多维数组的任何维度(但最左边的维度)的大小,则没有定义的大小,编译器就会犹豫。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31438122

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档