Here is what I am trying to do:
1. Create an array of struct pointers.
2. Fill the array with malloc'd structs.
3. Then replace one element in the array with a new malloc'd struct
4. Have no memory leaks.
I have written a test program below, but I am getting seg faults due to invalid reads and writes on my call to memcpy. What am I doing wrong?
#include <stdlib.h>
#include <string.h>
struct my_struct {
int a;
int b;
};
int main(int argc, char *argv[])
{
struct my_struct **my_arr;
my_arr = (struct my_struct **) malloc(10 * sizeof(struct my_struct *));
int i;
for (i = 0; i < 10; i++) {
struct my_struct *my_str = (struct my_struct *) malloc(sizeof(struct my_struct *));
my_arr[i] = my_str;
}
free(my_arr[0]);
memcpy(my_arr[0], my_arr[1], sizeof(struct my_struct *) * 9);
my_arr[9] = (struct my_struct *) malloc(sizeof(struct my_struct *));
for (i = 0; i < 10; ++i) {
free(my_arr[i]);
}
free(my_arr);
}
free(my_arr[0]);
memcpy(my_arr[0], my_arr[1], sizeof(struct my_struct *) * 9);
This is problem , you first free(my_arr[0]) and then copy my_arr[1] at address it points to .
You are not supposed to access memory after freeing it .
And also specified in manpage
[...]The memory areas must not overlap. Use memmove if the
memory areas do overlap.
again you do this -
my_arr[9] = (struct my_struct *) malloc(sizeof(struct my_struct *));
thus , loosing reference to previous memory block it was pointing to .
This code works and I cleaned it up a bit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct my_struct {
int a;
int b;
};
int main(){
const int structsz=sizeof(struct my_struct);
struct my_struct **my_arr=malloc(10 * structsz);
int i;
printf("Before\n");
for (i = 0; i < 10; i++){
my_arr[i]=malloc(structsz);
my_arr[i]->a=20+i;
my_arr[i]->b=10+i;
printf("i=%d a=%d, b=%d\n",i,my_arr[i]->a,my_arr[i]->b);
}
free(my_arr[9]);
my_arr[9]=malloc(structsz);
memcpy(my_arr[9], my_arr[1], structsz); //make 1st struct in array equal the 9th
free(my_arr[8]);
my_arr[8]=malloc(structsz);
memcpy(my_arr[8], my_arr[2], structsz); //make 2st struct in array equal the 8th
printf("After\n");
for (i = 0; i < 10; ++i) {
printf("i=%d a=%d, b=%d\n",i,my_arr[i]->a,my_arr[i]->b);
free(my_arr[i]);
}
free(my_arr);
return 0;
}
The reason why the third parameter of memcpy must be the same as the size of the structure is because both pointers in memcpy are the type of struct.
If the 3rd parameter is too large, then you can run into segmentation faults because you could try to copy memory that you're not allowed to access, or at best, you could be modifying other structs in your program.
If the 3rd parameter is too small, then you could receive invalid or insufficient data.
Related
I have an issue with pointers to struct that have members that are pointers to struct too.
Browsing the suggested similar questions I found out this:
Accessing elements within a pointer of a struct inside another pointer to a struct
where people suggest to pay attention to allocation memory of the structure.
I think this is done correctly in my code.
typedef struct {
int id_vec;
float *vec_value;
} Vector;
typedef struct cluster{
int id_cluster;
float *centroid;
Vector *patternInCluster;
} Cluster;
int main(void){
Cluster *cluster_ptr= malloc(3 * sizeof(Cluster));
if (cluster_ptr==NULL){
printf("NULL");
}
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector *));
if (cluster_ptr->patternInCluster==NULL){
printf("NULL");
cluster_ptr->patternInCluster=NULL;
}
float p1[3]={0.0f,1.0f,2.0f};
Vector *somePattern=malloc(2 * sizeof(Vector));
somePattern[0].id_vec=1;
somePattern[0].vec_value=p1;
somePattern[1].id_vec=2;
somePattern[1].vec_value=p1;
}
Then I expect that this statement works:
cluster_ptr[1].patternInCluster[1]=somePattern[1];
But it compiles and produces a Segmentation Fault.
Unexpectedly, the following statement doesn't get errors:
cluster_ptr[0].patternInCluster[1]=somePattern[1];
and a test show me correct result(somePattern[1] id and value)
I tried to debug with gdb but I only can see this:
Program received signal SIGSEGV, Segmentation fault.
0x00005555555547fe in main () at test_struct.c:36
36 cluster_ptr[1].patternInCluster[1]=somePattern[1];
Am I missing some allocation mistakes?
It's because you're not populating things fully.
This line
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector *));
is the same as saying
cluster_ptr[0].patternInCluster=malloc(2 * sizeof(Vector *));
and really given that cluster_ptr has been allocated as 3 Cluster it would be more clearer in your code to do the latter.
Since cluster_ptr[1].patternInCluster hasn't been given a value, trying to dereference it will lead to undefined behaviour but more likely will result in a segmentation fault.
You do not allocate enough memory:
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector *));
With patternInCluster being of type Vector *, you should allocate memory to hold elements of type Vector, not Vector*.
cluster_ptr->patternInCluster=malloc(2 * sizeof(Vector));
Your problem is NOT accessing the pointer inside the struct. Your problem is how you are using malloc().
When you have one pointer, you malloc only once:
int *pointer = (int* )malloc(sizeof(int));
*pointer = 1;
printf("*pointer:%d\n", *pointer);
When you have pointer-to-pointer, you malloc() once for the **pointer_to_pointer, but you also have to malloc() once for the *pointer_to_pointer:
int** pointer_to_pointer = (int** )malloc(sizeof(int*));
*pointer_to_pointer = (int* )malloc(sizeof(int));
**pointer_to_pointer = 2;
printf("**pointer:%d\n", **pointer_to_pointer);
And if you have more than one pointer, at the location pointed to by **pointer_to_pointer, you need a for loop to assign memory to every one of those *pointer_to_pointers.
for (unsigned int i = 0; i < 3; i++)
{
*(pointer_to_pointer + i*sizeof(int)) = (int* )malloc(sizeof(int));
}
**(pointer_to_pointer + sizeof(int)) = 3;
**(pointer_to_pointer + 2UL*sizeof(int)) = 4;
printf("**(pointer_to_pointer + sizeof(int):%d\n", **(pointer_to_pointer + sizeof(int)));
printf("**(pointer_to_pointer + 2UL*sizeof(int):%d\n", **(pointer_to_pointer + 2UL*sizeof(int)));
You are mistaken to think that Cluster *cluster_ptr= malloc(3 * sizeof(Cluster)); will automatically/magically assign memory for Cluster[0] and Cluster[1] and Cluster[2].
Your statement actually assigns memory only for Cluster[0], but big enough for 3 Clusters.
So the the modified code will look like this:
#include <string.h>
#include <stdio.h>
#include <malloc.h>
typedef struct {
int id_vec;
float *vec_value;
} Vector;
typedef struct cluster{
int id_cluster;
float *centroid;
Vector **patternInCluster;
} Cluster;
int main(void){
Cluster **cluster_ptr = (Cluster **)malloc(sizeof(Cluster*));
for (long unsigned int i = 0; i < 3; i++) {
cluster_ptr[i] = (Cluster *)malloc(sizeof(Cluster));
if (cluster_ptr[i]==NULL){
printf("NULL");
}
cluster_ptr[i]->patternInCluster = (Vector **) malloc(sizeof(Vector*));
for (long unsigned int j = 0; j < 3; j++) {
(*cluster_ptr)->patternInCluster[j] = (Vector *) malloc(sizeof(Vector));
if ((*cluster_ptr)->patternInCluster[j]==NULL){
printf("NULL");
(*cluster_ptr)->patternInCluster[j]=NULL;
}
}
}
float p1[3]={0.0f,1.0f,2.0f};
Vector *somePattern= (Vector *) malloc(sizeof(Vector));
somePattern[0].id_vec=1;
somePattern[0].vec_value=p1;
somePattern[1].id_vec=2;
somePattern[1].vec_value=p1;
cluster_ptr[1]->patternInCluster[1] = &somePattern[0];
cluster_ptr[0]->patternInCluster[1] = &somePattern[1];
cluster_ptr[1]->patternInCluster[0] = &somePattern[1];
cluster_ptr[2]->patternInCluster[1] = &somePattern[0];
printf("%d\n", cluster_ptr[1]->patternInCluster[1]->id_vec);
printf("%d\n", cluster_ptr[0]->patternInCluster[1]->id_vec);
printf("%d\n", cluster_ptr[1]->patternInCluster[0]->id_vec);
printf("%d\n", cluster_ptr[2]->patternInCluster[1]->id_vec);
return 0;
}
On my system, I just compiled and it builds and runs error-free.
I can't quite figure out how to do this, I've tried this and several variations and some will compile and seemingly work ok but I'll get very random segfaults and it has something to do with the way I'm declaring these structs. All the info in the structs are dynamic. Please let me know the proper way to do this, thank you.
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char* s2string1;
char* s2string2;
int s2int1;
} struct2;
typedef struct
{
char* s1string1;
char* s1string2;
struct struct2* mystruct;
int int1;
} struct1;
struct struct2* RetS2(char* CopyMe)
{
int* Array = (int*) malloc (sizeof (int) * 5);
Array[0] = strlen (CopyMe);
struct struct2* S2 = (struct struct2*) malloc ( sizeof (struct2) );
S2->s2int1 = Array[0];
return S2;
}
struct struct1* RetS1()
{
struct struct1* S1 = (struct struct1*) malloc ( sizeof (struct1) );
struct struct2* S2 = RetS2();
S1->mystruct = S2;
S1->int1 = S2->S2int1;
return S1;
}
int main()
{
struct struct1 Top = RetS1();
if (Top->mystruct->s2int1 == 10)
// do something
return 0;
}
Your code has multiple issues:
This is the main issue:
RetS2's function definition is
struct struct2* RetS2(char* CopyMe)
which means that it expects a char* as its first argument. But when you call it:
struct struct2* S2 = RetS2();
you don't pass an arguments. This invokes Undefined Behavior.
Here:
int* Array = (int*) malloc (sizeof (int) * 5);
You allocate memory for 5 ints. You use the first element of the array and stops using it. You also forgot the free the allocated memory for Array.
The cast in malloc (and family) is not required in C.
You don't free the malloced memory for S2 and S1.
works:
struct data{
int val;
};
int main(void){
struct data *var[2];
(*var)->val = 6;
printf("%d\n", (*var)->val);
return 0;
}
segfault:
struct data{
int val;
};
int main(void){
struct data **var = malloc(3 * sizeof(struct data));
(*var)->val = 6; // <- crash
printf("%d\n", (*var)->val);
return 0;
}
can someone explain why segfault appears and give me an working example with minimal changes to the segfault code that i can understand pls.
The pointer is not malloc'ed, you are dereferencing an invalid pointer because your array is an array of poitners, and it's elements are not pointing to valid memory.
Try this
#include <stdio.h>
#include <stdlib.h>
struct data
{
int val;
};
int main(void)
{
struct data *var[2];
/* You need to malloc before dereferencing `var[0]` */
var[0] = malloc(sizeof(var[0][0]));
if (var[0] != NULL)
{
var[0]->val = 6;
printf("%d\n", var[0]->val);
free(var[0]);
}
return 0;
}
also, using (*var)->val = 6 is absolutely unnecessary and confusing.
In the second case, you should also do almost the same thing, except that the array of pointers is a pointer to an array of poitners and hence needs malloc() too, so your second example accidentally works because there is enough memory malloc()ed but it's also wrong, you should do it this way
#include <stdio.h>
#include <stdlib.h>
struct data
{
int val;
};
int main(void)
{
struct data **var;
var = malloc(2 * sizeof(var[0]));
if (var == NULL)
return -1;
/* You need to malloc before dereferencing `var[0]` */
var[0] = malloc(sizeof(var[0][0]));
if (var[0] != NULL)
{
var[0]->val = 6;
printf("%d\n", var[0]->val);
free(var[0]);
}
free(var);
return 0;
}
I allocate array of struct in function, but cannot fill those structures with values in same function.
#include<sys/sem.h>
void setSemaphores(int N, struct sembuf **wait){
*wait = malloc(N * sizeof(struct sembuf));
wait[3]->sem_op = 99; //causes error: Segmentation fault (core dumped)
}
int main(int argc, char *argv[]) {
int N = 4;
struct sembuf *wait;
setSemaphores(N, &wait);
wait[3].sem_op = 99; //works fine
return 0;
}
In setSemaphores():
wait is a pointer to one variable of type struct sembuf, not to an array of them.
Thus, wait[3] is UB. What you wanted is (*wait)[3].sem_op.
Another tip:
Change *wait = malloc(N * sizeof(struct sembuf));
to *wait = malloc(N * sizeof **wait);.
That easily avoids using the wrong type in a sizeof.
I would like to create a function that will reallocate 2D array of typedef struct
typedef struct hero_data{
char name[254];
char title[254];
int encoding;
int startstr;
double incstr;
int startdex;
double incdex;
int startintel;
double incintel;
int basemindmg,basemaxdmg;
double bat;
double basearmor;
struct hero_data *next;
struct hero_data *Class;
}hero;
typedef struct parameters{
int toughtotal;
int nimbletotal;
int smarttotal;
int skeptictotal;
int mystictotal;
int cursedtotal;
int brutetotal;
int shreddertotal;
int vanillatotal;
int typetotal;
int typenum;
hero **smart[];
hero **nimble[];
hero **tough[];
hero **type[][];
hero **skeptic[][];
hero **mystic[][];
hero **cursed[][];
hero **brute[][];
hero **shredder[][];
hero **vanilla[][];
}Parameters;
void reallocation(Parameters *p, int typenum,int typetotal)
{
int i;
p = realloc(p,sizeof(Parameters *) * typenum);
for ( i = 0; i < typenum; i++)
{
p[i] = realloc(p[i],sizeof(Parameters) * typetotal);
}
}
The function above shall be called like: void reallocation(p->type,p->typenum,p->typetotal);
So, by substituting the parameters of the function correctly, I expect the function to look like:
void reallocation(Parameters *p, int typenum,int typetotal)
{
int i;
p->type = realloc(p->type,sizeof(Parameters *) * p->typenum);
for ( i = 0; i < p->typenum; i++)
{
p->type[i] = realloc(p->type[i],sizeof(Parameters) * p->typetotal);
}
}
The typedef struct named Parameters contains int typenum, int typetotal, and the 2D arrays that shall be initialized through realloc().
When I try to compile, I am getting an error in Tiny C (Windows): *The file is in C.
Error: cannot cast 'struct parameters' to 'void *'
(This apeears in the 'p[i] = realloc(p[i],sizeof(Parameters) * typetotal')
Can anyone help me re-write this function so that I will be able to realloc the 2D arrays within the Parameter *p?
I tried changing void reallocation(Parameters *p, ...) into void reallocation(Parameters *p[], ...) and the Error # 2 becomes the same message as Error #1 and it appears in the = of p[i] = realloc (...);
A large problem with your code is that you are assigning inequal types to each other, and you are also not checking the result of realloc. If this call were to fail, you will leak the memory allocated initially.
Assuming that your struct looks like
typedef struct {
int typenum;
int typetotal;
} Parameters;
Parameters *p;
p = malloc(10 * sizeof(*p));
if (p == NULL)
printf("Allocatation of memory failed!\n");
To properly reallocate to say 20, you could do something like this
reallocate_p(&p, 20);
Where the function is defined as
void reallocate_p(Parameters **p, int new_size)
{
Parameters *temp;
temp = realloc(*p, sizeof(*temp) * new_size);
if (temp==NULL) {
printf("Reallocatation of memory failed!\n");
// Handle error
}
*p = temp;
return;
}
Also note that we don't cast the return value of malloc() and realloc().
As to why, see this reference
OP is coding in C, but using a using a C++ compiler.
Code in C++
// C
// p = realloc(p,sizeof(Parameters *) * typenum);
// C++
p = (Parameters *) realloc(p,sizeof(Parameters *) * typenum);
OR
VS2012: set properties for each C file to use C compiler
How to compile C in visual studio 2010?
OP code has a memory leak when scaling down the pointer array table. The pointers in the table that are about to be loss due to realloc() need to be freed first.
for (i=old_typenum; i<typenum; i++) free(p[i]);
p = realloc(p,sizeof(Parameters *) * typenum);