Say I have a function from another api that returns structs by value
struct foo{
int bar;
bool success;
}
foo getThefoo();
What happens in a loop if this function is called eg
int foolen = 0;
foo** foos;
do {
foolen++;
foos = realloc(foos,sizeof(foo*)*foolen);
foo myfoo = getThefoo();
foos[foolen-1]=&myfoo;
}while (/**something*//)
Does a new foo struct get allocated on the stack for each iteration?. Or is the initial allocation reused?. I ask because taking a pointer to that structure might be an unexpected value.
getThefoo is defined in an external library. So its not trivial to make that return a pointer to a food structure.
This won't work, you're storing the address of a local which will go out of scope, rendering the stored addresses useless.
The proper fix seems to be to not store pointers to struct foos in the array, but just storing them directly:
struct foo *foos = NULL;
size_t foolen = 0;
do {
++foolen;
foos = realloc(foos, foolen * sizeof *foos);
foos[foolen - 1] = getTheFoo();
} while(something something);
Of course, the usual caveats apply:
It's more efficent to call realloc() less often, by over-allocating and tracking array length and array allocated space separately.
realloc() can fail, the above loses the old allocation (if any) when that happens.
Note that structures are values and thus fully assignable, so that's what we do.
Related
I have a struct defined like this:
typedef struct
{
int num;
char letter;
}* Foo;
And an array like this:
Foo* items = malloc(sizeof(Foo) * 4);
From my understanding and from the (accepted) answer to this question Dynamic array of pointers to structs, I would expect the above line to only reserve the memory for 4 Foo items, but doesn't initialize it - i.e., if I try to access items[i]->num, I should get some kind of error.
Also, in order to insert item into this array, I should do this:
items[0] = malloc(sizeof(*items[0]));
However, I did a little test, and seems like the following code prints 1 and a just fine:
Foo* items = malloc(sizeof(Foo) * 2);
items[0]->num = 4;
items[0]->letter = 'a';
printf("items[0] = {num=%d, char=%c}\n", items[0]->num, items[0]->letter);
I'm confused. Is this the expected behavior?
Your initial malloc:
Foo* items = malloc(sizeof(Foo) * 4);
Is creating an array of 4 pointers, since Foo is a pointer type. So your second malloc:
items[0] = malloc(sizeof(*items[0]));
Makes sense, since you're allocating a struct to that pointer.
However, the assignment you're doing leads to undefined behavior because you didn't do the second malloc and therefore no space has been allocated to items[0] yet. C won't prevent you from writing to a memory location you shouldn't be writing to. And once you do that, anything can happen.
One thing that's a bit confusing here is that you used typedef to define a pointer type. That can lead to a lot of confusion since it's not apparent by looking at the type that it's a pointer. And in this case, because of how you defined Foo, you had an extra layer of pointer indirection you probably don't need.
So if you define your struct like this:
typedef struct
{
int num;
char letter;
} Foo;
Then this can be done safely:
Foo* items = malloc(sizeof(Foo) * 2);
items[0].num = 4;
items[0].letter = 'a';
printf("items[0] = {num=%d, char=%c}\n", items[0].num, items[0].letter);
Now the malloc creates an array of structs instead of an array of pointers to structs, so an additional layer of mallocs is no longer necessary.
You have to allocate structs and save its pointer to items's elements if you want to use structs. Otherwise, the item's elements are junk and access to it may cause errors.
The second test may worked fine due to the optimization which removes malloc and pass the values of items[0]->num and items[0]->letter directly to printf.
This is happening because you have reserved enough space for the Foo array and probably one element but it's not the expected behavior, there is no expected behavior in this case because what you do invokes undefined behavior.
This will fail if you add more fields to the struct, because then 2 * sizeof(void *) will not be enough. To test it, try adding 2 pointers to the struct like this1
typedef struct
{
int num;
char letter;
void *pointers[2];
} *Foo;
If you want you can do it right, and this is another reason not to typedef a pointer, this would work
typedef struct
{
int num;
char letter;
void *pointers[2];
} Foo;
Foo *foo_pointer = malloc(N * sizeof(Foo));
/* ^ this would be wrong if `Foo' were a pointer */
if (foo_pointer == NULL)
please_abort_this_do_not_continue_because_malloc_has_failed();
foo_pointer[0].num = 1;
foo_pointer[0].letter = 'a';
1It really annoys me to write this, because typedefing a pointer is never a good idea
One of my assignments for the C Programming course was define a function called create_card. This function receives a suit character and an a card value, and returns a card_t struct.
Question: How is a function supposed to create a struct? Can't it only create values for the struct? Did I misinterpret the meaning of the question or was the assignment written down wrong?
This is an example of a function returning a struct.
struct test {
int a;
};
struct test Fun(int k) {
struct test d;
d.a=k;
return d;
}
Replace struct test with the name of your struct and the definition of struct test with your struct's definition.
How to use
int main() {
struct test Test=Fun(6);
printf("%d",Test.a); // prints '6'
return 0;
}
You can either return a struct from a function like in ForceBru's answer, or you can create a struct in C dynamic memory (a.k.a. the heap), using malloc, and return a pointer to it, e.g.
struct foo_st {
int num;
const char* str;
};
struct foo_st*
/* the second argument s should practically be a literal string */
make_foo (int n, const char* s) {
struct foo_st* p = malloc(sizeof(struct foo_st));
if (!p) { perror("malloc foo"); exit(EXIT_FAILURE); };
p->num = n;
p->str = s;
return p;
}
Your main (or some other function) might later do struct foo_st*fooptr = make_foo(32, "abc"); but someone should call free(fooptr) (or at least, free the address which has been inside fooptr).
Of course, you should never forget to free a malloc-ed pointer when it becomes useless. Be afraid of memory leaks, buffer overflow and undefined behavior. Read more about malloc(3) & free.
BTW, in practice you should decide of who is responsible for free-ing memory. In the above make_foo example, the second parameter to make_foo is supposed to be a literal string (if it is malloc-ed e.g. using strdup(3), you'll need to free it elsewhere, and that becomes very messy).
In practice you should document the conventions about who is responsible to free some dynamically previously mallocated memory. You might want to use valgrind (if your system has it), and, if using a recent GCC compiler, its -fsanitize=address option to hunt memory related bugs. Very often, you happen to code both making and destroying functions (like here or here).
You might want to read about garbage collection (at least, to understand the concepts, such as reference counting, and the terminology). Perhaps you'll later want to use Boehm's conservative garbage collector.
I have a structure (let's call it structure1) which holds a pointer to another structure (structure2), this way.
typedef struct structure{
structure2 *pointer
}structure;
structure structVariable;
structVariable.pointer = functionThatReturnsAPointerToStructure2Variable();
The thing is, as the program changes context (for example, when calling functions), the return value of the following code changes
structVariable.pointer->someAttribute
Any idea of why this might be happening? If you need more info please ask. Thanks!
MORE INFO
This is the real-deal
structure would be this
typedef struct CPU{
int variableCounter;
int instructionPointer;
char *currentInstruction;
t_list *dataDictionary_list;
u_int32_t currentContext;
PCB *assignedPCB;
CPU_STATUS status;
}CPU;
And this is how I assign the pointer (PCB *pointer)
PCB *pcb_createFromScript(const char *script){
t_medatada_program *metadata = metadatada_desde_literal(script);
PCB *pcb = malloc(sizeof(PCB));
pcb->instructionCount = metadata->instrucciones_size;
pcb->tagCount = metadata->cantidad_de_etiquetas;
pcb->functionCount = metadata->cantidad_de_funciones;
int codeSegmentSize = strlen(script);
int tagIndexSize = 0;
if(metadata->etiquetas != 0){
tagIndexSize = strlen(metadata->etiquetas);
}
int instructionIndexSize = metadata->instrucciones_size * sizeof(t_intructions);
pcb_getSegments(pcb,1024,codeSegmentSize,tagIndexSize,instructionIndexSize);
pcb->currentContext = pcb->stackSegment;
pcb->variableCounter = 0;
memory_write(pcb->codeSegment,0,codeSegmentSize,script);
memory_write(pcb->tagIndexSegment,0,tagIndexSize,metadata->etiquetas);
memory_write(pcb->instructionIndexSegment,0,instructionIndexSize,(void *)metadata->instrucciones_serializado);
pcb->uniqueId = (int) random();
return pcb;
}
And then I assign it this way (myCPU is global), that's why I call it inside cpu_getPCB without passing it as a parameter
cpu_getPCB(*dummyPCB);
void cpu_getPCB(PCB myPCB){
myCPU.currentContext = myPCB.currentContext;
myCPU.assignedPCB = &myPCB;
}
Here is some speculation.
If you are modifying the object that structVariable.pointer points to in some function, then when you try to read structVariable.pointer->someAttribute, that value will change to reflect to modification to the object.
Another possibility, as the other answer mentioned, is that structVariable.pointer is pointing to local memory (stack memory for a function) which can easily be overwritten on a new function call. That can be corrected by using malloc to do heap allocation instead of stack allocation.
Here is the first and most obvious issue. You are taking the address of a parameter and assigning it to myCPU.assignedPCB.
Since C is pass-by-value, you have copied it instead of capturing the original. Moreover, the parameter has the same lifetime as a local variable, and will go away when the function returns.
void cpu_getPCB(PCB myPCB){
myCPU.currentContext = myPCB.currentContext;
myCPU.assignedPCB = &myPCB;
}
You can fix it by passing a pointer instead, since you are in C and do not have access to the reference type.
void cpu_getPCB(PCB* myPCB){
myCPU.currentContext = myPCB->currentContext;
myCPU.assignedPCB = myPCB;
}
The "structure2 *pointer" will be pointing at a piece of memory that will disappear when you change context. Allocate the Structure2 variable and free it when it's no longer needed
I'm working my way through the learn c the hard way book and have run into a few issues on Exercise 19. The author said that ex19 was intended for the learners to get to know the macro in c. I have no problem in understanding the concept of that, but I just don't understand everything else. I can't understand how the object prototype is created.
Especilly,what does the following sentense mean?
Since C puts the Room.proto field first, that means the el pointer is
really only pointing at enough of the block of memory to see a full
Object struct. It has no idea that it's even called proto.
the relevant code is this:
// this seems weird, but we can make a struct of one size,
// then point a different pointer at it to "cast" it
Object *el = calloc(1, size);
*el = proto;
can anyone tell me how on earth malloc/calloc exactly works? As far as i know, it just allocate the required number of memory and return the first address. If so, how can the computer know the data struct of the allocated memory? like in the code, after Room *arena = NEW(Room, "The arena, with the minotaur");,you can do this directly arena->bad_guy = NEW(Monster, "The evil minotaur"); how does the computer know there is a bad_guy??
what on earth is the content of *el after the above two statements(Object *el = calloc(1, size); and *el = proto;)?
Any help will be appreciated!!
the link to the exercise: http://c.learncodethehardway.org/book/ex19.html
calloc has the additional feature that it fills the allocated memory with zero bytes, whereas using the equivalent malloc call would require an additional step if all or some of the allocation needs to be zero initially.
In the code
arena->bad_guy = NEW(Monster, "The evil minotaur");
the compiler knows the layout of the struct because the access is through the arena variable, which is declared as a pointer to Room, which is presumably a typedef of a struct.
For the other part, the guarantee of ordering within structs allows a limited form of inheritance in composite structs, or extended structs.
struct A {
int x;
};
struct B {
int foo;
double baloney;
};
struct B (or a pointer to it) can be cast to a (pointer to a) struct A because they both begin with an int. Of course, if you cast the other way, the struct A must have been originally a struct B or access to the baloney field will be undefined. In other words, struct B essentially begins with a struct A.
This may be easier to see if I rewrite my example like this:
struct A {
int x;
};
struct B {
struct A foo;
double baloney;
};
Now you can get a struct A out of struct B in different ways.
struct A a;
struct B b;
a = b.foo; // regular member variable access
struct A *ap = &a;
struct B *bp = &b;
ap = (struct A *)bp; // cast the pointer
ap = & b.foo; // take a pointer from the member variable
ap = & bp->foo; // take a pointer from the member variable via a pointer
All it does is to alloc 1*size bytes. There's nothing magic with malloc/calloc. He is passing the sizeof(T) to the function through that NEW macro and putting it in Object_new's size parameter. So all the function knows is the size in bytes.
I create drvm *drv structure in my function. This structure itself contains fields which contains malloc()-ed fields (uint32_t *buffer). The code which do that is similar to that:
...
size_t elm_size = sizeof(model*);
uint32_t length = *(uint32_t*)len;
GArray *models = g_array_sized_new(FALSE, FALSE, elm_size, length);
model *mod;
for (int i = 0; i < length; ++i) {
mod = create_model(...);
g_array_append_val(models, mod);
}
This piece of code doesn't contain errors and is highly tested.
At the start of program I register function free_all() (by atexit()) which should clean all resources (especially memory) when exit() is performed.
Inside this function I'm trying freeing memory of elements of GArray* (model * structure) and memory for GArray * itself:
GArray *models;
g_array_set_clear_func(models, clean_model);
if(!g_array_free(models, FALSE)) { //OK }
The problem is that when clean_model(void *data) is called inside glib library I suggest it contains pointer to one model * element. But the address is wrong, it doesn't seem point to any correct value. Neither GArray*, nor model*.
Furthermore GArray *models in free_all() function is correct (the same as when I created it) and when I iterate through all GArray * elements in free_all() by
for (int i = 0; i < len; ++i) {
mod = g_array_index(models, model*, i); // Here I get correct pointer to model*
clean_model(mod);
}
I get expected values.
Question: What's wrong? How should I free memory of elements of GArray * if these elements contain malloc()-ed memory?
Part of header:
struct _info {
uint32_t *buffer;
uint32_t len;
};
typedef struct _info info;
struct _prod {
uint32_t *buffer;
uint32_t len;
};
typedef struct _prod prod;
struct _model {
uint32_t name;
prod product;
info inform;
};
typedef struct _model model;
struct _drvm {
GArray *models;
GArray *strings;
};
typedef struct _drvm drvm;
Basically the problem is that your clean_model function is passed model** instead of model* you were expecting.
Remember that GArray is meant to store complete structs, not just pointers to structs. In order to do that it needs to copy the whole contents of the struct into the internal data array and therefore any subsequent pointers to the structs (as passed to clean_model) are going to be pointing somewhere inside data (i.e. clean_model((elt_type*)&models->data[index * sizeof(elt_type)]) - where in your case elt_type is model*)
To fix the situation couple options come to mind, in order of (subjective) preference:
use GPtrArray instead; given that your elements are dynamically allocated already the memory management / pointer handling / typecasts (or lack thereof) would be less confusing
change clean_model argument to model**
use GArray to store model structs rather than pointers, but only makes sense if you can separate the allocation from populating the model contents, e.g. g_array_new(FALSE, FALSE, sizeof(model)) and fill_model(&g_array_index(models, model, i))
In all cases you should also probably pass TRUE to g_array_free since you don't seem to be using the GArray.data for anything afterwards (not that it would make any sense given that you're freeing all the useful data in it anyway.)