Using malloc to create and pass array as function

Viewed 279

I'm trying to learn how to use C (from C#) and malloc has been one of the things giving me trouble when it comes to arrays. I have a pretty simple function to take an array sorted in non-descending { -1, 0, 1, 2, 3} ) order, and its size, square each value, and sort it in ascending order based on the squared values.

/// <param name="nums">integer array nums</param>
/// <param name="size">Size of array</param>
/// <returns>Sorted and squared array</returns>
int *sortedSquaredArray(int* nums, int size)
{
    //Starting from both ends of the array, square and do a semi-merge sort
    int *sortedArray = (int *)malloc(size * sizeof(int));

    int startIdx = 0;
    int endIdx = size - 1;
    int cnt = size - 1;
    int a;
    int b;
    int c;

    while (startIdx < endIdx)
    {
        a = nums[startIdx] * nums[startIdx];
        b = nums[endIdx] * nums[endIdx];

        if (a >= b)
        {
            sortedArray[cnt] = a;
            startIdx += 1;
        }
        else
        {
            sortedArray[cnt] = b;
            endIdx += 1;
        }
        cnt -= 1;
    }

    //final loop
    c = nums[startIdx] * nums[startIdx];
    sortedArray[0] = c;


    return sortedArray;

When I pass the array back and try to print it (I'm in the console on Visual Studio) only the final value is set correctly in the sortedArray, which makes me think I'm writing to totally the wrong memory addresses, but I'm not sure why. I'm also not really clear when, if you pass the pointer back to another function, to free up the used memory from malloc.

/// Run the sortedSquaredArray test
/// </summary>
void runSortedSquaredArrayTest()
{
    int nums1[] = { -4, -1, 0, 3, 10 };

    int *res = sortedSquaredArray(nums1, 5);
    printf("val1 %d, val2 %d, val3 %d, val4 %d, val5 %d", res[0], res[1], res[2], res[3], res[4]);
    
}

I feel like an idiot for taking something as neat as being able to actually manually allocate the memory and making such a mess of it :/

3 Answers

The line

endIdx += 1;

looks wrong because it will lead to out-of-range access.

Try using

endIdx -= 1;

or

endIdx += -1;

instead.

As MikeCAT mentioned, endIdx should be going down instead of up when you pull values off the end.

Your "semi-merge sort" is also a bit dubious. Consider the array:

{ 2, 3, 1 }

Your algorithm will start by comparing the start and the end. 2 > 1, so it will place 2 at the end. Only after this will it look at 3. This will end up as:

{ 1, 3, 2 }

I'm also not really clear when, if you pass the pointer back to another function, to free up the used memory from malloc.

As implemented, your function allocates memory and creates an obligation for the caller to free it when they are done using it. This is similar to how calling "open" creates an obligation to the caller to later call "close". To address this, your runSortedSquaredArrayTest function should end with free(res);. An alternative way to implement this is to have the caller provide the memory they want the output placed in. When called, this could look like:

void sortedSquaredArray(int length, int* input, int* output) {...}
void runSortedSquaredArrayTest()
{
    int input[] = { -4, -1, 0, 3, 10 };
    int output[] = { 0, 0, 0, 0, 0 };

    sortedSquaredArray(5, input, output);
    printf("val1 %d, val2 %d, val3 %d, val4 %d, val5 %d", output[0], output[1], output[2], output[3], output[4]);
    
}

With this approach the caller doesn't need to free anything.

the following proposed code:

  1. cleanly compiles
  2. performs the desired functionality
  3. only uses standard C header files

and now the proposed code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//from: https://www.programmingsimplified.com/c/source-code/c-program-bubble-sort
void bubbleSort( int *array, size_t n )
{
    for ( size_t c = 0 ; c < n - 1; c++)
    {
        for (size_t d = 0 ; d < n - c - 1; d++)
        {
            if (array[d] > array[d+1]) /* For decreasing order use '<' instead of '>' */
            {
                int swap       = array[d];
                array[d]   = array[d+1];
                array[d+1] = swap;
            }
        }
    }
}


/// <param name="nums">integer array nums</param>
/// <param name="size">Size of array</param>
/// <returns>Sorted and squared array</returns>
int *sortedSquaredArray( int* nums, size_t size )
{
    int *sortedArray = malloc(size * sizeof(int));
    
    if( ! sortedArray )
    { 
        return NULL;
    }

    memcpy( sortedArray, nums, size*sizeof(int) );
    
    bubbleSort( sortedArray, size );
    
    for( size_t i = 0; i<size; i++ )
    {
        sortedArray[i] *= sortedArray[i];
    }

    return sortedArray;
}


/// Run the sortedSquaredArray test
/// </summary>
void runSortedSquaredArrayTest( void )
{
    int nums1[] = { -4, -1, 0, 3, 10 };

    int *res = sortedSquaredArray(nums1, sizeof(nums) / sizeof( int ));
    if( res )
    {
        printf("val1 %d, val2 %d, val3 %d, val4 %d, val5 %d", 
                res[0], res[1], res[2], res[3], res[4]);
        free( res );
    }
}


int main( void )
{
    runSortedSquaredArrayTest();
}

a typical run of the program results in:

val1 16, val2 1, val3 0, val4 9, val5 100
Related