I'm trying to allocate a struct array inside a function, but when I return to main it's like the memory that I just allocated has been overwritten. That's my example code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Class {
int students;
Person * N;
};
struct Person
{
char * name;
int age;
};
void allocation(struct Class ** myclasspointer)
{
struct Class *mytempstruct= malloc(sizeof *mytempstruct);
mytempstruct -> students = 10;
char *n= "My name is...?";
mytempstruct -> N = malloc (sizeof (mytempstruct -> N) * 10);
for (i = 0; i < 10; i++) {
mytempstruct -> N[i].age = i;
mytempstruct -> N[i].name = malloc (sizeof (char) * (strlen(n));
strncpy (N[i].name, n, strlen(n));
}
*myclasspointer = mytempstruct;
}
int main(void)
{
int i;
struct class * MyClass;
allocation(&MyClass);
for (int i = 0; i < MyClass.students; i++)
Prinf("Student %s, age %d: %d \n", MyClass->N[i].name, MyClass->N[i].age);
for (int i = 0; i < MyClass->students; i++)
free(MyClass->N[i]);
free (MyClass);
return 0;
}
Once I go back to main, only some values are as they should. I also tryed to change:
void allocation(struct Class ** myclasspointer)
{
struct Class *mytempstruct= malloc(sizeof *mytempstruct);
char *n= "My name is...?";
mytempstruct -> N = malloc (sizeof (mytempstruct -> N) * 10);
for (i = 0; i < 10; i++) {
mytempstruct -> N[i].age = i;
mytempstruct -> N[i].name = malloc (sizeof (char) * (strlen(n));
}
*myclasspointer = mytempstruct;
}
to:
void allocation(struct Class ** myclasspointer)
{
myclasspointer= malloc(sizeof *myclasspointer);
char *n= "My name is...?";
myclasspointer-> N = malloc (sizeof (myclasspointer-> N) * 10);
for (i = 0; i < 10; i++) {
mytempstruct -> N[i].age = i;
mytempstruct -> N[i].name = malloc (sizeof (char) * (strlen(n));
}
}
But I have the same result.
First you need a forward declaration of person. Then change
mytempstruct -> N = malloc (sizeof (mytempstruct -> N) * 10);
^will give the size of pointer instead of structure `person`
to
mytempstruct -> N = malloc (sizeof (struct person) * 10);
mytempstruct -> N[i].name = malloc (sizeof (char) * (strlen(n)) );
strncpy (N[i].name, n, strlen(n));
is wrong you want:
mytempstruct -> N[i].name = malloc (sizeof (char) * (strlen(n)+1) );
strncpy (N[i].name, n, strlen(n)+1);
for space for the null character.
Related
I'm using an example from https://phoxis.org/2012/07/12/get-sorted-index-orderting-of-an-array/ where he returns the sort indices from a sort of an array, i.e.
3,4,2,6,8 returns 4,3,1,0,2 (+1 for each index in R). This is the equivalent of R's order function
I've translated his/her code to work as a function returning an array of sorted indices. The code gives the correct answer.
keeping track of the original indices of an array after sorting in C has a similar response, but as #BLUEPIXY warns, his solution doesn't work in all circumstances. I need something that will work in all circumstances, including ties.
however, the original author uses a global pointer, which causes a memory leak, and free() doesn't fix it. which I don't know how to do this without the global pointer.
How can I fix this memory leak, or at least return sorted indices in C that will always work?
#include <stdio.h>
#include <stdlib.h>
/* holds the address of the array of which the sorted index
* order needs to be found
*/
int * base_arr = NULL;
/* Note how the compare function compares the values of the
* array to be sorted. The passed value to this function
* by `qsort' are actually the `idx' array elements.
*/
static int compar_increase (const void * a, const void * b) {
int aa = *((int * ) a), bb = *((int *) b);
if (base_arr[aa] < base_arr[bb]) {
return 1;
} else if (base_arr[aa] == base_arr[bb]) {
return 0;
} else {
// if (base_arr[aa] > base_arr[bb])
return -1;
}
}
int * order_int (const int * ARRAY, const size_t SIZE) {
int * idx = malloc(SIZE * sizeof(int));
base_arr = malloc(sizeof(int) * SIZE);
for (size_t i = 0; i < SIZE; i++) {
base_arr[i] = ARRAY[i];
idx[i] = i;
}
qsort(idx, SIZE, sizeof(int), compar_increase);
free(base_arr); base_arr = NULL;
return idx;
}
int main () {
const int a[] = {3,4,2,6,8};
int * b = malloc(sizeof(int) * sizeof(a) / sizeof (*a));
b = order_int(a, sizeof(a) / sizeof(*a));
for (size_t i = 0; i < sizeof(a)/sizeof(*a); i++) {
printf("b[%lu] = %d\n", i, b[i]+1);
}
free(b); b = NULL;
return 0;
}
A straightforward approach without using a global variable can look the following way
#include <stdio.h>
#include <stdlib.h>
int cmp_ptr(const void *a, const void *b)
{
const int **left = (const int **)a;
const int **right = (const int **)b;
return (**left < **right) - (**right < **left);
}
size_t * order_int(const int *a, size_t n)
{
const int **pointers = malloc(n * sizeof(const int *));
for (size_t i = 0; i < n; i++) pointers[i] = a + i;
qsort(pointers, n, sizeof(const int *), cmp_ptr);
size_t *indices = malloc(n * sizeof(size_t));
for (size_t i = 0; i < n; i++) indices[i] = pointers[i] - a;
free(pointers);
return indices;
}
int main( void )
{
const int a[] = { 3,4,2,6,8 };
const size_t N = sizeof(a) / sizeof(*a);
size_t *indices = order_int(a, N);
for (size_t i = 0; i < N; i++) printf("%d ", a[indices[i]]);
putchar('\n');
free(indices);
return 0;
}
The program output is
8 6 4 3 2
As for the memory leak then it is due to overwriting the value of the pointer to redundantly allocated memory.
int * b = malloc(sizeof(int) * sizeof(a) / sizeof (*a));
b = order_int(a, sizeof(a) / sizeof(*a));
The memory allocation does not make sense.
The problem I see is that within main function - you are allocating pointer b some memory -
int * b = malloc(sizeof(int) * sizeof(a) / sizeof (*a));
The next line calls order_int(...) that returns a pointer to already allocated memory -
b = order_int(a, sizeof(a) / sizeof(*a));
Looking at the order_int function -
int * order_int (const int * ARRAY, const size_t SIZE) {
int * idx = malloc(SIZE * sizeof(int));
base_arr = malloc(sizeof(int) * SIZE);
for (size_t i = 0; i < SIZE; i++) {
base_arr[i] = ARRAY[i];
idx[i] = i;
}
qsort(idx, SIZE, sizeof(int), compar_increase);
free(base_arr); base_arr = NULL;
return idx;
}
.. you see that idx has been already been allocated the correct memory.
I would suggest removing the malloc from b - see below.
int * b = NULL;
I want to know how to assign a struct containing an array of int to an array of structs. I keep getting the incorrect result no matter what new solution I think of.
I believe the problem lies in this piece of code:
struct Codes *create(int as) {
struct Codes *c = malloc(sizeof (struct Codes)+as * sizeof (int));
c->as = as;
for (int i = 0; i < as; i++) {
c->a[i] = i;
}
return c;
}
The whole code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
struct Codes {
int as;
int a[];
};
struct Code {
int as;
struct Codes *ci[];
};
struct Codes *create(int as) {
struct Codes *c = malloc(sizeof (struct Codes)+as * sizeof (int));
c->as = as;
for (int i = 0; i < as; i++) {
c->a[i] = i;
}
return c;
}
struct Code *and(int as, struct Codes *cd) {
struct Code *c = malloc(sizeof (struct Code)+as * sizeof (struct Codes));
for (int i = 0; i < as; i++) {
c->ci[i] = cd;
}
c->as = as;
return c;
}
int main(int argc, char **argv) {
struct Codes *cd;
cd = create(4);
struct Code *c;
c = and(2, cd);
for (int i = 0; i < c->as; i += 1) {
for (int j=0; j < c->ci[i]->as; j++) {
printf("%d \n", c->ci[i]->a[j]);
}
}
free(cd);
free(c);
}//main
Actual Result:
0
1
2
3
Expected Result:
0
1
2
3
0
1
2
3
struct Code *c = malloc(sizeof (struct Code)+as * sizeof (struct Codes)); is incorrect. The struct Code 's ci is an array of pointers , but you allocated space for an array of structs.
To fix this, either change to sizeof(struct Codes *), or preferably use the pattern of dereferencing the pointer to the type you're allocating space for:
struct Code *c = malloc( sizeof *c + as * sizeof c->ci[0] );
Also, for (int j; should be for (int j = 0; . Your code causes undefined behaviour by using uninitialized value of j, it's just chance that you happened to get the output you did. Using the gcc flag -Wextra would have diagnosed this error.
How can I allocate with malloc and array of structures within and array of structures?
for expample:
struct car_t{
int price;
float kmsDriven;
};
struct garage_t{
int locationX;
int locationY;
struct car_t * car;
}
There's an array of garages, which every one of them has an array of cars.
You will have to use a loop:
#define N 42
#define M 17
struct garage_t *a = malloc(sizeof *a * N);
for (int i = 0; i < N; i++) {
a[i].car = malloc(sizeof (*a[i].car) * M);
}
Just allocate as usual, one by one.
int garage_num = 3, car_num = 5;
int i;
struct garage_t *garage;
garage = malloc(sizeof(struct garage_t) * garage_num);
for (i = 0; i < garage_num; i++) {
garage[i].car = malloc(sizeof(struct car_t) * car_num);
}
You should check if malloc()s are successful for actual use.
Searched around for one hour. I guess I'd better post the question here.
I simplify the code. The segfault is in the function initMyStruct.
#include "stdlib.h"
typedef struct {
int * arr1;
int * arr2;
} myStruct;
void allocMyStruct (myStruct * a, int num) {
a = malloc(sizeof(myStruct));
a->arr1 = malloc(10*sizeof(int));
a->arr2 = malloc(10*num*sizeof(int));
}
void initMyStruct (myStruct * a, int num) {
int i;
for (i = 0; i < 10; i++) a->arr1[i] = 0;
for (i = 0; i < 10*num; i++) a->arr2[i] = -1;
}
void freeMyStruct (myStruct * a, int num) {
int i;
for (i = 0; i < 10; i++) free(a->arr1);
for (i = 0; i < 10*num; i++) free(a->arr2);
free(a);
}
int main (void) {
int num = 3;
myStruct * a;
allocMyStruct (a, num);
initMyStruct (a, num);
freeMyStruct (a, num);
return 1;
}
Because you're not keeping the pointer to the newly allocated memory, instead you use an uninitialized pointer and getting undefined behavior.
You pass the a variable into allocMyStruct(), but that call is (like all others) by value, so the new value being assigned to it inside the function does not affect the value of a in main().
Change it so that allocMyStruct() either returns the new pointer value, or takes a pointer to the pointer. I would prefer the former, it's cleaner and using function return values often leads to better code:
myStruct * allocMyStruct(int num)
{
myStruct *p;
if((p = malloc(sizeof *p +
10 * sizeof *p->arr1 +
10 * num * sizeof *p->arr2)) != NULL)
{
p->arr1 = (int *) (p + 1);
p->arr2 = p->arr1 + 10;
}
return p;
}
The above code also streamlines the memory allocation, doing it all in one big malloc() call which is then "sliced" into the three parts you actually need.
If the size of arr1 is always 10 by the way, there's no point in having it dynamically allocated, it should just be int arr1[10]; in the struct declaration.
a is used uninitialized, change to:
myStruct * allocMyStruct (int num) {
myStruct *a;
a = malloc(sizeof(myStruct));
a->arr1 = malloc(10*sizeof(int));
a->arr2 = malloc(10*num*sizeof(int));
return a;
}
myStruct * a = allocMyStruct(num);
Also, there is no need to loop in your free function
void freeMyStruct (myStruct * a, int num) {
int i;
for (i = 0; i < 10; i++) free(a->arr1);
for (i = 0; i < 10*num; i++) free(a->arr2);
free(a);
}
Must be
void freeMyStruct (myStruct * a) {
free(a->arr1);
free(a->arr2);
free(a);
}
When you call void allocMyStruct (myStruct * a, int num) the a pointer will be passed as a value and the a parameter is a local copy of your pointer from main , after you change the local a in any of your three functions, it will not change in main.
For this you have to use double pointer as a function argument, so those functions will get an address of a pointer so they can modify it.
#include "stdlib.h"
typedef struct {
int * arr1;
int * arr2;
} myStruct;
void allocMyStruct (myStruct ** a, int num) {
*a = malloc(sizeof(myStruct));
(*a)->arr1 = malloc(10*sizeof(int));
(*a)->arr2 = malloc(10*num*sizeof(int));
}
void initMyStruct (myStruct ** a, int num) {
int i;
for (i = 0; i < 10; i++) (*a)->arr1[i] = 0;
for (i = 0; i < 10*num; i++) (*a)->arr2[i] = -1;
}
void freeMyStruct (myStruct ** a, int num) {
free((*a)->arr1);
free((*a)->arr2);
free(*a);
*a = NULL;
}
int main (void) {
int num = 3;
myStruct * a;
allocMyStruct (&a, num);
initMyStruct (&a, num);
freeMyStruct (&a, num);
return 1;
}
EDIT: Alter Mann is right about multiple freeing of the same address, on linux you would get instant crash for double freeing. And he has a simpler solution.
Based on this answer: https://stackoverflow.com/a/19765782/1606345
#include <stdlib.h>
typedef struct {
int *arr1;
int *arr2;
} myStruct;
myStruct *allocMyStruct(int num)
{
myStruct *p;
if ((p = malloc(sizeof *p +
10 * sizeof *p->arr1 +
10 * num * sizeof *p->arr2)) != NULL)
{
p->arr1 = (int *)(p + 1);
p->arr2 = p->arr1 + 10;
}
return p;
}
void initMyStruct(myStruct * a, int num)
{
int i;
for (i = 0; i < 10; i++) a->arr1[i] = 0;
for (i = 0; i < 10 * num; i++) a->arr2[i] = -1;
}
int main (void)
{
int num = 3;
myStruct *a = allocMyStruct(num);
initMyStruct(a, num);
free(a);
return 1;
}
It is safe to assign p->arr1 to the address of (p + 1)?
p->arr1 = (int *)(p + 1);
You have a fundamental problem here in how you are thinking about struct allocation.
When you malloc a struct, you malloc the sizeof that struct, you don't malloc for the arrays it will contain, those need to be allocated separately. To do this your code should look more like:
myStruct *allocMyStruct(int num)
{
myStruct *p = malloc( sizeof( myStruct ) );
if( p != NULL )
{
p->arr1 = malloc( sizeof( int ) * 10 ); // p->arr1 now points to an array of 10 elements
p->arr2 = malloc( sizeof( int ) * 10 * num ); // p->arr2 now points to an array of 10 * num elements
}
return p;
}
Keep in mind when you free this you will need to free the arrays individually as well so if your pointer the myStruct was a:
free( a->arr1 );
free( a->arr2 );
free( a );