Question

I came to C from Python. Python has a delightfully simplistic white glove approach to manipulating strings. The more I use arrays in C, the more I think how convenient it would be to have certain features. Rather than writing loops to do this every time I need to do a particular operation, I have decided to create a library to do this.

So, let's say I have a library and the call looks something like this:

char* new_array = meatSlicer(old_array, element_start);

I'm passing the pointer to the array I want changed, expecting a pointer return, and indicating what element to slice at.

If meatSlicer (yes, I'm a sucker for bad naming) returns a pointer to an array that is made locally within the slicer, the pointer will be a bad pointer. So, within meatSlicer() I have this:

    ... manipulation before the below ...

    char *heap_the_Array;     /* put it on the heap to pass it back to caller */
    heap_the_Array = malloc((size + 1) * sizeof(char));

    int i;                
    for (i = 0; i <= (size + 1); i++){           /* make it so... again */

            heap_the_Array[i] = newArray[i];     /* newArray is the local */

    }

    return heap_the_Array;                       /* return pointer */

My question is, am I properly returning ownership to the caller function so that it can free() the new array? Is passing a pointer to an array on the heap sufficient for that?

Was it helpful?

Solution

Yes, copying local variables into malloc-ed regions of memory works well. You can replace the loop with a call of memcpy to reduce the code size. Write

memcpy(heap_the_Array, newArray, size+1);

instead of

int i;                
for (i = 0; i <= (size + 1); i++){           /* make it so... again */
        heap_the_Array[i] = newArray[i];     /* newArray is the local */
}

OTHER TIPS

Yes, you are properly transferring ownership to the caller function. This approach to ownership is not frequently used by C programmers, but it happens sometimes (strdup and GNUish asprintf are widely-known examples).

You can also work with a heap-allocated array from the very start, eliminating the need for copying.

As of copying itself, by the way, there is a bug in your code: the body of for (i = 0; i <= (size + 1); i++) is invoked size+2 times. Using memcpy with the size argument, as hinted by another answer, is indeed less error-prone than doing it yourself.

And the last thing: sizeof(char) is always 1 in ANSI C, please don't multiply by it.

Yes, your meatSlicer is done with heap_the_Array, it belongs now to the caller. So the caller is the only one now who can (and has to) delete that array, unless he passes ownership to somebody else. This ownership idea is something which has to be defined somehow by you, and you have to be consistent with it in order to avoid trouble and avoid beeing sliced by the memory-leak-monster.

It has been clearly explained how the ownership is transferred. However, I would like to propose a "more traditional" approach. Your code looks very much like something I would happily do in Python - but C is not Python (and Python is not C!), part of learning a new language is learning "how things are done in that language". There is a tendency for programmers that are just learning C to jump at calling malloc here there and everywhere. Try to NOT do that.

Instead of letting the function allocate an array, pass in an array in your calling code, that has space for the things you want to copy. Then return how many lements you actually got, for example something like this:

 TYPE new_array[some_size];
 int max_size = sizeof(new_array) / sizeof(new_array[0]);
 int actual_size;

 actual_size = meatSlicer(old_array, new_array, element_start, max_size);

If you want to use malloc to create new_array, then you can of course do so:

 TYPE new_array = malloc(some_size * sizeof(TYPE));
 int max_size = some_size;
 int actual_size;

 if (new_array == NULL) panic();    // Do something useful here. 

 actual_size = meatSlicer(old_array, new_array, element_start, max_size);

 ... 

 free(new_array);

I much prefer to use arrays of fixed size, as there is less overhead, and less need to "remember to free later" - the latter is a common problem in code, especially when the code gets a bit more complicated and there are several call levels involved - and if you allocate several items in one function, you need to remember to clean up the first ones if a later allocation fails, for example. Makes life complicated...

Yes, only stack allocated variables are automatically "freed" when a function returns, and you have correctly allocated an array on the heap, and correctly returned a pointer to it.

Specifically, the pointer variable heap_the_Array is allocated on the stack, and a copy of that value will be returned.

Although you can return a pointer to heap allocated object, it does not mean you can forget NULL terminating the character array :).

It will work, just don't forget to add the trailing '\0' to the mix and don't forget to free() the char array once done with.

Assuming your arrays are strings, you can replace your buggy code with a single line.

return strdup(newArray);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top