Modifying struct members through a pointer passed to a function - c

for instance this code:
struct test{
int ID;
bool start;
};
struct test * sTest;
void changePointer(struct test * t)
{
t->ID = 3;
t->start = false;
}
int main(void)
{
sTest->ID = 5;
sTest->start = true;
changePointer(sTest);
return 0;
}
If I was to execute this code, then what would the output be? (i.e. if I pass a pointer like this, does it change the reference or is it just a copy?)
Thanks in advance!

Your program doesn't have any output, so there would be none.
It also never initializes the sTest pointer to point at some valid memory, so the results are totally undefined. This program invokes undefined behavior, and should/might/could crash when run.
IF the pointer had been initialized to point at a valid object of type struct test, the fields of that structure would have been changed so that at the end of main(), ID would be 3. The changes done inside changePointer() are done on the same memory as the changes done in main().
An easy fix would be:
int main(void)
{
struct test aTest;
sTest = &aTest; /* Notice the ampersand! */
sTest->start = true;
changePointer(sTest);
return 0;
}
Also note that C before C99 doesn't have a true keyword.

The only question is why do you need a test pointer in a global name space? Second is that you do not have any memory allocation operations. And you have a pointer as an input parameter of your function. Therefore structure where it points to will be changed in "changePointer".

1) First thing your code will crash since you are not allocating memory for saving structure.. you might need to add
sText = malloc(sizeof(struct test));
2) After correcting the crash, you can pass structure pointer and the changes you make in changePointer function will reflect in main and vizeversa..
3) But since you are not printing anything, there wont be any output to your program..

Related

Passing struct pointer to two functions and then calling malloc

I have a struct in my main function. I pass that pointer to another function which does some stuff and if conditions are met, it passes it to another function to get filled out. When returning to the main function the t struct contains none of the data mydata that was copied into it.
typedef struct _t {
int one;
int two;
int three;
int four;
} T;
void second(T *t) {
t = malloc(20);
memcpy(t, mydata, 20);
}
void first(T *t) {
second(t);
}
int main() {
T t;
first(t);
}
Do I need to be working with double pointers here? If the address of t was 0x1000 and I passed it to first() then wouldn't referencing t just be 0x1000? And same as if I pass the pointer to second()?
In this answer, I assume that, for reasons not shown, you do in fact need to make a dynamic memory allocation. If that is not the case, the only changes that need to be made are replacing first(t); with first(&t);, and removing t = malloc(20);.
The first problem to fix is that t in main should have the type T *, not T. You are making a dynamic memory allocation, and seem to want to store that pointer in t, so you would need: T *t;.
The second problem is that you want to manipulate the value of t in main, but are passing it by value to first. Instead, you need to pass a pointer to t into first: first(&t);.
Fixing both of these, you now pass a pointer to a pointer to T (the type of &t) into first and second, so you need to change their signatures to be, respectively, void first(T **t) and void second(T **t).
Applying both changes, as well as making some small style tweaks, we get:
typedef struct T {
int one;
int two;
int three;
int four;
} T;
void second(T **t_ptr) {
*t_ptr = malloc(20);
memcpy(*t_ptr, mydata, 20);
}
void first(T **t_ptr) {
second(t_ptr);
}
int main() {
T *t;
first(&t);
}
Another thing that's missing, and needs to be added, is checking for the success of malloc, but I haven't added that to the above code.
Also, what you've shown in the question shouldn't compile; you're passing a struct to a function that accepts a pointer.
Your problems are common to new C developers. And actually you have two of them.
The first problem is that you pass your structure by value.
The first function is declared to receive a pointer to T but you pass t and not &t (which is the address of t - and this is what you want when a function accepts a pointer).
However there is still another problem so that even if you change your code as suggested above it will still not work correctly. second allocates memory using malloc. The function receives T as a pointer T *t. You assign the output of malloc to t in effect overwriting what t points to (and if t was previously allocated you will leak memory here).
Bellow you can see a correct code for what you want.
typedef struct _t {
int one;
int two;
int three;
int four;
} T;
/* Make sure we have some data to initialize */
T mydata = {0};
/*
We take a pointer to a pointer and change what the external pointer points to. */
In our example when this function is called *ppt is NULL
and t is a pointer to t in main()
*/
void second(T **ppt) {
/*
We never calculate the size of structures by hand. It can change depending on
OS and architecture. Best let the compiler do the work.
*/
*ppt = (T*)malloc(sizeof(T));
memcpy(*ppt, &mydata, sizeof(T));
}
void first(T **ppt) {
/* Make sure we don't leave dangling pointers. */
if (NULL != *ppt)
free(*ppt);
second(ppt);
}
int main() {
T *t = NULL; /* A pointer to our data */
/*
We pass a pointer to our pointer so that the function can change the value it
holds
*/
first(&t);
/* Always do an explicit return if the type of the function is not void */
return 0;
}
How to understand what is going on:
First we declare t as a pointer to a memory holding a type T and we make sure we initialize the pointer to point to NULL (which is a convention meaning that the pointer is not initialized).
We have a function that will allocate the memory for us using malloc. malloc allocates memory from the heap and returns the address of that memory. (In reality a pointer is just a variable holding an address in memory). We want to place that address in t declared in main(). To do so we need to pass to the allocating function the address of t so it can be modified. To do this we use the address of operator - &. This is why we call the function like this first(&t).
Our allocating function accepts a pointer to a pointer. This is because we want to change the address t points to. So we declared the parameter as T **ppt. It holds the address of the pointer *t in main. In the function we dereference the pointer to the pointer to get the original pointer we want to assign the address malloc returns.

