What is wrong with my dynamically allocated array of pointers to structs? - c

I have the following program that references array elements through a double pointer.
typedef struct {
int num1;
int num2;
int num3;
} DATA_SET;
typedef struct {
int structID;
DATA_SET *data_set_array; // Pointer to an array of DATA_SET structs
} MY_STRUCT;
int main () {
MY_STRUCT *Struct1;
DATA_SET **DataSetArray; // Array of pointers
Struct1 = malloc(sizeof(MY_STRUCT));
Struct1->data_set_array = malloc(sizeof(DATA_SET*)) //Allocate mem for the pointer to array of DATA_SETs
DataSetArray = malloc(sizeof(DATA_SET*) * 2) // Allocate mem for an array of 2 DATA_SET pointers
DataSetArray[0] = malloc(sizeof(DATA_SET)) // Allocate mem for the actual DATA_SET struct
DataSetArray[0]->num1 = 1;
DataSetArray[0]->num2 = 2;
DataSetArray[0]->num3 = 3;
DataSetArray[1] = malloc(sizeof(DATA_SET)) // Allocate mem for the actual DATA_SET struct
DataSetArray[1]->num1 = 1;
DataSetArray[1]->num2 = 2;
DataSetArray[1]->num3 = 3;
memcpy(Struct1->data_set_array, *DataSetArray, sizeof(DATA_SET*); //Copy data set array into Struct1
When I print all the data out in Struct1, i get:
Struct1->data_set_array[0].num1 = 1
Struct1->data_set_array[0].num2 = 2
Struct1->data_set_array[0].num3 = 3
Struct1->data_set_array[1].num1 = 50 //This should be 1
Struct1->data_set_array[1].num2 = 50 //This should be 2
Struct1->data_set_array[1].num3 = 65 //This should be 3
Seems to be misuse/data corruption for the 2nd element in the array.
I know there's probably different ways to do this, but I wanted to get familiar with referencing the array indices via double pointers. Am I allocating memory properly? I have a feeling the memcpy is incorrect.

Struct1->data_set_array = malloc(sizeof(DATA_SET*)
/* ^ wrong */
DataSetArray = malloc(sizeof(DATA_SET*) * 2)
/* ^ wrong */
You need to do sizeof(DATA_SET) because that is the actual size of a struct, not a pointer to a DATA_SET struct.
You're making the mistake of allocating only the size of a pointer times 2, which in many cases can be smaller than you'd hope for.
memcpy(Struct1->data_set_array, *DataSetArray, sizeof(DATA_SET*);
This is also wrong. You must copy the sizeof(DATA_SET). Keep in mind that sizeof(DATA_SET) is not equal to sizeof(DATA_SET*). A pointer's size in bytes is the same regardless of the type of pointer.

What is wrong with my dynamically allocated array of pointers to structs?
DataSetArray is an array of pointers to struct and there is not anything wrong with it.
The problem is 2 other things:
You can't use memcpy on an array of pointers to struct. The memory isn't consecutive.
Further, data_set_array is not an array of pointers to struct so you are trying to copy between incompatible types.

I guess you basically want to create a Double Dimension array. So basically you can do the code like this
struct abc {
int i;
};
struct abc **arr;
arr = (struct abc **) malloc(sizeof(struct abc) * 2);
arr[0] = (struct abc*)malloc(sizeof(struct abc));
arr[0]->i = 100;
arr[1] = (struct abc*)malloc(sizeof(struct abc));
arr[1]->i = 200;
One thing that you need to remember is that the outer array is just a pointer, so it doesn't need to be sizeof(abc) , it could very well be sizeof(int*) / sizeof (void*) etc.
so basically the above code could be written as
struct abc **arr;
arr = (struct abc **) malloc(sizeof(int *) * 2);
arr[0] = (struct abc*)malloc(sizeof(struct abc));
arr[0]->i = 100;
arr[1] = (struct abc*)malloc(sizeof(struct abc));
arr[1]->i = 200;
Hope this helps in underlying memory management you want to do with your code

Related

Problem with setting the array of pointers in the struct using malloc

I want to allocate a memory to an array of pointers in struct, but I receive the following error:
expression must be a modifiable lvalue
Here's struct code:
typedef struct {
int id;
char *entity[];
}entity;
Here's memory allocation in main function:
entity s;
s.entity= malloc(30 * sizeof(char *));
IDE underlines s.entity and pops the error I mentioned.
Please, help me out to solve this issue.
Your structure does not have a member called entity, only id and set.
You apparently want to allocate the whole structure. This type of struct member called flexible array member is useful if you want to allocate the whole structure in one malloc.
entity *s;
s = malloc(sizeof(*s) + 30 * sizeof(s -> set[0]));
This kind of struct members are very useful as you can realloc or free them in a single call.
Increase the size of the set array to 50
entity *tmp = realloc(s, sizeof(*s) + 50 * sizeof(s -> set[0]));
if(tmp) s = tmp;
Thats how you would allocate the pointers:
typedef struct {
int id;
char **set;
}entity;
int how_many_pointers = 30;
entity s;
s.set= malloc(how_many_pointers * sizeof(char *));
And for each pointer you would have to allocate the space for the corresponding string:
int i, string_size;
for(i = 0; i < how_many_pointers; i++)
{
printf("How many chars should have string number %d ?", i + 1);
scanf("%d", &string_size);
s.set[i] = malloc((string_size + 1) * sizeof(char)); // string + 1 due to space for '\0'
}

Garbage value even after initializing members of dynamically allocated struct array

I have a dynamically allocated array of structures, 'buff'. Each element is a structure that has a few integer variables and a pointer 'buffer_ptr' which points to another dynamically allocated array of structures. The size of both arrays is given as command line input.
int buffer_size;
int user_num;
struct tuple
{
char userID[5];
char topic[16];
int weight;
};
struct buff_ctrl
{
struct tuple* buffer_ptr;
int in;
int out;
int numItems;
int done;
};
The arrays are created and initialized in main() as follows:
int main(int argc, char* argv[])
{
void *status;
pthread_t mapThd;
if(argc != 4)
{
printf("Input format: ./combiner <buffer_size> <number_of_users> <input_file>\n");
return -1;
}
buffer_size = atoi(argv[1]);
user_num = atoi(argv[2]);
struct buff_ctrl *buff = (struct buff_ctrl*)malloc(user_num * sizeof(struct buff_ctrl));
for(int i=0; i<user_num; i++)
{
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
struct tuple *ptr = (struct tuple*)malloc(buffer_size * sizeof(struct tuple));
curr_buff->buffer_ptr = ptr;//points to another array
curr_buff->in = 8;
curr_buff->out = 4;
curr_buff->numItems = 7;
curr_buff->done = 0;
printf("%p\n",curr_buff);
}
Then, I need to pass the 'buff' pointer as an argument when creating thread using pthread_create:
pthread_create(&mapThd, NULL, mapper, (void*)buff);
pthread_join(mapThd, &status);
free(buff);
/*end of main*/
My function pointer is as follows:
void* mapper(void *buff)
{
struct buff_ctrl* arr = (struct buff_ctrl *)buff;
struct buff_ctrl* temp_ptr;
printf("######################################################\n");
for(int k=0; k<user_num; k++)
{
/*Printing just to check values */
temp_ptr = arr + (k*sizeof(struct buff_ctrl));
printf("buffer ptr = %p\n", temp_ptr->buffer_ptr);
printf("in = %d\n", temp_ptr->in);
printf("out = %d\n", temp_ptr->out);
printf("numItems = %d\n", temp_ptr->numItems);
}
printf("######################################################\n");
pthread_exit((void*)buff);
}
But, when I print the values of 'buffer_ptr' from the created thread (only one), for ODD number of user_num, there is always ONE element of the array 'buff' which gives garbage value after pthread_create statement! When the values are checked in main itself after removing calls to pthread, it runs fine.
This line
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
should be
struct buff_ctrl* curr_buff = buff + i;
buff + i is pointer arithmetic and the compiler already takes the size of the
object pointed to by buff into consideration. By doing i*sizeof(struct buff_ctrl) you are assigning
a pointer that may be after the allocated memory.
As general suggestion:
Don't cast malloc. And instead of using sizeof(<type>), use sizeof *variable, this is more safe, because
it's easier to make mistakes when writing sizeof(<type>).
So:
struct buff_ctrl *buff = malloc(user_num * sizeof *buff);
...
struct tuple *ptr = malloc(buffer_size * sizeof *ptr);
And you don't need to declare a separate pointer, you can do:
for(int i=0; i<user_num; i++)
{
buff[i].buffer_ptr = malloc(buffer_size * sizeof *buff[i].buffer_ptr);
buff[i].in = 8;
buff[i].out = 4;
buff[i].numItems = 7;
buff[i].done = 0;
}
Also you should always check for the return value of malloc. If it returns
NULL, you cannot access that memory.
This is wrong:
struct buff_ctrl* curr_buff = (buff + (i*sizeof(struct buff_ctrl)));
When you do pointer arithmetic, it operates in units of the size of what the pointer points to, so you don't need to multiply by sizeof. As a result, you're effectively multiplying twice and accessing outside the array bounds.
Just treat buff as an array, rather than dealing with pointers.
for(int i=0; i<user_num; i++)
{
struct tuple *ptr = malloc(buffer_size * sizeof(struct tuple));
buff[i].buffer_ptr = ptr;//points to another array
buff[i].in = 8;
buff[i].out = 4;
buff[i].numItems = 7;
buff[i].done = 0;
}
Also, see Do I cast the result of malloc?
You have a fundamental error.
Pointer arithmetics works by adding the offset in multiples of the pointer type, so adding the offset yourself will not work as you apparently expect it to.
If it was a char * pointer then you would need to add the offset manually, increments would be multiplied by one. But in your case increments by n are multiplied by the size of the pointer base type.
There are times when doing pointer arithmetics with the addition notation makes sense, but most of the time it's much clearer to write index notation instead.

How can I initialize and dynamically allocate an int pointer member in an array of structs?

How can I initialize and dynamically allocate an int pointer that is in an array of structs?
My program allows me to print enroll[0].grades[x], but when I try to access any other index value of enroll other than 0 (such as enroll[1].grades[x] or enroll[2].grades[x]), my program segmentation faults.
Here's my code...
How can I make enroll[2].grades[x], for example, initialize and equal zero?
In my struct:
struct Enroll
{
int *grades;
};
In main:
struct Enroll *enroll = (struct Enroll *) calloc(count.enroll, 10 * sizeof(struct Enroll));
enroll->grades = (int *) calloc(count.grades, 10 * sizeof(int));
In functions:
enroll[x].grades[y];
Allocate memory for number of struct Enrollements
struct Enroll *p = calloc(count.enroll, sizeof(struct Enroll));
Now you have the number of structures to be filled in and what you need is memory for the int pointer to hold values and the number of int pointers is count.enroll
for(i=0;i<count.enroll;i++)
{
p[i].grades = calloc(count.grades,sizeof(int));
// Fill in the values
}
PS: Alternatively you can go for malloc() followed by memset()
In main you should have
struct Enroll *enroll = calloc(count.enroll, sizeof(struct Enroll));
for(int i = 0; i < count.enroll ;i++)
{
enroll[i].grades = calloc(count.grades, sizeof(int));
}
In your code you have not allocated memory for each integer pointer.

Difference between pointers when malloc

I usually make myself a struct and I allocate memory for the struct and sometimes for buffers inside the struct. Like so:
typedef struct A
{
char *buffer;
int size;
} A;
Then when I malloc for the struct I do this. (I learned not to cast the malloc return here on SO.)
X
A *a = malloc(sizeof(a));
a->buffer = malloc(10*sizeof(a->buffer));
What is the difference between X and Y this?
Y
A *a = malloc(sizeof(*a));
a->buffer = malloc(10*sizeof(a->buffer));
They seem to be doing the same thing.
Neither is correct, the second one doesn't even compile.
You want either of these:
A * a = malloc(sizeof(A)); // repeat the type
// or:
A * a = malloc(sizeof *a); // be smart
Then:
a->size = 213;
a->buffer = malloc(a->size);
you should typecast it (A *) because calloc or malloc return void *.
A *a=(a*)malloc(sizeof(A));
suppose you want to allocate memory for buffer for 10 characters
a->buffer=(char *)malloc(sizeof(char)*10);

Modifying a structure array through a pointer passed to a function

I am trying to pass a structure array pointer and a pointer to a structure array pointer into a function and then have it modified rather than using a return.
This example code is indeed pointless, its just a learning example for me.
Basically I want to create array[0]...array[1]..array[2] and so on and have a pointer that points to these while using a different index...such as array_ref[2] points to array[0] and array_ref[3] points to array[1].
The code below compiles, but immediately crashes. Any suggestions?
typedef struct unit_class_struct {
char *name;
char *last_name;
} person;
int setName(person * array, person ***array_ref) {
array[0].name = strdup("Bob");
array[1].name = strdup("Joseph");
array[0].last_name = strdup("Robert");
array[1].last_name = strdup("Clark");
*array_ref[2] = &array[0];
*array_ref[3] = &array[1];
return 1;
}
int main()
{
person *array;
person **array_r;
array = calloc (5, sizeof(person));
array_r = calloc (5, sizeof(person));
setName(array,&array_r);
printf("First name is %s %s\n", array_r[2]->name, array_r[2]->last_name);
printf("Second name is %s %s\n", array_r[3]->name, array_r[3]->last_name);
return 0;
}
You are allocating an array of structures but declaring an array of pointers.
Calloc() and malloc() return a void * object that can be assigned to everything. So, even with -Wall your program will compile with no warnings.
However, when it runs, it tries to deal with what you said was an array of pointers, in fact, an array of pointers to pointers to pointers. None of these pointers are ever created. All you start with are one-level pointers to an array of objects. Depending on what you really want, you may need something more like...
array_ref[2] = &array[0];
array_ref[3] = &array[1];
return 1;
}
int main()
{
person *array, *array_r_real;
person **array_r;
array = calloc(5, sizeof(person));
array_r_real = calloc(5, sizeof(person));
array_r = calloc(5, sizeof(struct unit_class_struct *));
int i;
for (i = 0; i < 5; ++i)
array_r[i] = &array_r_real[i];
setName(array, array_r);

Resources