C指针帮助:数组/指针等价



在这个玩具代码示例中:

int MAX = 5;
void fillArray(int** someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
(*someArray)[i] = blah[i];  // segfault happens here
}
int main() {
int someArray[MAX];
int blah[] = {1, 2, 3, 4, 5};
fillArray(&someArray, blah);
return 0;
}

我想填充数组someArray,并使更改在函数之外保持不变。

这是一个非常大的家庭作业的一部分,这个问题解决了这个问题,而不允许我复制解决方案。我得到了一个函数签名,它接受一个int**作为参数,我应该编写逻辑来填充该数组。我的印象是,取消引用&fillArray()函数中的someArray将为我提供所需的数组(指向第一个元素的指针),并且在该数组上使用方括号中的数组元素访问将给我提供需要分配的必要位置。然而,我不明白为什么我会出现segfault。

非常感谢!

我想填充数组someArray,并在函数外保持更改。

只需将数组传递给函数,因为它会衰减到指向第一个元素的指针:

void fillArray(int* someArray, int* blah) {
int i;
for (i=0; i<MAX; i++)
someArray[i] = blah[i]; 
}

并调用:

fillArray(someArray, blah);

元素的更改将在函数之外可见。

如果实际的代码是在fillArray()中分配一个数组,则需要一个int**

void fillArray(int** someArray, int* blah) {
int i;
*someArray = malloc(sizeof(int) * MAX);
if (*someArray)
{
for (i=0; i<MAX; i++)  /* or memcpy() instead of loop */
(*someArray)[i] = blah[i];
}
}

并调用:

int* someArray = NULL;
fillArray(&someArray, blah);
free(someArray);

当您创建一个数组时,例如int myArray[10][20],会从堆栈中分配一个有保证的连续内存块,并使用普通的数组算术来查找数组中的任何给定元素。

如果你想从堆中分配3D"数组",你可以使用malloc()来获取一些内存。这种记忆是"愚蠢的"。它只是一块内存,应该被认为是一个向量。数组附带的导航逻辑都没有,这意味着您必须找到另一种方法来导航所需的3D数组。

由于您对malloc()的调用返回一个指针,因此您需要的第一个变量是一个指针来保存int*s的向量,您将需要保存一些实际的整数数据IE:

int*pArray;

但这仍然不是您想要存储整数的存储空间。您所拥有的是一个指针数组,当前不指向任何内容。为了获得数据的存储空间,您需要调用malloc()10次,每个malloc)在每次调用中为20个整数分配空间,这些整数的返回指针将存储在指针的*pArray向量中。这意味着

int*pArray

需要更改为

int**pArray

以正确地指示它是指向指针向量的基的指针。

第一个解引用,*pArray[i],将您放在int指针数组中的某个位置,而第二个解引用*p[i][j],将使您放在由pArray[i]中的int指针指向的int数组中的某处。

IE:你有一个散布在堆上的整数向量云,由一组跟踪其位置的指针指向。与从堆栈静态分配的Array[10][20]完全不同,后者都是连续存储,并且在任何位置都没有一个指针。

正如其他人所回避的那样,乍一看,基于指针的堆方法似乎没有太多优点,但事实证明它非常优越。

首先,也是最重要的一点,您可以随时释放()或realloc()来调整堆内存的大小,并且当函数返回时,它不会超出范围。更重要的是,经验丰富的C编码器在可能的情况下安排他们的函数对向量进行操作,其中在函数调用中删除了1级间接性。最后,对于大型阵列,相对于可用内存,尤其是在大型共享机器上,大块的连续内存通常不可用,并且对其他需要内存进行操作的程序不友好。在堆栈上分配具有大型静态数组的代码是维护噩梦。

在这里,您可以看到该表只是一个收集向量操作返回的向量指针的shell,其中所有有趣的事情都发生在向量级别或元素级别。在这种特殊情况下,VecRand()中的矢量代码正在调用它自己的存储,并将calloc()的返回指针返回给TblRand(

/*-------------------------------------------------------------------------------------*/
dbl **TblRand(dbl **TblPtr, int rows, int cols)
{
int  i=0;
if ( NULL == TblPtr ){
if (NULL == (TblPtr=(dbl **)calloc(rows, sizeof(dbl*)))) 
printf("nCalloc for pointer array in TblRand failed");
}
for (; i!=rows; i++){
TblPtr[i] = VecRand(NULL, cols);
}
return TblPtr;
}
/*-------------------------------------------------------------------------------------*/
dbl *VecRand(dbl *VecPtr, int cols)
{
if ( NULL == VecPtr ){
if (NULL == (VecPtr=(dbl *)calloc(cols, sizeof(dbl)))) 
printf("nCalloc for random number vector in VecRand failed");
}
Randx = GenRand(VecPtr, cols, Randx);
return VecPtr;
}
/*--------------------------------------------------------------------------------------*/
static long GenRand(dbl *VecPtr, int cols, long RandSeed)
{
dbl  r=0, Denom=2147483647.0;
while ( cols-- )
{
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
r       = sqrt(-2.0 * log((dbl)(RandSeed/Denom)));
RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
*VecPtr = r * sin(TWOPI * (dbl)(RandSeed/Denom));
VecPtr++;
}
return RandSeed;
}

没有"数组/指针"等价,数组和指针非常不同。永远不要混淆它们。someArray数组&someArray是指向数组的指针,类型为int (*)[MAX]。该函数将一个指针指向一个指针,即int **,该指针需要指向内存中某个地方的指针变量。代码中的任何位置都没有指针变量。它可能指向什么?

数组值可以隐式地降级为某些表达式中其第一个元素的指针右值。需要左值的东西,比如获取地址(&),显然不能以这种方式工作。以下是数组类型和指针类型之间的一些区别:

  • 无法分配或传递数组类型。指针类型可以
  • 指向数组的指针和指向指针的指针是不同的类型
  • 数组数组和指针数组是不同的类型
  • 数组类型的sizeof是组件类型的长度乘以大小;指针的sizeof只是指针

最新更新