Valgrind + C: Handling uninitialized pointers without error

Maybe I got too involved with testing my assignment, but here's my dilemma:
This is my offending function (more or less):
struct thing{
char* data;
}
int function(struct thing* arg){
if(arg->data == NULL)
return -1;
}
This is my offending input:
struct thing *x = malloc(sizeof(struct thing));
function(x);
And valgrind outputs this when I test it:
Conditional jump or move depends on uninitialised value(s)
I'm about 99% sure that this is because valgrind has an issue with evaluating x->data when it hasn't been initialized to NULL or malloced. Is there a workaround for this?
To my opinion valgrind is right in complaining here because data is in fact not initialized and function is not able to determine if it was. The function can only check if it has the defined value you used for initialization.
So I would consider using a creation function that does the initialization as well. This way you could also allocate the memory for data right away when passing its size as parameter (or just NULL if you want to do that later).
struct thing *newThing(size_t dataSize)
{
struct thing *t = malloc(sizeof (struct thing));
if (t)
t->data = malloc(sizeof(char) * dataSize);
// or t->data = NULL if it should be done later
return t;
}
You are defining a function like this:
int function(struct thing *arg) {
if (arg->data == NULL) {
// abort here
return 1;
} else {
// use the value here
return 0;
}
}
Here, Valgrind is right about complaining, because it's impossible to achieve the intended behavior for function(). If arg->data is not explicitly initialized, then its value is indeterminate, and the if statement could execute any of the two branches depending on whichever random value it reads from arg->data.
In general, it's impossible for the function to work correctly, because:
If the check arg->data == NULL fails, the rest of the code will assume that arg->data is not NULL and therefore use the invalid value, most likely causing a crash or other kind of problem.
If the check arg->data == NULL passes, the rest of the code will wrongfully assume that the data is known to be invalid, and do any other kind of thing assuming that data was intended to be NULL, like for example call some cleanup code at the wrong time.
Other than this, if you really want to be pedantic, reading uninitialized variables is actually undefined behavior in C.
The right thing to do in your case is to either use calloc() instead of malloc() or to manually set x->data = NULL right after malloc().
The memory allocated by malloc is not initialized.
You need to set it to the know state:
struct thing *x = calloc(1,sizeof(*x));
or
struct thing *x = malloc(sizeof(*x));
memset(x, 0, sizeof(*x);
you can also of course just assign some values to the struct members,
struct thing *x = malloc(sizeof(*x));
x -> data = NULL;

C structure initialization before using it?

I do not understand why i have to initialize my structure before using it, i get this error in my code, i know it works if i use pointers or if i initialize the structure members, but why it does not work in this way ?
#include <stdio.h>
typedef struct human{
char name[20];
int age;
} student;
void function(student ){
printf("It's not working");
}
int main(){
student a;
function(a);
return 0;
}
I get this
Debug Error!
File: Run - Time Check Failure #3 - The variable 'a' is being used without being initialized. (Press Retry to debug the application)
and i do not get the message from my function on output
You get this error, because your debugger detect, that you are sending unitialized variable to the function. It doesn't know, what will you do with it inside of the function, so it warns you. You can see, that if you run program in release, no error will occur. Easiest solution for you, if you know, that you will initialize it lately to correct values, is just to initialize it, when creating student a = {0};
You are passing the object a by value to function. As C has only value-semantics, it can only copy values in this case. So, you initialise the parameter (even if your implementation doesn't care about the parameter) with an unitialised object, wich requires reading from that object. This is undefined behaviour, hence the compiler informs you that you are doing something illegal.
If you pass the object via a pointer, you still pass-by-value, but the value being copied is the pointer. Hence you don't have to read the actual value and your compiler wont complain.
Observe:
void flat(student s) {
s.age = 20;
}
void ptr(student* s) {
s->age = 20;
}
int main() {
student s = {"Eve", 0};
// { s.age == 0 }
flat(s);
// { s.age == 0 } --- still the same, no change
ptr(&s);
// { s.age == 20 } --- now it has changed
}

why can't i free the memory?

I wrote a simple counter structure in C:
typedef struct{
int value;
}Counter;
then, I wrote some simple implementations:
void createCounter(Counter *dCount)
{
dCount = (Counter*)malloc(sizeof(Counter));
dCount->value = 0;
}
void FreeResource(Counter *dCount)
{
free(dCount);
}
now in the main, i wanted to free the pointer i created and it complained that the pointer being freed was not allocated.I am looking at the code and I thought I allocated memory for it when I called the createCounter() function?
int main()
{
Counter m;
CreateCounter(&m);
FreeResource(&m); //run time error given here..
return 0;
}
You are trying to pass the address of a variable allocated in stack and then trying to assign an address allocated by malloc to it which won't get reflected in the caller. So, when you try to free it, you are effectively passing a stack variable's address to free due to which you get undefined behavior.
Change the function
void createCounter(Counter *dCount)
{
dCount = (Counter*)malloc(sizeof(Counter));
dCount->value = 0;
}
as
void createCounter(Counter **dCount)
{
*dCount = (Counter*)malloc(sizeof(Counter));
(*dCount)->value = 0;
}
In your case, the pointer gets passed by value and the new memory address allocation doesn't reflect in the caller.
The main function must be changed as:
int main()
{
Counter *m;
CreateCounter(&m);
FreeResource(m); //run time error given here..
return 0;
}
dCount = (Counter*)malloc(sizeof(Counter));
There are multiple problems:
dCount = ... has absolutely no effect for the caller., i.e. the pointer is unchanged.
You passed a pointer to an already allocated structure, you don't need to malloc anything
You're trying to free something (&m) you didn't obtain from malloc
The only sane suggestion at this point is to review a chapter on pointers.
The problem is that in CreateCounter the variable dCount is a local variable. That means changes to the variable won't be visible when the function returns.
There are two common solutions to this:
Return the pointer:
Counter *CreateCounter()
{
Counter *dCounter = malloc(sizeof(Counter));
dCounter->value = 0;
return dCounter;
}
Pass the argument as a reference, i.e. a pointer to the pointer:
void CreateCounter(Counter **dCounter)
{
*dCounter = malloc(sizeof(Counter);
(*dCounter)->value = 0;
}
And call it as this:
Counter *m;
CreateCounter(&m);

Confused about accessing struct members via a pointer

I'm new to C, and am confused by results I'm getting when referencing a member of a struct via a pointer. See the following code for an example. What's happening when I reference tst->number the first time? What fundamental thing am I missing here?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int number;
} Test;
Test* Test_New(Test t,int number) {
t.number = number;
return &t;
}
int main(int argc, char** argv) {
Test test;
Test *tst = Test_New(test,10);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
}
The output is:
Test.number = 10
Test.number = 4206602
Test.number = 4206602
When you pass test into your Test_New function, you are passing it by value and so a local copy is made on the stack for the function scope of your Test_New function. Since you return the address of the variable, once the function returns the stack is useless but you've returned a pointer to a struct on the old stack! So you can see that your first call returns the correct value since nothing has overwritten your stack value but the subsequent calls (which all use the stack) overwrite your value and give you erroneous results.
To do this correctly rewrite your Test_New function to take a pointer and pass the pointer to the struct into the function.
Test* Test_New(Test * t,int number) {
t->number = number;
return t;
}
int main(int argc, char ** argv) {
Test test;
Test * tst = Test_New(&test,10);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
printf("Test.number = %d\n",tst->number);
}
Independent of struct, it is always incorrect to return the address of a local variable. It is usually also incorrect to put the address of a local variable into a global variable or to store it in an object allocated on the heap with malloc. Generally if you need to return a pointer to an object, you'll need either to get someone else to provide the pointer for you, or else you'll need to allocate space with malloc, which will return a pointer. In that case, part of the API for your function must specify who is responsible for calling free when the object is no longer needed.
You are returning the address of t as declared in the method Test_New, not the address of test that you passed into the method. That is, test is being passed by value and you should instead pass a pointer to it.
So, here is what happens when you call Test_New. A new Test struct named t is created and t.number is set to be equal to the value of test.number (which you had not initialized). Then you set t.number equal to the parameter number that you passed to the method, and then you return the address of t. But t is a local variable and goes out of scope as soon as the method ends. Thus, you are returning a pointer to data that no longer exists and that is why you are ending up with garbage.
Change the declaration of Test_New to
Test* Test_New(Test* t,int number) {
t->number = number;
return t;
}
and call it via
Test *tst = Test_New(&test,10);
and all will go as you are expecting.
Just to extend BlodBath's answer, think about what happens in memory when you do this.
As you enter your main routine, a new automatic Test struct is created -- on the stack, since it's auto. So your stack looks something like
| return address for main | will be used at bottom
| argc | copied onto stack from environment
| argv address | copied onto stack from environment
-> | test.number | created by definition Test test;
with -> indicating the stack pointer to the last used element of the stack.
Now you call Test_new(), and it updates the stack like this:
| return address for main | will be used at bottom
| argc | copied onto stack from environment
| argv address | copied onto stack from environment
| test.number | created by definition Test test;
| return addr for Test_new| used to return at bottom
| copy of test.number | copied into the stack because C ALWAYS uses call by value
-> | 10 | copied onto stack
When you return &t, which address are you getting? Answer: the address of the data ON THE STACK. BUT THEN you return, the stack pointer is decremented. When you call printf, those words on the stack are re-used, but your address is still poiting to them. It happens that what the number in that location in the stack, interpreted as an address, points to has the value 4206602, but that's pure chance; in fact, it was kind of bad luck, as good luck would have been something that caused a segmentation fault, letting you know something was actually broken.
The problem is that you are not passing a reference into Test_New, you are passing a value. Then, you're returning the memory location of the local variable. Consider this code which demonstrates your problem:
#include <stdio.h>
typedef struct {
} Test;
void print_pass_by_value_memory(Test t) {
printf("%p\n", &t);
}
int main(int argc, char** argv) {
Test test;
printf("%p\n", &test);
print_pass_by_value_memory(test);
return 0;
}
The output of this program on my machine is:
0xbfffe970
0xbfffe950
Test t declared in Test_New() is a local variable. You are trying to return the address of a local variable. As the local variable gets destroyed once the function exists, the memory will be freed meaning, the compiler is free to put some other value in the location where your local variable was kept.
In your program when you are trying to access the value the second time, the memory location might have got assigned to a different variable or process. Hence you are getting the wrong output.
A better option for you will be to pass the structure from main() by reference rather than by value.
You've passed the contents of test by value to Test_New. IOW a new copy of a Test structure has been allocated on the stack when you called Test_New. It is the address of this Test that you return from the function.
When you use tst->number the first time the value of 10 is retrieved because although that stack has be unwound no other use of that memory has been made. However as soon as that first printf has been called the stack memory is reused for whatever it needs, but tst is still pointing to that memory. Hence subsquent uses of tst->number retrieve whatever printf left there in that memory.
Use Test &t in the function signature instead.
You could do something like this to make it a little easier:
typedef struct test {
int number;
} test_t;
test_t * Test_New(int num)
{
struct test *ptr;
ptr = (void *) malloc(sizeof(struct test));
if (! ptr) {
printf("Out of memory!\n");
return (void *) NULL;
}
ptr->number = num;
return ptr;
}
void cleanup(test_t *ptr)
{
if (ptr)
free(ptr);
}
....
int main(void)
{
test_t *test, *test1, *test2;
test = Test_New(10);
test1 = Test_New(20);
test2 = Test_new(30);
printf(
"Test (number) = %d\n"
"Test1 (number) = %d\n"
"Test2 (number) = %d\n",
test->number, test1->number, test2->number);
....
cleanup(test1);
cleanup(test2);
cleanup(test3);
return 0;
}
... As you can see, its easy to allocate room for several completely different instances of test_t, for instance if you need to save the existing state of one so you can revert later .. or for whatever reason.
Unless, of course there is some reason why you must keep it local .. but I really can't think of one.

Resources