Is it possible to have an array of multiple types by using malloc
?
EDIT:
Currently I have:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define int(x) *((int *) x)
int main() {
void *a[10];
a[0] = malloc(sizeof(int));
int(a[0]) = 4;
char *b = "yola.";
a[1] = malloc(strlen(b)*sizeof(char));
a[1] = b;
printf("%d\n", int(a[0]));
printf("%s\n", a[1]);
}
But it's messy. Other ways?
EDIT: Cleaned it up a bit.
No, we cannot store multiple datatype in an Array, we can store similar datatype only in an Array.
Consider this example: int *ptr; int arr[5]; // store the address of the first // element of arr in ptr ptr = arr; Here, ptr is a pointer variable while arr is an int array. The code ptr = arr; stores the address of the first element of the array in variable ptr .
To declare a pointer to an array type, you must use parentheses, as the following example illustrates: int (* arrPtr)[10] = NULL; // A pointer to an array of // ten elements with type int. Without the parentheses, the declaration int * arrPtr[10]; would define arrPtr as an array of 10 pointers to int.
When we allocate memory to a variable, pointer points to the address of the variable. Unary operator ( * ) is used to declare a variable and it returns the address of the allocated memory. Pointers to an array points the address of memory block of an array variable.
You can't have an array of different types, exactly. But you can achieve a similar effect (for some purposes at least) in a number of different ways.
If you just want a few values of different types packaged together, but the number and types of values don't change, you just need a struct
and can access them by name:
struct s_item {
int number;
char str[100];
} item;
item.number = 5;
strcpy(item.str,"String less than 100 chars");
If you know what types you might use, you can create a union, or a struct containing a union so you can tag it with the type. You can then create an array of those. The type
member lets you check to see what you stored in each array element later.
enum ElementType { et_str, et_int, et_dbl };
struct Element {
ElementType type;
union {
char *str;
int i;
double d;
}
};
struct Element *arr = malloc(sizeof(struct Element) * 3);
arr[0].type = et_str;
arr[0].str = strdup("String value"); /* remember to free arr[0].str */
arr[1].type = et_int;
arr[1].i = 5;
arr[2].type = et_dbl;
arr[2].d = 27.3;
/* access the values.. */
for (int i = 0; i < 3; i++) {
switch(arr[i].type) {
case et_str: printf("String: %s\n",arr[i].str); break;
case et_int: printf("Integer: %d\n",arr[i].i); break;
case et_dbl: printf("Double: %f\n",arr[i].d); break;
}
}
/* The strings are dynamically allocated, so free the strings */
for (int i = 0; i < 3; i++)
if (arr[0].type == et_str) free(arr[0].str);
/* free the malloc'ed array */
free(arr);
/* etc., etc. */
This approach may waste space because:
If you have another way of knowing what type you've stored in each element, you can use just the bare union without the struct wrapping it. This is a little more compact, but each element will still be at least as large as the largest type in the union.
You can also create an array of void *
values. If you do this, you'll have to allocate the items somehow and assign their addresses to the array elements. Then you'll need to cast them to the appropriate pointer type to access the items. C doesn't provide any runtime type information, so there's no way to find out what type of data each element points at from the pointer itself -- you must keep track of that on your own. This approach is a lot more compact than the others when the types you're storing are large and their sizes vary a lot, since each is allocated separately from the array and can be given only the space needed for that type. For simple types, you don't really gain anything over using a union.
void **arr = malloc(3 * sizeof(void *));
arr[0] = strdup("Some string"); /* is a pointer already */
arr[1] = malloc(sizeof(int));
*((int *)(arr[1])) = 5;
arr[2] = malloc(sizeof(double));
*((double *)(arr[2])) = 27.3;
/* access the values.. */
printf( "String: %s\n", (char *)(arr[0]) );
printf( "Integer: %d\n", *((int *)(arr[1])) );
printf( "Double: %f\n", *((double *)(arr[2])) );
/* ALL values were dynamically allocated, so we free every one */
for (int i = 0; i < 3; i++)
free(arr[i]);
/* free the malloc'ed array */
free(arr);
If you need to keep track of the type in the array, you can also use a struct to store the type along with the pointer, similar to the earlier example with the union. This, again, is only really useful when the types being stored are large and vary a lot in size.
enum ElementType { et_str, et_int, et_dbl };
struct Element {
ElementType type;
void *data;
};
struct Element *arr = malloc(sizeof(struct Element) * 3);
arr[0].type = et_str;
arr[0].data = strdup("String value");
arr[1].type = et_int;
arr[1].data = malloc(sizeof(int));
*((int *)(arr[1].data)) = 5;
arr[2].type = et_dbl;
arr[2].data = malloc(sizeof(double));
*((double *)(arr[2].data)) = 27.3;
/* access the values.. */
for (int i = 0; i < 3; i++) {
switch(arr[i].type) {
case et_str: printf( "String: %s\n", (char *)(arr[0].data) ); break;
case et_int: printf( "Integer: %d\n", *((int *)(arr[1].data)) ); break;
case et_dbl: printf( "Double: %f\n", *((double *)(arr[2].data)) ); break;
}
}
/* again, ALL data was dynamically allocated, so free each item's data */
for (int i = 0; i < 3; i++)
free(arr[i].data);
/* then free the malloc'ed array */
free(arr);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With