Double indirection and structures passed into a function - c

I am curious why this code works:
typedef struct test_struct {
int id;
} test_struct;
void test_func(test_struct ** my_struct)
{
test_struct my_test_struct;
my_test_struct.id=267;
*my_struct = &my_test_struct;
}
int main ()
{
test_struct * main_struct;
test_func(&main_struct);
printf("%d\n",main_struct->id);
}
This works, but pointing to the memory address of a functions local variable is a big no-no, right?
But if i used a structure pointer and malloc, that would be the correct way, right?
void test_func(test_struct ** my_struct)
{
test_struct *my_test_struct;
my_test_struct = malloc(sizeof(test_struct));
my_test_struct->id=267;
*my_struct = my_test_struct;
}
int main ()
{
test_struct * main_struct;
test_func(&main_struct);
printf("%d\n",main_struct->id);
}

The first version working is just dumb luck. Try randomly calling something else after test_func returns but before you call printf.
The second version is correct. Of course, you didn't free the heap memory, but whether that matters at the end of a program is a matter of debate.

You are right, passing a pointer to something that is allocated on the stack (and therefore goes away when the function returns, is wrong).
Passing a pointer to a heap allocated variable is fine.
"It works" is an illusion. You are returning a pointer to a stack-allocated variable in the first code example.
The pointer will point to garbage -- try dereferencing it...

Related

Assign pointer-to-pointer to a pointer to a pointer inside a struct

I am editing someone else's code and trying to make sense of it. The function passes in a parameter void **dst_val. I am not great with pointers. I have looked at all of the remotely relevant posts on stack overflow and didn't find what I am looking for.
I have a struct:
typedef struct {
u_int img_out_len;
char *img_out_val;
} img_out;
I declare a pointer to a struct:
img_out *clnt_res;
and allocate memory for it.
Now, where I'm confused. I need to set void **dst_val to point to the img_out_val pointer inside the pointer to the struct, and I can't figure out the syntax. Why are these incorrect, and what is correct?
dst_val = (void *)(*clnt_res).img_out_val; //wrong
dst_val = (void **)clnt_res->img_out_val; //wrong
I should also note that img_out_val points to data for a binary file.
Edit:
Since the function passes in void **dst_val, I need that to point to the data for the binary when the function returns.
If frslm's anser is not good enough, you could also try
&(void*)clnt_res->img_out_val;
Since clnt_res->img_out_val gives you a char *, you need to get the address of that (to end up with a char **) before casting it as a void **:
(void **)&clnt_res->img_out_val;
Assuming you had to call
void foo(void ** ppv);
then to get around any casting questions/issues do it like this:
{
void * pv = &clnt_res->img_out_val;
foo(&pv);
}
or even shorter:
{
foo(&((void*){&clnt_res->img_out_val}));
}
Please note that the above void* does not indicate a cast but defines a compound literal of type void*.

allocating static memory for character pointer defined in struct in C

