1

In this toy code example:

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;
}

... I want to fill the array someArray, and have the changes persist outside the function.

This is part of a very large homework assignment, and this question addresses the issue without allowing me to copy the solution. I am given a function signature that accepts an int** as a parameter, and I'm supposed to code the logic to fill that array. I was under the impression that dereferencing &someArray within the fillArray() function would give me the required array (a pointer to the first element), and that using bracketed array element access on that array would give me the necessary position that needs to be assigned. However, I cannot figure out why I'm getting a segfault.

Many thanks!

5
  • 1
    blah[5] to blah[999] are outside bounds. Why are you accessing them in fillArray? Commented Dec 15, 2012 at 23:26
  • I'm pretty sure the pointer to pointer declaration is also wrong. Commented Dec 15, 2012 at 23:28
  • The 'max' variable should have been defined as 5. My dumb mistake. The seg fault does not occur because of boundary issues. The function declaration requiring the int** parameter is given as a requirement, so I must work with it. Commented Dec 15, 2012 at 23:34
  • I'd suggest giving your code better names/comments. Regardless whether it's homework or not. Commented Dec 15, 2012 at 23:35
  • I think you may have missed the point of the exercise. The only reason I can think of for using int**, is to reference a 2-dimentional array. Therefore, I think your instructor wishes you to fill an array like Array2D[X_MAX][Y_MAX] (you'll need an i and a j loop), and I doubt he expects that array to be allocated from the stack. See my remarks and code below. Commented Dec 16, 2012 at 7:01

3 Answers 3

3

I want to fill the array someArray, and have the changes persist outside the function.

Just pass the array to the function as it decays to a pointer to the first element:

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

and invoked:

fillArray(someArray, blah);

The changes to the elements will be visible outside of the function.

If the actual code was to allocate an array within fillArray() then an int** would be required:

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];
    }
}

and invoked:

int* someArray = NULL;
fillArray(&someArray, blah);
free(someArray);
Sign up to request clarification or add additional context in comments.

1 Comment

It makes perfect sense why this works. However, if the array is already allocated, why exactly does passing &someArray into fillArray() and accessing the array itself by *someArray lead to a segmentation fault?
1

When you create an array, such as int myArray[10][20], a guaranteed contiguous block of memory is allocated from the stack, and normal array arithmetic is used to find any given element in the array.

If you want to allocate that 3D "array" from the heap, you use malloc() and get some memory back. That memory is "dumb". It's just a chunk of memory, which should be thought of as a vector. None of the navigational logic attendant with an array comes with that, which means you must find another way to navigate your desired 3D array.

Since your call to malloc() returns a pointer, the first variable you need is a pointer to hold the vector of int* s you're going to need to hold some actual integer data IE:

int *pArray;

...but this still isn't the storage you want to store integers. What you have is an array of pointers, currently pointing to nothing. To get storage for your data, you need to call malloc() 10 times, with each malloc() allocating space for 20 integers on each call, whose return pointers will be stored in the *pArray vector of pointers. This means that

int *pArray

needs to be changed to

int **pArray

to correctly indicate that it is a pointer to the base of a vector of pointers.

The first dereferencing, *pArray[i], lands you somewhere in an array of int pointers, and the 2nd dereferencing, *p[i][j], lands you somewhere inside an array of ints, pointed to by an int pointer in pArray[i].

IE: you have a cloud of integer vectors scattered all over the heap, pointed to by an array of pointers keeping track of their locations. Not at all similar to Array[10][20] allocated statically from the stack, which is all contiguous storage, and doesn't have a single pointer in it anywhere.

As others have eluded to, the pointer-based heap method doesn't seem to have a lot going for it at first glance, but turns out to be massively superior.

1st, and foremost, you can free() or realloc() to resize heap memory whenever you want, and it doesn't go out of scope when the function returns. More importantly, experienced C coders arrange their functions to operate on vectors where possible, where 1 level of indirection is removed in the function call. Finally, for large arrays, relative to available memory, and especially on large, shared machines, the large chunks of contiguous memory are often not available, and are not friendly to other programs that need memory to operate. Code with large static arrays, allocated on the stack, are maintenance nightmares.

Here you can see that the table is just a shell collecting vector pointers returned from vector operations, where everything interesting happens at the vector level, or element level. In this particular case, the vector code in VecRand() is calloc()ing it's own storage and returning calloc()'s return pointer to TblRand(), but TblRand has the flexibility to allocate VecRand()'s storage as well, just by replacing the NULL argument to VecRand() with a call to calloc()

/*-------------------------------------------------------------------------------------*/
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;
}

Comments

0

There is no "array/pointer" equivalence, and arrays and pointers are very different. Never confuse them. someArray is an array. &someArray is a pointer to an array, and has type int (*)[MAX]. The function takes a pointer to a pointer, i.e. int **, which needs to point to a pointer variable somewhere in memory. There is no pointer variable anywhere in your code. What could it possibly point to?

An array value can implicitly degrade into a pointer rvalue for its first element in certain expressions. Something that requires an lvalue like taking the address (&) obviously does not work this way. Here are some differences between array types and pointer types:

  • Array types cannot be assigned or passed. Pointer types can
  • Pointer to array and pointer to pointer are different types
  • Array of arrays and array of pointers are different types
  • The sizeof of an array type is the length times the size of the component type; the sizeof of a pointer is just the size of a pointer

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.