C language: why do these two printf statements print different things - c

#include <stdio.h>
typedef struct {
int data;
char * string;
}Node;
Node * init(){
Node node;
node.data = 5;
node.string = "hello";
Node * point = &node;
return point;
}
int main() {
Node * test = init();
printf("%d\n", test->data);
printf("%d", test->data);
}
Why do the last two printf statements produce different results. I suspect is has something to do with how I assigned my test pointer, but I don't know how to fix it.

In your case, node is a variable local to the function init() and yet, you return the address of this. So, once the function is returned, there's no existence of node anymore.
After the function returns accessing the return value is accessing invalid memory which causes undefined behavior.
You can, however, return the structure variable itself, not a pointer to it and collect the return value in the caller in another variable, it'll work out.

Yes, your code has undefined behavior on account of returning a pointer to a function local object. But it seems your approach is misguided to begin with. Your init function is supposed to initialize a structure with a proper initial value, there's no need to return a pointer to do this. You have three options:
Return by value, like another answer suggested.
Pass the address of a structure for the function to initialize. This frees up the return value, so you can signal success or failure:
bool init(Node *node) { // must include stdbool.h
if(!node)
return false;
node->data = 5;
node->string = "hello";
return true;
}
//...
Node test;
if(!init(&test)) {
//failed to initialize, handle the error
}
Forgo the function entirely and supply a macro that stands for the nodes initial value:
#define NODE_INIT_VAL { \
.data = 5, .string = "hello", \
}
This allows you to simply write Node test = NODE_INIT_VAL;. It's also how you'd prefer to initialize any objects with static storage duration.