I have structure with char pointer. I want to allocate static memory to this struct member. How can I do this?
Example:
struct my_data {
int x;
bool y;
char *buf;
};
How to assign 10 bytes static memory to this char pointer? I know malloc to assign dynamic memory allocation. Is this Ok?
struct my_data data;
char buffer[10];
data.buf = &buffer[0];
PS: I am not allowed to change this struct and use malloc to assign dynamic memory.
That will be even simpler (array decays to pointer automatically):
data.buf = buffer;
note that buffer must have an ever-lasting lifetime or you have to make sure that it's not deallocated (i.e. routine where it is declared returns) while you're using it or referencing it.
Allocating from a subroutine and returning will cause underfined behaviour because memory will be deallocated on return.
For instance don't do this (as we often see in questions here):
struct my_data foo()
{
struct my_data data;
char buffer[10];
data.buf = &buffer[0];
return data;
}
int main()
{
struct my_data d = foo(); // buffer is already gone
Bugs introduced by this kind of UB are nasty because the code seems to work for a while, until the unallocated buffer gets clobbered by another function call.

Compiler warnings and notes but dropping & does not work

In the below code snippet I'm getting a gcc compiler warning: "passing argument 1 of initArr from incompatible pointer type initArr(&stack,2);"
and a note: "expected 'struct Arr *' but argument is of type 'struct Arr**'"
which makes perfect sense to me.
As suggested by many a SO post, dropping the ampersand from the call to initArr(&stack, 2) however, results in another warning: "'stack' is used unitialized in this function: init(stack, 2);" and an immediate segfault error when ran.
What am I doing incorrectly?
I also tried using struct Arr in the malloc sizeof call and as expected, no change.
#include<stdio.h>
#include <stdlib.h>
#define TYPE int
struct Arr {
TYPE * data; // Pointer to the data array.
int size; // Number of elements in the array.
int capacity; // Capacity of the array.
};
void initArr(struct Arr * da, int capacity) {
da->data = malloc(sizeof(TYPE) * capacity);
da->size = 0;
da->capacity = capacity;
}
int main() {
struct Arr *stack;
initArr(&stack, 2);
return 0;
}
As haccks answer says,
you need to initialize your pointer, so it points to a real location
pass the pointer (rather than the address of the pointer variable)
int main()
{
struct Arr realArray; // allocate memory for the Arr (on the CPU's stack)
struct Arr *stack; // pointer variable (undefined)
stack = &realArray; // make variable "stack" point to realArray
initArr(stack, 2); // pass the pointer to realArray
}
stack is a pointer and it must be pointing to some valid memory location. Since stack is passed to the function and isn't initialized, you are getting a warning. In the function you are trying to access some random memory location which can cause the program crash or any erroneous behavior of the program, aka undefined behavior.
Change this:
struct Arr *stack;
To this:
struct Arr stack;
First look at the declaration of your initArr function:
void initArr(struct Arr * da, int capacity)
Your first argument is of type 'pointer to a struct'
Now look at your invocation of this function:
struct Arr *stack;
initArr(&stack, 2);
We see that stack is of type 'pointer to a struct', and in the function you are passing the address of stack (.i.e. the type is a pointer to a pointer to a struct). Which is what the gcc error is about, the note actually gives more information about the type that the function expects and the type that you are providing
There are two ways to fix this
leave the declaration of initArr as it is, and then change the function
invocation from initArr(&stack, 2) to initArr(stack, 2). In this case you will need to make sure that you have allocated memory for the structure prior to passing it to the function;
int main()
{
struct Arr* da = NULL;
da = malloc(sizeof(struct Arr));
initArr(da, 2);
}
or equivalently,
int main
{
struct Arr stack;
initArr(&stack, 2);
}
I would probably go for one of the above solutions.
Modify the declaration of initArr to initArray(struct Arr** da, int capacity). You will still need to make sure memory is allocated as before. However, if you change initArr to:
void initArr(struct Arr** da, int capacity)
{
*da = malloc(sizeof(struct Arr));
(*da)->data = malloc(sizeof(TYPE) * capacity);
(*da)->size = 0;
(*da)->capacity = capacity;
}
In this case I am changing the semantics of your initArr function so that I am initializing the structure all in one place. The code in your main function would remain unchanged.
N.B. For clarity, error checking has been omitted in the above code snippets, please don't do this in real code. Always check the return value from malloc to ensure that memory has been allocated.

Incrementing member of struct segfaults

I'm trying to increment a value of a struct (an int) just to test a code snippet of mine (This isn't my entire code), just the point of focus of my question. I'm given the struct:
typedef struct Test Test;
typedef struct Test {
char * name;
int numOfElements;
Test * test[];
}Test;
As well as the functions:
void startFunc(Test ** newStruct) {
newStruct = malloc(sizeof(Test));
(*newStruct)->name = NULL;
(*newStruct)->numOfElements = 0;
func(newStruct);
}
void func(Test ** newStruct) {
(*newStruct)->numOfElements++;
}
//create function to later free allocated memory
However incrementing the value of numOfElements seems to segfault. Is it the fact that I didn't allocate enough memory (Since I'm using a flexible array member?)
I tried using valgrind and got a invalid read of size 8 on the (*newStruct)->name =NULL;
Which would suggest it's not malloced, Memory help here would be much appreciated,
malloc(sizeof(Test)) is intended to allocate a raw object of type Test, so conceptually it returns a Test * pointer. This pointer is assigned to newStruct, which is a Test **. This mismatch between Test * and Test ** already suggests that the malloc line is broken.
An immediate guess would be that this
newStruct = malloc(sizeof(Test));
was actually intended to be
*newStruct = malloc(sizeof(Test));
You are already scrupulously using *newStruct everywhere in your startFunc, but for some reason completely forgetting about it in the malloc line.
An arguably better way to express the same thing would be
*newStruct = malloc(sizeof **newStruct);

Accessing members in a pointer to a pointer of a struct

Code is as follows:
/* set.h */
struct setElement{
char *element;
setElement *next;
};
typedef struct setElement *Set; //Set is now the equivalent of setElement*
Set a;
setInit(&a);
/* setInit function declaration # setInit.c */
int setInit(Set *a){
(*a)->element = "asdf"; //results in a seg fault
}
Trying to malloc 'a' works, but if I try to access any member within the set 'a' doesn't work. I understand I'm passing a reference of the set from the main() function to setInit, so I believe the pointer contained within setInit is addressing the memory allocated by 'Set a' in the main() function, so a malloc wouldn't be required...
Iunno. Help is appreciated :)
The problem is that you have not allocated the setElement you are trying to assign to. In the main part of the code you are creating a Set, which is just a pointer to a setElement. This pointer is never set to point to anything sensible. I.e. you need something like
Set a = malloc(sizeof(setElement));
Alas, it is unclear where exactly your variables are defined. I assume your main.c is something like
#include "set.h"
Set a;
int main()
{
setInit(&a);
}
If so, your a, which is a pointer by itself, should point to somewhere.
If your framework wants malloc()ed data, you should do
int main()
{
a = malloc(sizeof(*a)); // *a is a struct setElement now, with 2 pointer-sized members.
setInit(&a); // Now seInit should be able to operate on the struct as wanted.
}
As #amaurea has mentioned, you'll need to make use of malloc() for your setElement structure. In addition to this, you need to do the same for the setElement struct's element member. A char* is merely a pointer to a char or char array and will not implicitly allocate anything.
int setInit(Set *a){
(*a)->element = "asdf"; //results in a seg fault
}
Could be re-written
int setInit(Set *a){
(*a)->element = malloc(sizeof("asdf"));
strcpy((*a)->element,"asdf");
}
Which the above could be rewritten to take a second parameter of the actual element contents.

Resources