关于指针和数组的问题

问题描述 投票:0回答:3

理智检查问题:

我做了一些谷歌搜索并发现了在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; 但他们不是两种声明阵列的方式吗?如果我使用后一个声明,我可以将值赋给[10000000]吗?

主要问题:

  1. 如何在C中返回二维数组?我不认为我只能返回指向数组开头的指针,因为我不知道数组的维数。

感谢你的帮助!

c
3个回答
2
投票
  1. 是;数组索引是根据指针算法完成的:a[i]定义为*(a + i);我们在i之后找到a'th元素的地址并取消引用结果。所以a可以声明为指针或数组。
  2. 它将被解释为地址,是(很可能是无效地址)。您需要将文字3强制转换为指针,因为intint *类型的值不兼容。
  3. 是的,这是合法的。毫无意义,但合法。
  4. 指针和数组不是一回事;在大多数情况下,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,其值将是数组的第一个元素的地址。单独声明一个指针是不够的,因为除非你初始化它指向一块内存(malloc调用或另一个数组的结果),否则它的值将是不确定的,并且可能不指向有效的内存。
  5. 你真的不想返回数组;请记住,数组表达式转换为指针表达式,因此您将返回第一个元素的地址。但是,当函数退出时,该数组不再存在且指针值不再有效。最好将要修改的数组作为参数传递给函数,例如 void foo(int * a,size_t asize){size_t i; for(i = 0; i <asize; i ++)a [i] = some_value(); }

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

对于2D数组,你可以做类似的事情

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编译器;否则列数必须是常量表达式(即,在编译时已知)。


3
投票
  1. 是的,但它需要一个演员:return(int *)3;
  2. 是的,但是您没有将数组分配给另一个数组,而是指定指向指针的指针。
  3. 指针和数组不是一回事。 int [10]预留10个英镑的空间。 int * a是一个未初始化的变量,指向谁知道什么。当您尝试访问无法访问或不存在的内存时,访问[10000000]很可能会导致程序崩溃。
  4. 要返回一个2d数组,返回一个指向指针的指针:int ** f(){}

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。)但需要很简单。您需要告诉编译器如何计算第一列之后的元素的地址。 (我正在使用“column”作为最右边的索引。)在这种情况下,我们可能假设它需要将地址((2 * 1)+ 1)递增到索引[1] [1]。

但是,编译器知道(希望)还有一些事情,你可能不会。

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

通常,编译时数组是按顺序存储的,与维度无关,没有额外的指针。但是,请务必查看编译器文档。因此,如果编译器允许您索引[0] [2],它实际上是[1] [0]等。然而,运行时数组是你做的。您可以制作任意长度的一维数组,并将其地址放入其他数组,也可以选择任何长度。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.