完整性检查问题:
我做了一些谷歌搜索并发现在C中返回一维整数数组的正确方法是
int * function(args);
如果我这样做,函数会返回一个指针,对吧?如果返回值是r,我可以通过输入r [n]来找到数组的第n个元素?
如果我让函数返回数字“3”,那会被解释为指向地址“3?”的指针
说我的功能就像
int * function(int * a);
这会是一个法律职能部门吗?
int * b;
b = a;
return b;
我们是否允许将数组分配给其他类似的数组?
如果指针和数组实际上是同一个东西,我可以在不指定数组大小的情况下声明指针吗?我觉得
int a[10];
传达的信息比
更多int * a;
但它们不是两种声明阵列的方式吗?如果我使用后一种声明,我可以将值分配给[10000000]吗?
主要问题:
感谢您的帮助!
答案 0 :(得分:3)
答案 1 :(得分:2)
是;数组索引是根据指针算法完成的:a[i]
定义为*(a + i)
;我们在i
之后找到a
'元素的地址,并取消引用结果。因此a
可以声明为指针或数组。
它将被解释为地址,是(很可能是无效的地址)。您需要将文字3
强制转换为指针,因为类型int
和int *
的值不兼容。
是的,这是合法的。毫无意义,但合法。
指针和数组不相同的东西;在大多数情况下,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,其值将是数组的第一个元素的地址。单独声明一个指针是不够的,因为除非你初始化它指向一块内存(malloc
调用或另一个数组的结果),否则它的值将是不确定,并且可能没有指向有效的内存。
你真的不想返回数组;请记住,数组表达式转换为指针表达式,因此您将返回第一个元素的地址。但是,当函数退出时,该数组不再存在且指针值不再有效。最好将要修改的数组作为参数传递给函数,例如
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编译器;否则列数必须是常量表达式(即,在编译时已知)。
答案 2 :(得分: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的幂,则可以通过移位而不是乘法来计算地址。因此,这可能是增加长度的一个很好的理由-编译器至少在理论上可以做到这一点而无需告诉您!这可能取决于您是否选择速度或空间优化。
任何被描述为“现代”和“强大”的体系结构都可以像取消引用一样迅速地繁殖,并且这些问题完全消失了,除了您的代码是否正确之外。