This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 5 years ago.
I am learning structures and linked-lists. However I am facing a problem that prevents me from debugging my program's bugs, since it comes, seemingly, from the function printf, which is what I use to debug the program.
The following program works fine:
struct pointer_struct
{
struct new_struct *ptr;
};
struct new_struct
{
int i;
struct new_struct *ptr;
};
void init(struct pointer_struct *pointer, int nb)
{
struct new_struct my_struct;
my_struct.i = nb;
my_struct.ptr = NULL;
pointer->ptr = &my_struct;
}
int main(void)
{
struct pointer_struct pointer;
pointer.ptr = NULL;
init(&pointer, 15);
//printf("pointer.ptr = %p\n", pointer.ptr);
printf("pointer.ptr->i = %d\n", pointer.ptr->i);
}
Output:
pointer.ptr->i = 15
But as soon as I uncomment the commented line, i takes weird values. Here are some examples of outputs:
$./a.out
pointer.ptr = 0x7fffc6bcc650
pointer.ptr->i = -448723664
$./a.out
pointer.ptr = 0x7fffd09ed480
pointer.ptr->i = 1218512176
$./a.out
pointer.ptr = 0x7ffff630fa70
pointer.ptr->i = -1073674960
What is going wrong with printf?
You have an undefined behavior or UB, which is always A Bad Thing™.
void init(struct pointer_struct *pointer, int nb)
{
struct new_struct my_struct;
my_struct.i = nb;
my_struct.ptr = NULL;
pointer->ptr = &my_struct;
} // here my_struct lifetime is finish so pointer->ptr become invalid
int main(void)
{
struct pointer_struct pointer;
pointer.ptr = NULL;
init(&pointer, 15);
printf("pointer.ptr = %p\n", pointer.ptr); // pointer.ptr is not valid so it's UB
printf("pointer.ptr->i = %d\n", pointer.ptr->i); // This is UB too
}
You initialize pointer.ptr with a local variable.
void init(struct pointer_struct *pointer, int nb)
{
struct new_struct my_struct;
my_struct.i = nb;
my_struct.ptr = NULL;
pointer->ptr = &my_struct; // MISTAKE!!! my_struct is on the stack.
// its memory space could be overwritten at
// any time after the function returns.
}
Later, in main
printf("pointer.ptr = %p\n", pointer.ptr); // This call to printf uses the stack,
// and overwrites the space used
// by my_struct
printf("pointer.ptr->i = %d\n", pointer.ptr->i);
Related
If I want to create a structure initialization functions that return a pointer to the initialized structure members, will the allocated memory to the data array in new_foo still be valid outside the function?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct structure{
char* data;
size_t num;
}foo_t;
foo_t* new_foo(size_t num);
int main(void){
foo_t* foo = new_foo(32);
while(1){;}
}
foo_t* new_foo(size_t num){
foo_t* self;
char temp[num];
self->data = temp;
self->num = num;
return self;
}
I wanted to take a look at the assembly code to see if anything jumped out at me, the only thing that potentially makes me thing memory is still valid is that there are no stack operations associated with
char temp[num];
self->data = temp;
but it's been a while since I had to look at assembly code.
https://godbolt.org/z/5Wx4TY
[EDIT] Modified new_foo
foo_t* new_foo(size_t num){
static foo_t self = {NULL, 0};
char data_array[num];
self.data = temp;
self.num = num;
return &self;
}
The function has undefined behavior.
foo_t* new_foo(size_t num){
foo_t* self;
char temp[num];
self->data = temp;
self->num = num;
return self;
}
For starters the pointer self is not initialized and has indeterminate value.
The variable length array temp is a local variable of the function that will not be alive after exiting the function. So any pointer to it returned from the function will be invalid.
Bug:
While passing a double pointer to a function the value of the fields that the pointer is pointing to seems to be dependent on some local variable of the function.
More specifically when I comment the line L(in the function "function")Output:
In the main function: 1
In the function: 1
But when I uncomment the same line,
Output:
In the main function: 1
In the function: 0
program:
typedef struct s{
int *value;
}s;
s** initialize()
{
s** temp = (s**)malloc(sizeof(s*));
s* f = (s*)malloc(sizeof(s));
f->value = NULL;
temp = &f;
return temp;
}
void function(s** what)
{
//Line L: size_t count = 0;
printf("In the function: %d\n", (*what)->value == NULL);
}
int main()
{
s** m = initialize();
printf("In the main function: %d\n", (*m)->value == NULL);
function(m);
}
What I have tried:
I thought that I am getting random outputs, but that was not the case as I am consistently getting the same output.
I tried deciphering the assembly language code but that was too cryptic for me.
Environment:
compiler: gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
operating system: linux mint
Here:
s** initialize()
{
s** temp = (s**)malloc(sizeof(s*));
s* f = (s*)malloc(sizeof(s));
f->value = NULL;
temp = &f; // temp is now the address of a local variable
return temp; // now temp is returned
// that's undefined behavior when the returned
// pointer is used
}
The variable f doesn't exist when the initialize function returns, so you are returning the address of a non-existing variable. Using the address will be undefined behavior, i.e. anything can happen and there is no way in general to explain it.
On a specific system, we can do some guessing. My guess is that once you add the line with a new variable, it overwrites the memory location where f used to be stored. Without the new variable the location where f used to be stored is still the same.
The function initialize
s** initialize()
{
s** temp = (s**)malloc(sizeof(s*));
s* f = (s*)malloc(sizeof(s));
f->value = NULL;
temp = &f;
return temp;
}
can invoke undefined behavior because it returns pointer to a local variable. And moreover it has a memory leak.
At first a memory was allocated and its address was assigned to the variable temp
s** temp = (s**)malloc(sizeof(s*));
Then the pointer was reassigned
temp = &f;
So the allocated memory is not freed.
The pointer is assigned by the address of a local variable
s* f = (s*)malloc(sizeof(s));
//...
temp = &f;
After exiting the function the variable f will not alive. So the pointer temp has an invalid value.
It seems what you mean is the following
s** initialize()
{
s** temp = (s**)malloc(sizeof(s*));
s* f = (s*)malloc(sizeof(s));
f->value = NULL;
*temp = f;
return temp;
}
If to make the changes you will get the expected result.
#include <stdio.h>
#include <stdlib.h>
typedef struct s{
int *value;
}s;
s** initialize()
{
s** temp = (s**)malloc(sizeof(s*));
s* f = (s*)malloc(sizeof(s));
f->value = NULL;
*temp = f;
return temp;
}
void function(s** what)
{
//Line L: size_t count = 0;
printf("In the function: %d\n", (*what)->value == NULL);
}
int main( void )
{
s** m = initialize();
printf("In the main function: %d\n", (*m)->value == NULL);
function(m);
free( *m );
free( m );
}
The program output is
In the main function: 1
In the function: 1
I'm trying to call queue_t from my main function in order to give queue_t the size which I then intend to print out for test purpose .
Why does it say that my q is not initialized when I did in line 21 ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct queue_t {
char *name;
int size;
int entries;
double time;
struct packet_t **packets;
int read;
int write;
long lost;
};
struct queue_t *queue_create (char *name, int size) {
int i;
struct queue_t *q;
q->size = size;
q->name = name;
printf("Name of queue: %s", q->name);
printf("Size of queue: %d", q->size);
return (q);
}
int main () {
char *a = "Test";
int size = 80;
queue_create(a, size);
}
struct queue_t *q;
q->size = size;
The pointer q is clearly uninitialized here. And then you use it in q->size. You should assign/initialize a variable before using, ie. q = something;. Using an uninitialized pointer value might be undefined behavior.
You can:
struct queue_t *q = malloc(sizeof(*q));
if (q == NULL) { fprintf(stderr, "ERROR! malloc!\n"); abort(); }
q->size = size;
q is clearly assigned a value here, ie. the result of malloc() call. It allocates the memory for the queue_t on the heap. Remember to free() the pointer so that your program does not leak memory.
You also can allocate the memory for variable on the stack:
struct queue_t q_memory;
struct queue_t *q = &q_memory;
q->size = size;
But note that in this case the memory will be invalid after closing the block it was declared in, ie. after the }! So don't use it, if you want to return it from a function.
I am trying to play around with structures in C and I am stuck at this point. Here's my code:
#include <stdio.h>
void Test(void);
void updateIt(struct Item* ptr);
struct Item
{
double value;
int unitno;
int isTa;
int quant;
int minQuant;
char name[21];
};
int main(void)
{
Test(); // here I am gonna call updateit() function and print
}
void Test(void) {
struct Item I = { 100.10,100,10,110,10,"NAME!" };
updateIt(&I);
}
void updateIt(struct Item* ptr){
struct Item I[0] = 200 // This doesn't work — but why?
}
How do I update values of Item I = { 100.10,100,10,110,10,"NAME!" } to { 200.20,200,20,220,20,"NAME2!"} by accessing values inside the updateIt function?
In the code snippet:
void updateIt(struct Item* ptr){
struct Item I[0] = 200 // This doesn't work — but why?
}
There is no variable I in this scope.
Since you passed the address of the structure through updateIt(&I); in the above function you will have to use the pointer to it.
The pointer variable ptr in the arguments of the function has the address of the structure, which can be used to update the values as :
ptr->structureMember
where structureMember is any member of the structure.
updateIt(struct Item* ptr) accepts pointer ptr of type item; to access fields of structure Item using a pointer, one should use -> operator like below:
void updateIt(struct Item* ptr){
ptr->value = 200.20;
ptr->unitno = 200;
ptr->isTa = 20;
ptr->quant = 220;
ptr->minQuant = 20;
strcpy(ptr->name, "NAME2");
}
You must use the ptr value like
ptr->unitno = 200 and so for every member of the struct
This question already has answers here:
Can someone help what is incorrect in this program? [duplicate]
(2 answers)
Closed 8 years ago.
I make a struct array in C and i want to initialize it in a void function. If i use return function it's well but if i use void function i have some problems.
Here is my code
#include <stdio.h>
#include <stdlib.h>
typedef struct Essai{
char *nom;
struct Essai* next;
} Essai;
void initialise(Essai* essai){
struct Essai *newE = malloc(sizeof(Essai));
newE->next = NULL;
printf("What's your name ? ");
scanf("%s", newE->nom);
if(essai != NULL){
essai = newE;
}else{
struct Essai* temp = essai;
while(temp->next != NULL) temp = temp->next;
temp->next = newE;
}
}
int main()
{
Essai *var = NULL;
initialise(var);
printf("nom : %s", var->nom);
return 0;
}
In the function essai is well created but outside the function it become NULL.
Remember that arguments to functions are passed by value, meaning that they are copied and the function only modifies the copy.
To make changes inside the function which is visible when the function returns, you need to emulate "call by reference", by passing a pointer. This includes passing pointers as pointer-to-pointer:
void initialise(Essai** essai){
...
*essai = newE;
...
}
int main(void)
{
Essai *var = NULL;
initialise(&var);
...
}
Another solution is to return the pointer from the function:
Essai *initialise(Essai* essai){
...
return essai;
}
int main(void)
{
Essai *var = NULL;
var = initialise(var);
...
}