node is defined as local variable in the function init() so it's memory is freed after the function returns.
You should either define node as global variable (I don't like globals :-)) or allocate memory by calling malloc.
node = malloc(sizeof(Node));
Don't forget to free the memory if you no longer need node.

Update init() to return struct:
Node init(){
Node node;
node.data = 5;
node.string = "hello";
return node;
}
then access it like the following :
Node testNode = init();
printf("%d\n", testNode.data);
printf("%d", testNode.data);
Or if you want to use pointer like this :
Node testNode = init();
Node* pointerToNode = &testNode;
printf("%d\n", pointerToNode->data);
printf("%d", pointerToNode->data);
And the reason for this is as #Sourav answered that the data will be no longer valid.
Hope this is useful.

Related

Scope of a struct variable created in main() and a user-defined function?

typedef struct node {
int data;
struct node *next;
} Node;
void checkEmpty(Node *list) {
printf(list == NULL ? "true" : "false");
}
The first time, I created the main() function, made a list directly in it, and called checkEmpty(). It printed true.
int main() {
Node *list;
checkEmpty(list); // it return true
return 0;
}
Then, I created a new function menu(), created a list inside it, and called checkEmpty(). It printed false.
void menu() {
Node *list;
checkEmpty(list);
}
int main() {
menu(); // it return false
return 0;
}
Why does this happen?
The declaration Node *list inside a function does not initialize list. Its value is indeterminate, meaning it does not have to behave as if it has any fixed value at all. The compiler may generate code that uses a different value for it each time it is used, such as reading from memory on one occasion or using a value from a processor register on another.
To fix your program, give list an initial value with Node *list = 0; or Node *list = NULL.
Also turn on compiler warnings and elevate warnings to errors. Check your compiler documentation for the switches to do that. Also pay attention to compiler warning and error messages.
You have a pointer of type Node that is currently not pointing to any memory specifically. However, there can already be junk data stored into the memory block of the pointer so that technically it's not pointing to NULL and it is pointing to something. The first time you created a pointer, could've been by chance that it's already NULL in the memory block.
So,if you do declare the pointer, it is always good practice to have the pointer point to NULL first.
Node *list = NULL;

I can alter a struct member from one location but not from the other

I am trying to implement a linked list in C - starting simple, with one list containing one node. However, I stumble upon some issues when trying to add data to the node. Here's my implementation thus far:
struct mylist_node {
int data;
};
struct mylist {
struct mylist_node *head_pt;
};
void mylist_init(struct mylist* l){
struct mylist_node head_node;
head_node.data = 5; //First try
l->head_pt = &head_node;
l->head_pt->data = 5; //Second try
};
And my main method:
int main()
{
struct mylist ml, *ml_pointer;
ml_pointer = &ml;
mylist_init(ml_pointer);
printf("%d\n", ml_pointer->head_pt->data);
ml_pointer->head_pt->data = 4;
printf("%d\n", ml_pointer->head_pt->data);
return 0;
}
This should print out
5
4
If my knowledge of pointers is correct. However, it prints out
0
4
As you can see I try to set the node data twice within the mylist_init method. Neither appears to be working - meanwhile, writing to and reading from it from my main method works just fine. What am I doing wrong?
In mylist_init, you're storing the address of a local variable in the struct pointed to by l. That variable goes out of scope when the function returns, so the memory it occupied is no longer valid, and thus the pointer that previously pointed to it now points to an invalid location. Returning the address of a local variable a dereferencing that address invokes undefined behavior.
Your function needs to allocate memory dynamically using malloc so the memory will still be valid when the function returns.
void mylist_init(struct mylist* l){
struct mylist_node *head_node = malloc(sizeof(*head_node));
l->head_pt = head_node;
l->head_pt->data = 5;
};
Also, don't forget to free the memory when you're done using it.
For starters, you have to allocate memory for your node, the way you were doing it, your node is a local variable on the stack which will likely get overwritten after the function exits.
void mylist_init(struct mylist* l)
{
struct mylist_node *head_node = (struct mylist_node *)malloc(sizeof(struct mylist_node));
head_node.data = 5; //First try
l->head_pt = head_node;
};

Malloc function in dynamic lists

I'm getting started with dynamic lists and i don't understand why it is necessary to use the malloc function even when declaring the first node in the main() program, the piece of code below should just print the data contained in the first node but if i don't initialize the node with the malloc function it just doesn't work:
struct node{
int data;
struct node* next;
};
void insert(int val, struct node*);
int main() {
struct node* head ;
head->data = 2;
printf("%d \n", head->data);
}
You don’t technically, but maintaining all nodes with the same memory pattern is only an advantage to you, with no real disadvantages.
Just assume that all nodes are stored in the dynamic memory.
Your “insert” procedure would be better named something like “add” or (for full functional context) “cons”, and it should return the new node:
struct node* cons(int val, struct node* next)
{
struct node* this = (struct node*)malloc( sizeof struct node );
if (!this) return next; // or some other error condition!
this->data = val;
this->next = next;
return this;
}
Building lists is now very easy:
int main()
{
struct node* xs = cons( 2, cons( 3, cons( 5, cons( 7, NULL ) ) ) );
// You now have a list of the first four prime numbers.
And it is easy to handle them.
// Let’s print them!
{
struct node* p = xs;
while (p)
{
printf( "%d ", p->data );
p = p->next;
}
printf( "\n" );
}
// Let’s get the length!
int length = 0;
{
struct node* p = xs;
while (p)
{
length += 1;
p = p->next;
}
}
printf( "xs is %d elements long.\n", length );
By the way, you should try to be as consistent as possible when naming things. You have named the node data “data” but the constructor’s argument calls it “val”. You should pick one and stick to it.
Also, it is common to:
typedef struct node node;
Now in every place except inside the definition of struct node you can just use the word node.
Oh, and I almost forgot: Don’t forget to clean up with a proper destructor.
node* destroy( node* root )
{
if (!root) return NULL;
destroy( root->next );
free( root );
return NULL;
}
And an addendum to main():
int main()
{
node* xs = ...
...
xs = destroy( xs );
}
When you declare a variable, you define the type of the variable, then it's
name and optionally you declare it's initial value.
Every type needs an specific amount of memory. For example int would be
32 bit long on a 32bit OS, 8 bit long on a 64.
A variable declared in a function is usually stored in the stack associated
with the function. When the function returns, the stack for that function is
no longer available and the variable does not longer exist.
When you need the value/object of the variable to exist even after a function
returns, then you need to allocate memory on a different part of the program,
usually the heap. That's exactly what malloc, realloc and calloc do.
Doing
struct node* head ;
head->data = 2;
is just wrong. You've declaring a pointer named head of type struct node,
but you are not assigning anything to it. So it points to an unspecified
location in memory. head->data = 2 tries to store a value at an unspecified
location and the program will most likely crash with a segfault.
In main you could do this:
int main(void)
{
struct node head;
head.data = 2;
printf("%d \n", head.data);
return 0;
}
head will be saved in the stack and will persist as long as main doesn't
return. But this is only a very small example. In a complex program where you
have many more variables, objects, etc. it's a bad idea to simply declare all
variables you need in main. So it's best that objects get created when they
are needed.
For example you could have a function that creates the object and another one
that calls create_node and uses that object.
struct node *create_node(int data)
{
struct node *head = malloc(sizeof *head);
if(head == NULL)
return NULL; // no more memory left
head->data = data;
head->next = NULL;
return head;
}
struct node *foo(void)
{
struct node *head = create_node(112);
// do somethig with head
return head;
}
Here create_node uses malloc to allocate memory for one struct node
object, initializes the object with some values and returns a pointer to that memory location.
foo calls create_node and does something with it and it returns the
object. If another function calls foo, this function will get the object.
There are also other reasons for malloc. Consider this code:
void foo(void)
{
int numbers[4] = { 1, 3, 5, 7 };
...
}
In this case you know that you will need 4 integers. But sometimes you need an
array where the number of elements is only known during runtime, for example
because it depends on some user input. For this you can also use malloc.
void foo(int size)
{
int *numbers = malloc(size * sizeof *numbers);
// now you have "size" elements
...
free(numbers); // freeing memory
}
When you use malloc, realloc, calloc, you'll need to free the memory. If
your program does not need the memory anymore, you have to use free (like in
the last example. Note that for simplicity I omitted the use of free in the
examples with struct head.
What you have invokes undefined behavior because you don't really have a node,, you have a pointer to a node that doesn't actually point to a node. Using malloc and friends creates a memory region where an actual node object can reside, and where a node pointer can point to.
In your code, struct node* head is a pointer that points to nowhere, and dereferencing it as you have done is undefined behavior (which can commonly cause a segfault). You must point head to a valid struct node before you can safely dereference it. One way is like this:
int main() {
struct node* head;
struct node myNode;
head = &myNode; // assigning the address of myNode to head, now head points somewhere
head->data = 2; // this is legal
printf("%d \n", head->data); // will print 2
}
But in the above example, myNode is a local variable, and will go out of scope as soon as the function exists (in this case main). As you say in your question, for linked lists you generally want to malloc the data so it can be used outside of the current scope.
int main() {
struct node* head = malloc(sizeof struct node);
if (head != NULL)
{
// we received a valid memory block, so we can safely dereference
// you should ALWAYS initialize/assign memory when you allocate it.
// malloc does not do this, but calloc does (initializes it to 0) if you want to use that
// you can use malloc and memset together.. in this case there's just
// two fields, so we can initialize via assignment.
head->data = 2;
head->next = NULL;
printf("%d \n", head->data);
// clean up memory when we're done using it
free(head);
}
else
{
// we were unable to obtain memory
fprintf(stderr, "Unable to allocate memory!\n");
}
return 0;
}
This is a very simple example. Normally for a linked list, you'll have insert function(s) (where the mallocing generally takes place and remove function(s) (where the freeing generally takes place. You'll at least have a head pointer that always points to the first item in the list, and for a double-linked list you'll want a tail pointer as well. There can also be print functions, deleteEntireList functions, etc. But one way or another, you must allocate space for an actual object. malloc is a way to do that so the validity of the memory persists throughout runtime of your program.
edit:
Incorrect. This absolutely applies to int and int*,, it applies to any object and pointer(s) to it. If you were to have the following:
int main() {
int* head;
*head = 2; // head uninitialized and unassigned, this is UB
printf("%d\n", *head); // UB again
return 0;
}
this is every bit of undefined behavior as you have in your OP. A pointer must point to something valid before you can dereference it. In the above code, head is uninitialized, it doesn't point to anything deterministically, and as soon as you do *head (whether to read or write), you're invoking undefined behavior. Just as with your struct node, you must do something like following to be correct:
int main() {
int myInt; // creates space for an actual int in automatic storage (most likely the stack)
int* head = &myInt; // now head points to a valid memory location, namely myInt
*head = 2; // now myInt == 2
printf("%d\n", *head); // prints 2
return 0;
}
or you can do
int main() {
int* head = malloc(sizeof int); // silly to malloc a single int, but this is for illustration purposes
if (head != NULL)
{
// space for an int was returned to us from the heap
*head = 2; // now the unnamed int that head points to is 2
printf("%d\n", *head); // prints out 2
// don't forget to clean up
free(head);
}
else
{
// handle error, print error message, etc
}
return 0;
}
These rules are true for any primitive type or data structure you're dealing with. Pointers must point to something, otherwise dereferencing them is undefined behavior, and you hope you get a segfault when that happens so you can track down the errors before your TA grades it or before the customer demo. Murphy's law dictates UB will always crash your code when it's being presented.
Statement struct node* head; defines a pointer to a node object, but not the node object itself. As you do not initialize the pointer (i.e. by letting it point to a node object created by, for example, a malloc-statement), dereferencing this pointer as you do with head->data yields undefined behaviour.
Two ways to overcome this, (1) either allocate memory dynamically - yielding an object with dynamic storage duration, or (2) define the object itself as an, for example, local variable with automatic storage duration:
(1) dynamic storage duration
int main() {
struct node* head = calloc(1, sizeof(struct node));
if (head) {
head->data = 2;
printf("%d \n", head->data);
free(head);
}
}
(2) automatic storage duration
int main() {
struct node head;
head.data = 2;
printf("%d \n", head.data);
}

How to free memory allocated to local static pointer

In legacy C code I have one pointer basically an array of size equal to one of enumerator and it is static in local scope. But now I have to remove that enumeration and now this static local array is giving error. I can convert that array to normal pointer and then allocate it dynamically but I am not sure how to do that. Below is sample code I have simplified from existing code base.
enum
{
E1,
E2,
EOL
};
void func
{
//static int array[EOL]; //-> that how it was earlier
static int *array = (int*)malloc(sizeof(int)*EOL); //Will this allocated memory only once
//or on every invokation.
free(array);//will it free the memory more than once?
}
Now I can move array pointer to global scope and then allocate it in main and free it in atexit functions but I want to keep changes minimum as I am not sure of impact it will have in shared projects?
Thanks
The malloc will occure only once.
1) You can use a static boolean to let you know if the pointer in the array variable can be free.
2) You can free the pointer then set it to NULL. The next occuration of the free will do nothing.
If you want to keep changes minimal then simply move the enumeration definition inside the function body before this static variable. Or you can use even an unnamed enum with one enumerator for the size of the array.
I do not understand your attempts to substitute the array for a dynamically allocated array.
Moreover at present C allows to use variable length arrays. So your could define the function such a way that it had a parameter that would specify the size of the local (non-static) array.
You can't initialise a static variable with something non const if you are using C.
If you are using C++, then the static pointer will only get a memory pointer allocated to it once.
I just solved the problem by using one function which basically is collects all memory allocated to local static pointers like above and then other functions free them during the end as it is registered using atexit function.
struct node
{
node *next;
void *content;
};
node* head = NULL, tail =NULL;
void addToList(void* ptr)
{
struct node* p = (struct node*)malloc(sizeof(struct node));
p->next = NULL;
p->conent = ptr;
tail->next = p;
tail = p;
return;
}
void freeList()
{
struct node* p = NULL, p1 = NULL;
for(p = head; p != NULL; p = p->next)
{
free(p1);
free(p->content);
p1 = p;
}
head = tail = NULL;
return;
}
/*
*/
void func
{
//static int array[EOL]; //-> that how it was earlier
static int *array = (int*)malloc(sizeof(int)*EOL); //Will this allocated memory only once
addToList(array); //or on every invokation.
free(array);//will it free the memory more than once?
}
As you can see it above code a linked list is created in separate .c file and using .map method head,tail and node will not be exposed to outside world only addToList and freeList will be visible. In every places just after doing a malloc I am calling addToList and then freeList will free up the memory.
Thanks

Values in array of structs turning into garbage values

I have an issue that's really confusing me... Below I am calling an initialize function:
void Initialize (List *L) {
char* initialize = "initialize";
int i;
for (i=0; i<MAXLISTSIZE; i++) {
strncpy(L->items[i].name,initialize,MAXNAMESIZE);
L->items[i].name[MAXNAMESIZE - 1] = '\0';
L->items[i].grade = 0;
printf("L->items[i].name = %s\n", L->items[i].name);
printf("L->items[i].grade = %d\n", L->items[i].grade);
}
L->count = 0;
}
And it seems to work, I print the values in the loop and it's fine. If I also print inside an identical loop in main to double check it works as well but If I just print the values in main after the initialize function (no print statements in Initialize) I get complete garbage.
It seems the memory I'm storing my values in isn't staying consistent and I can't figure out why.
Do I need to malloc memory for the structs? Since I don't need a variable amount of storage I thought it was not necessary... I am unsure of how to go about that.
My Structs:
typedef Student Item;
#define MAXLISTSIZE 4
typedef struct {
Item items[MAXLISTSIZE];
int count;
} List;
#define MAXNAMESIZE 20
typedef struct {
char name[MAXNAMESIZE];
int grade;
} Student;
I am simply calling Initialize from main:
int main () {
List *newList;
/*call initialize function*/
newList = callInitialize();
return 0;
}
callInitialize:
List *callInitialize () {
List *L;
List studentList;
L = &studentList;
Initialize(L);
return L;
}
Now that you posted the function that causes the actual problem, we see what's wrong: You are returning the address of a local variable that goes out of scope! This is not valid.
List * foo()
{
List x; // <--- x comes to life
return &x; // <--- x dies here...
}
int main()
{
List * p = foo(); // ... but its address is used here!
p->name ... // dereferencing an invalid address!!
}
Your situation calls for dynamic (or "manual") allocation, which means memory allocation whose lifetime is controlled only by you, and not by the local scope.
List * initList()
{
return malloc(sizeof(List)); // this memory is permanent
}
Any manual allocation needs to come with a clean-up routine:
void freeList(List * p)
{
free(p);
}
Now that you've posted the remainder of your code, the problem is obvious:
List *callInitialize () {
List *L;
List studentList;
L = &studentList;
Initialize(L);
return L;
}
Within this function you create a local variable studentList which you the pass to Initialize to set it up.
Unfortunately, the scope of the studentList variable ends when you exit the callInitialize function. That's why it may contain rubbish when you attempt to use it later on.
Despite your comment about not needing malloc because the structure is small, you do need it if you want the scope of the data to exist beyond the function it's created in.
Probably the "minimal-change" solution would be:
List *callInitialize (void) {
List *L = malloc (sizeof (List));
if (L != NULL)
Initialize(&L);
return L;
}
and then remember that it needs to be freed at some point by the caller, unless the malloc fails and this function therefore returns NULL.

Resources