0

健全性检查问题:

我做了一些谷歌搜索,发现在 C 中返回一维整数数组的正确方法是

int * function(args);
  1. 如果我这样做,该函数将返回一个指针,对吗?如果返回值为 r,我可以通过键入 r[n] 找到数组的第 n 个元素吗?

  2. 如果我让函数返回数字“3”,那会被解释为指向地址“3”的指针吗?

  3. 说我的功能类似于

    int * function(int * a);
    

    这会是一个法律职能机构吗?

    int * b;
    b = a;
    return b;
    

    我们是否允许像这样将数组分配给其他数组?

  4. 如果指针和数组实际上是一回事,我可以只声明一个指针而不指定数组的大小吗?我感到

    int a[10];
    

    传达的信息多于

    int * a;
    

    但它们不是声明数组的两种方式吗?如果我使用后一个声明,我可以为 a[10000000] 赋值吗?

主要问题:

  1. 如何在 C 中返回二维数组?我不认为我可以只返回一个指向数组开头的指针,因为我不知道数组有哪些维度。

感谢你的帮助!

4

3 回答 3

3
  1. 是的
  2. 是的,但它需要一个演员:return (int *)3;
  3. 是的,但是您没有将数组分配给另一个数组,而是将指针分配给指针。
  4. 指针和数组不是一回事。int a[10] 为十个整数保留空间。int *a 是一个未初始化的变量,指向谁知道什么。当您尝试访问您无权访问或不存在的内存时,访问 a[10000000] 很可能会使您的程序崩溃。
  5. 要返回一个二维数组,返回一个指向指针的指针:int ** f() {}
于 2012-11-11T04:44:22.567 回答
2
  1. 是的; 数组索引是根据指针算术完成的:a[i]定义为*(a + i); 我们在i之后找到第 ' 个元素的地址a并取消引用结果。所以a可以声明为指针或数组。

  2. 它会被解释为一个地址,是的(很可能是一个无效的地址)。您需要将文字转换3为指针,因为类型int和值int *不兼容。

  3. 是的,这将是合法的。无意义,但合法。

  4. 指针和数组不是一回事。在大多数情况下,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,其值将是数组第一个元素的地址。单独声明一个指针是不够的,因为除非您将它初始化为指向一块内存(malloc调用的结果或另一个数组),否则它的值将是不确定的,并且可能不指向有效的内存。

  5. 你真的不想返回数组;请记住,数组表达式被转换为指针表达式,因此您将返回第一个元素的地址。但是,当函数退出时,该数组不再存在并且指针值不再有效。最好将要修改的数组作为参数传递给函数,例如

    void foo (int *a, size_t asize) { size_t i; for (i = 0; i < asize; i++) a[i] = some_value(); }

指针不包含有关它们指向的元素数量的元数据,因此您必须将其作为单独的参数传递。

对于二维数组,你会做类似的事情

void foo(size_t rows, size_t columns, int (*a)[columns])
{
   size_t i, j;
   for (i = 0; i < rows; i++)
     for (j = 0; j < columns; j++)
        a[i][j] = some_value;
}

这假设您使用的是支持可变长度数组的 C99 编译器或 C2011 编译器;否则列数必须是一个常量表达式(即,在编译时已知)。

于 2012-11-11T05:20:03.440 回答
0

这些答案当然需要更多的深度。你对指针理解得越好,你写的代码就越少。

数组和指针是不同的,除非它们是相同的。在我的头顶上:

int a[2][2] = { 1, 2, 3, 4 }; int (* p)[2] = a; ASSERT (p[1][1] == a[1][1]);

数组“a”的功能与指针“p”完全相同。并且编译器从每个地址中知道同样多的信息,特别是地址,以及如何计算索引地址。但请注意,数组 a 不能在运行时采用新值,而 p 可以。因此,当程序运行时,a 的“指针”方面已经消失,只剩下数组。相反,p 本身只是一个指针,它在运行时可以指向任何东西,也可以不指向任何东西。

请注意,指针声明的语法很复杂。(这就是我今天首先来到stackoverflow的原因。)但是需求很简单。您需要告诉编译器如何计算超过第一列的元素的地址。(我使用“列”作为最右边的索引。)在这种情况下,我们可能假设它需要将地址 ((2*1) + 1) 递增到索引 [1][1]。

但是,编译器知道(希望如此)还有一些您可能不知道的事情。

编译器知道两件事:1)元素是否按顺序存储在内存中,以及 2)是否真的有额外的指针数组,或者只有一个指向数组开头的指针/地址。

通常,编译时数组是按顺序存储的,与维度无关,没有额外的指针。但可以肯定的是,请检查编译器文档。因此,如果编译器允许您对 a[0][2] 进行索引,它实际上是 a[1][0] 等。但是您可以创建一个运行时数组。您可以制作您选择的任何长度的一维数组,并将它们的地址放入其他数组中,也可以选择您选择的任何长度。

而且,当然,使用其中任何一个的一个原因是因为您选择使用运行时乘法、移位或指针取消引用来索引数组。如果指针取消引用是最便宜的,您可能需要制作指针数组,因此无需进行算术运算来计算行地址。一个缺点是它需要内存来存储额外的指针。请注意,如果列长度是 2 的幂,则可以使用移位而不是乘法来计算地址。所以这可能是增加长度的一个很好的理由——编译器可以,至少在理论上,在不告诉你的情况下做到这一点!这可能取决于您选择优化速度还是空间。

任何被描述为“现代”和“强大”的架构可能会像取消引用一样快速增加,并且这些问题完全消失了——除了你的代码是否正确。

于 2019-01-11T22:53:54.777 回答