First post, long time reader. I am learning C but coming from many years of experience with Python. Sorry if this is a repost, but I don't even know the correct vocabulary to use when searching Google.
I think I am still stuck in an object-oriented mindset, which leads me to to stupid things in C. I have a type "my_type" which contains a pointer to a second type "my_array". In my OO way of thinking, I want to write New and Free functions for my_type. During initialization, my_type should create a new my_array and store it's pointer. Later during destruction, the destructor for my_type should call the destructor for my_array and free the dynamically allocated memory.
This code compiles but yields a nasty error
#include <stdio.h>
#include <stdlib.h>
/**
* @brief A type implementing a dynamically allocated array
*/
typedef struct my_array {
int n;
double *array;
} my_array;
/**
* @brief A type containing a my_array pointer
*/
typedef struct my_type {
my_array *a;
} my_type;
/**
* @brief Initialize the dynamically allocated array
*
* @param ma pointer to a my_array
* @param n number of array elements
*/
void my_array_new(my_array *ma, int n) {
ma->n = n;
ma->array = (double *) malloc(n * sizeof(double));
}
/**
* @brief Free dynamically allocated memory of a my_array
*
* @param ma pointer to a my_array
*/
void my_array_free(my_array *ma) {
free(ma->array);
}
/**
* @brief Initialize a my_type
*
* @param mt pointer to a my_type
* @param n number of array elements
*/
void my_type_new(my_type *mt, int n) {
/* Create a local my_array */
my_array a;
my_array_new(&a, n);
/* Store pointer to a */
mt->a = &a;
/* I am holding on to the pointer for a, but does a fall out of scope
* here? Is this the origin of the error? */
}
/**
* @brief Free allocated my_type
*
* @param mt pointer to my_type
*/
void my_type_free(my_type *mt) {
my_array_free(mt->a);
}
int main(int argc, char *argv[]) {
my_type mt;
int n = 10;
printf("Initializing my_type %p\n", &mt);
my_type_new(&mt, n);
printf("mt.a->n = %d\n", mt.a->n);
printf("Freeing my_type %p\n", &mt);
my_type_free(&mt);
return 0;
}
Here is the error
Initializing my_type 0x7ffede7434c0
mt.a->n = 10
Freeing my_type 0x7ffede7434c0
*** Error in `./test': double free or corruption (out): 0x00007ffede7434c0 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3e5f077d9e]
/lib64/libc.so.6(cfree+0x5b5)[0x3e5f0839f5]
./test[0x400618]
./test[0x400662]
./test[0x4006da]
/lib64/libc.so.6(__libc_start_main+0xf0)[0x3e5f01ffe0]
./test[0x4004f9]
I think I have an idea what is going on here. When I call my_type_new
I create a local my_array
variable. When the function ends this falls out of scope, but I still have the pointer stored. And now it gets fuzzy: is the memory formally assigned to mt.a
marked as junk, but I can still read out it's value from dereferencing the pointer?
What is the correct way for my_type_new
to create and store a my_array
?
I am open to all suggestions, but I can't use C++ classes here for other reasons.