1

在这个玩具代码示例中:

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 会给我所需的数组(指向第一个元素的指针),并且在该数组上使用括号数组元素访问会给我需要分配的必要位置. 但是,我无法弄清楚为什么会出现段错误。

非常感谢!

4

3 回答 3

3

我想填充数组 someArray,并让更改在函数之外持续存在。

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

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

并调用:

fillArray(someArray, blah);

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

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

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);
于 2012-12-15T23:26:53.990 回答
1

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

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

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

整数 *pArray;

...但这仍然不是您要存储整数的存储空间。你所拥有的是一个指针数组,目前没有指向任何东西。要获取数据的存储空间,您需要调用 malloc() 10 次,每个 malloc() 在每次调用时为 20 个整数分配空间,其返回指针将存储在 *pArray 指针向量中。这意味着

整数 *pArray

需要改为

int **pArray

正确地表明它是一个指向指针向量基数的指针。

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

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

正如其他人所逃避的那样,基于指针的堆方法乍一看似乎没什么用,但事实证明它非常优越。

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

在这里您可以看到该表只是一个收集从向量操作返回的向量指针的外壳,其中所有有趣的事情都发生在向量级别或元素级别。在这种特殊情况下,VecRand() 中的向量代码是 calloc() 处理它自己的存储并将 calloc() 的返回指针返回到 TblRand(),但 TblRand 也可以灵活地分配 VecRand() 的存储,只需通过调用 calloc() 替换 VecRand() 的 NULL 参数

/*-------------------------------------------------------------------------------------*/
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;
}
于 2012-12-16T01:57:35.847 回答
0

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

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

  • 不能分配或传递数组类型。指针类型可以
  • 指向数组的指针和指向指针的指针是不同的类型
  • 数组数组和指针数组是不同的类型
  • sizeof数组类型的长度乘以组件类型的大小;指针的sizeof只是指针的大小
于 2012-12-16T00:21:50.383 回答