Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do one line assignment to malloc() arrays in C?

In C I can initialize an array on the stack like so:

SOME_DATA_TYPE* x = (SOME_DATA_TYPE[5]) {v1, v2, v3, v4, v5};

Is there a similar one-line method to assign values to a malloc()-ed array on the heap?

SOME_DATA_TYPE* y = malloc(sizeof(SOME_DATA_TYPE)*5);  
// what comes here?  

Or do I have to iterate over the array and assign values individually?

like image 830
hazrmard Avatar asked Jul 27 '16 19:07

hazrmard


3 Answers

The first issue about "initializing" the result of malloc() is that the allocation may fail. Here y is initialized to some pointer value. The data referenced is still indeterminate.

#define  element_count  5
SOME_DATA_TYPE *y = malloc(sizeof *y * element_count);
if (y == NULL) Handle_OutOfMemory();

With C11, code can use compound literals to set, not initialize, the data pointed to by y.

memcpy(y, (SOME_DATA_TYPE[element_count]) {v1, v2, v3, v4, v5}, sizeof *y * element_count);

Using a direct one-liner without checking the allocation would not be robust programming.

// one-liner, but not robust code
SOME_DATA_TYPE *y = memcpy(malloc(sizeof *y * element_count), 
    (SOME_DATA_TYPE[element_count]) {v1, v2, v3, v4, v5}, sizeof *y * element_count);

Notice code uses the sizeof *pointer_variable * element_count rather than sizeof (pointer_variable_dereferenced_type) * element_count as easier to code, less error prone, easier to review and maintain. Either approach will work.

like image 55
chux - Reinstate Monica Avatar answered Sep 22 '22 09:09

chux - Reinstate Monica


You could define a function like so:

#include <stdarg.h>
#include <stdlib.h>

int * intMallocInit (int length, ...) {
   // Initialize Variable Arguments
   va_list args;
   va_start (args, length); 

    // Allocate Memory
    int * arr = malloc (sizeof(int) * length);
    if (arr == NULL) return NULL;

    // Initialize Array
    for (int i = 0; i < length; i++) {
        arr[i] = va_arg(args, int);
    }

    // Clean Up and Return
    va_end(args)
    return arr;
}

And we could call it like so:

int len = 3;
int * myArray = intMallocInit (len, 4, 5, 2);
if (myArray == NULL) return 0; 

for (int i = 0; i < len; i++) {
    printf("%d,", myArray [i]);
}

Output: 4,5,2,

Note: We could also define floatMallocInit (), etc. simply by replacing every instance of "int" in the above function to "float"

You could also use void pointers, or enum& switch, but I wont go there.

Untested attempt at general function Im sure theres a clever work around fhe switchs but this is what I can come up with.

#include <stdarg.h>
#include <stdlib.h>
enum {INT, FLOAT /* etc...*/}

 int getSize(int type) {
     int typeSize = 0;
     switch (type) {
        case INT: 
             typeSize = sizeof (int);
             break;
        case FLOAT:
             typeSize = sizeof (float);
             break;
        // Etc...
        default:
             return -1;
    }
    return typeSize;
 }


void * mallocInit (int type, int length, ...) {
   // Initialize Variable Arguments
   va_list args;
   va_start (args, length); 

    // Get Size of type
    int typeSize = getSize(type);
    if (typeSize == -1) return NULL;

    // Allocate Memory
    void * arr = malloc (typeSize * length);
    if (arr == NULL) return NULL;

    // Initialize Array, Maybe va_copy can be used? No good reference
    for (int i = 0; i < length; i++) {
         switch(type) {
            case INT:
             arr[i] = va_args(args, int);
             break;
            // Etc..
        }
    }

    // Clean Up and Return
    va_end(args)
    return arr;
}

Called with

float myArray = mallocInit (FLOAT, 3, 1, 5, 7);
like image 36
Nawar Ismail Avatar answered Sep 22 '22 09:09

Nawar Ismail


One way to do it without getting too far away from the natural C memory management philosophy, is to use a memdup-like function. Since it is not standard, you might have to implement it yourself

SOME_DATA_TYPE *y = memdup(
  (SOME_DATA_TYPE[5]) {v1, v2, v3, v4, v5},
  5 * sizeof(SOME_DATA_TYPE)); 
like image 34
AnT Avatar answered Sep 22 '22 09:09

AnT