Singly Linklist in C - c

This is my First post on StackOverFlow.
I was working on linklist - below is my code.
I am just adding a single node to list and printing it -- All I am doing is passing a pointer to the "addTermNode" function and then pointing this passed pointer to the newly created Node.
#include<stdio.h>
#include<time.h>
typedef struct _termination_code_ {
int terminationCode;
unsigned long time;
struct _termination_code_ *next;
}termination_code;
int addTermCode(termination_code *infoTerm, int termCode, unsigned long timerInfo)
{
termination_code *node;
node=(termination_code*)malloc(sizeof(termination_code));
if(NULL == node) return -1;
node->terminationCode=termCode;
node->time=timerInfo;
node->next=NULL;
infoTerm = node;
return 0;
}
int main ()
{
termination_code *list2=NULL;
//Add A single node and print it.
if(addTermCode(list2, 12, time(0))==0)
printf("All OK node added\n");
else
printf("something went wrong\n");
printf("Entered info :%d %ld\n",list2->terminationCode,list2->time);
}
Here what I get the output -- Not sure why. Please Help.
[zahmed#build3 rnd]$ ./a.out
All OK node added
Segmentation fault
[zahmed#build3 rnd]$
Thanks

In addTermCode you are changing the value of the infoTerm variable. That value is a pointer, but you are only changing the local value (C is pass-by-value only). To change the pointer outside of the function, you should pass a pointer to the pointer... Something like termination_code **infoTerm, and change *infoTerm = &node.
And, to be clear, the segmentation fault is because you are accessing the outer pointer, which has not been changed and still points to the wrong address.

The problem is the way you are passing back the new object. Assigning the new object to the pointer will not work the way you have it written. You should return the object instead from your addTermCode() function.
Basically your list2 pointer is still null. Return the newly created object from that function and assign it to list2.
If not, you'll need to adjust your code so that the pointer is properly assigned.
int addTermCode(termination_code **infoTerm, int termCode, unsigned long timerInfo)
{
....
*infoTerm = node;
}
int main ()
{
termination_code *list2=NULL;
//Add A single node and print it.
if(addTermCode(&list2, 12, time(0))==0)
printf("All OK node added\n");
printf("Entered info :%d %ld\n",list2->terminationCode,list2->time);
}

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;

Why do I get the memory access violation error using pointer to pointer

I created a small program in C to test pointer to pointer.
When I use a function (line 39) to print a list data, after adding an item to the list I get error 3221225477. However, when I comment the line 39, and I remove the comment from line 59 the program works normally.
Why do I get a ACCESS_VIOLATION error from the operating system, in this case Windows, if the program is running from top to bottom?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
struct employee{
int id;
char name[50];
char street[50];
};
typedef struct element* List;
struct element{
struct employee data;
struct element *next;
};
typedef struct element Elem;
List* list_create();
void list_print(List* list);
int list_is_empty(List* list);
int list_add(List* list, struct employee a);
int main(){
List* list = list_create();
struct employee a1;
a1.id = 10;
strcpy(a1.name, "John");
strcpy(a1.street, "Address XYZ");
list_add(list, a1);
//Sleep(5000); small pause, I thinking it might have something to do with thread.
//list_print(list); // *****line--39 *****;
return 0;
}
List* list_create(){
List* li = (List *) malloc(sizeof(List));
if(li != NULL)
*li = NULL;
return li;
}
int list_add(List* list, struct employee emp){
Elem* n1 = (Elem *) malloc(sizeof(Elem));
n1->data = emp;
n1->next = *list;
list = &n1;
list_print(list); // *****line--59 *****;
}
void list_print(List* list){
Elem aux = **list;
printf(" **lista Id: %d\n", aux.data.id);
printf(" **lista name: %s\n", aux.data.name);
printf(" **lista name: %s\n", aux.data.street);
}
C is pass-by-value, not pass-by-reference. Thus, the List* list in the function list_add and the List* list in main refer to two different locations in memory (they initially point to the same place at the start of list_add, but they are two different pointers with initially the same value, not the same pointer): modifying the value of the variable list within list_add does not affect the value of list in main.
To be specific:
list = &n1 in list_add modifies only the value of list within that function, i.e. the argument value that was copied into list_add's stack frame on invocation. However, when you try to print it on line 59, still within list_add, the changed value is seen and is thus the pointer printed from, working as you expect.
When you try to print list on line 39, in main, on the other hand, the variable list within the main function did not have its value changed by the assignment list = &n1 just before line 39 in list_add, since that only changed the value of the copy in that function's scope. Thus in that case list_print tries to print elements of an empty list (since the value of list is still just what was returned by list_create, which is a pointer to a NULL pointer, and so Elem aux = **list thus dereferences list and then tries to dereference a NULL pointer) and thus leads to an invalid memory access.
The problem in this code, then, is not the placement of the list's printing but rather that list_add is not updating the list properly. In fixing this you need to take into account that it can only modify the list structure by modifying what the reference value it received as an argument is pointing to, rather than by trying to modify the pointer itself. If you do want to modify the address list points to in main from within the function list_add (such as what the line list = &n1 seems to be attempting to do), you would need to pass a pointer to list into list_add, rather than just the pointer list itself.
There appear to be other issues in the code itself (list_print prints only one element and has no handling for printing empty lists, for example, which is what causes the error here to be an actual invalid memory access instead of merely incorrectly leaving the list empty after calling list_add), but the issue described above is the cause of this particular problem.

C: Method that handles pointer

I was wondering why the first method does not work but the second does:
//First method
int create_node(struct node *create_me, int init){
create_me = malloc(sizeof(struct node));
if (create_me == 0){
perror("Out of momory in ''create_node'' ");
return -1;
}
(*create_me).x = init;
(*create_me).next = 0;
return 1;
}
int main( void ){
struct node *root;
create_node(root, 0);
print_all_nodes(root);
}
Ok, here the print_all_nodes function tells me, root has not been initialized. Now second method that works fine:
struct node* create_node(struct node *create_me, int init){ //<-------
create_me = malloc(sizeof(struct node));
if (create_me == 0){
perror("Out of momory in ''create_node'' ");
exit(EXIT_FAILURE);
}
(*create_me).x = init;
(*create_me).next = 0;
return create_me; //<---------
}
int main( void ){
struct node *root;
root = create_node(root, 0); //<---------------
print_all_nodes(root);
}
In my understanding (talking about method 1), when I give the create_node function the pointer to the root node, then it actually changes the x and the next of root.
Like when you do:
void change_i(int* p){
*p = 5;
}
int main( void ){
int i = 2;
printf("%d\n", i);
change_i(&i);
printf("%d", i);
}
It actually changes i.
Get the idea?
Can someone share his/her knowledge with me please !
You need a pointer to pointer, not just a pointer.
If you want to change a variable in another function, you have to send a pointer to that variable. If the variable is an integer variable, send a pointer to that integer variable. If the variable is a pointer variable, send a pointer to that pointer variable.
You are saying in your question that "when I give the create_node function the pointer to the root node, then it actually changes the x and the next of root." Your wording makes me suspect that there is some confusion here. Yes, you are changing the contents of x and next, but not of root. root has no x and next, since root is a pointer that points to a struct that contains an x and a next. Your function does not change the contents of root, since what your function gets is only a copy of that pointer.
Changes to your code:
int create_node(struct node **create_me, int init) {
*create_me = malloc(sizeof(struct node));
if (*create_me == 0){
perror("Out of momory in ''create_node'' ");
return -1;
}
(*create_me)->x = init;
(*create_me)->next = 0;
return 1;
}
int main( void ){
struct node *root;
create_node(&root, 0);
print_all_nodes(root);
}
You need to do something like create_node(&root, 0); and then access it as a ** in the called method. C doesn't have pass by reference concept. You need to give the address to access it in another function.
This is a question of the scope of your variables. In the first example, where you supply a pointer to a node, you could change that node and the changes would persist afterwards. However, your malloc changes this pointer, which is discarded after the scope (your function) ends.
In the second example you return this pointer and therefore copy it before being discarded.
This would correspond to this in your given example no. 3:
void change_i(int* p){
*p = 5; // you can 'change i'
p = 5 // but not p (pointer to i), as it is local -> gets discarded after following '}'
}
when I give the create_node function the pointer to the root node, then it actually changes the x and the next of root.
You don't give the create_node() function (in both versions) a pointer to the root node because you don't have the root node, in the first place.
The declaration:
struct node *root;
creates the variable root, of type struct node * and lets it uninitialized. root is a variable that can store the address in memory of a struct node value (a pointer to a struct node value). But the code doesn't create any struct node value and the value of root is just garbage.
Next, both versions of function create_node() receive the garbage value of root in parameter create_me as a consequence of the call:
create_node(root, 0);
The first thing both implementations of create_node() do is to ignore the value they receive in create_me parameter (be it valid or not), create a value of type struct node and store its address in create_me.
The lines:
(*create_me).x = init;
(*create_me).next = 0;
put some values into the properties of the newly allocated struct node object.
The first version of the function then returns 1 and ignores the value stored in create_me. Being a function parameter (a local variable of the function), its value is discarded and lost forever. The code just created a memory leak: a block of memory that is allocated but inaccessible because there is no pointer to it. Don't do this!
The second version of the function returns the value of create_me (i.e. the address of the newly allocated value of type struct node). The calling code (root = create_node(root, 0);) stores the value returned by the function into the variable root (replacing the garbage value used to initialize this variable).
Great success! The second version of the create_node() function creates a new struct node object, initializes its properties and returns the address of the new object to be stored and/or further processed. Don't forget to call free(root) when the object is not needed any more.

Error in initializing the instance of a structure to NULL

I was writing a program to implement BST and I declareed two structures for that.
struct node
{
int data;
struct node *link[2];
};
struct tree
{
struct node *root;
};
typedef struct node node;
typedef struct tree tree;
And then i wrote a function to insert the elements in it.
void insert_iter(tree *tree, int data);
But in my main() function, I got confused that what thing shoud I initialise as NULL. So, I did this in my main() function.
tree *tree=NULL;
And it gave an error of segmentation fault.
But then I realised that the first condition in my insert_iter() function calls for tree->root, so this error was bound to happen.
But then I am confused about how to initialize this. How to go on for this?
EDIT: I have updated with the required code!!
this is the main() function
int main()
{
tree *tree=NULL; // all the confusion is regarding this
printf("hello"); // for debugging
//*tree->root=NULL; // tried this one but it was wrong
int value,choice;
while(1)
{
printf("enter the element : ");
scanf("%d",&value);
insert_iter(tree,value);
printf("do you want to enter more : 0 or 1 : ");
scanf("%d",&choice);
if(choice==0)
break;
}
return 0;
}
and this is the function that i used to insert the elements
void insert_iter(tree *tree, int data)
{
if(tree->root==NULL)
tree->root=newNode(data); // function to make a new node
else{
node *it=tree->root;
int dir;
while(1)
{
dir=data>it->data;
if(it->link[dir]!=NULL)
it=it->link[dir];
else
{
it->link[dir]=newNode(data);
break;
}
}}}
tree *tree=NULL; // all the confusion is regarding this
// the above is setting a pointer to NULL, which is ok
*tree->root=NULL; // tried this one but it was wrong
// the above is setting a
// (not initialized to point to any specific memory)
// offset in the tree struct variable
// (that offset is not pointing any specific memory)
// to set the first 4 bytes of that memory to NULL
// which should/will cause a seg fault event due to undefined behaviour
// a workable solution might be:
tree *pTree = malloc( sizeof(tree) );
// and then this would work:
tree->root = NULL; // notice no '*' dereference needed
//I would also strongly suggest that the variable names be different
//than the struct names, and not just in the capitalization of the name.
//The use of different names will greatly enhance
//the readability and understandability and clarity of the code
//(and will avoid any misunderstandings by the compiler and future maintainer)

C Linked list only contains first element...not sure what happens to rest

I posted a question a few days ago about a linked list in C. I thought everything was ok then the prof emails us saying that instead of this signature:
int insert_intlist( INTLIST* lst, int n); /* Inserts an int (n) into an intlist from the beginning*/
He accidentally meant:
int insert_intlist( INTLIST** lst, int n); /* Inserts an int (n) into an intlist from the beginning*/
I thought to myself cool now that I have a pointer to a pointer I can move the pointer outside of main and when I return to main I will still have my complete linked list.
He starts off with giving us this:
INTLIST* init_intlist( int n )
{
INTLIST *lst; //pointer to store node
lst = (INTLIST *)malloc(sizeof(INTLIST)); //create enough memory for the node
lst->datum = n; //set the value
lst->next = NULL; //set the pointer
return lst; //return the new list
}
Which is simply to initialize the list like so in main:
if (lst==NULL)
lst = init_intlist(i);
else
insert_intlist(lst, i);
lst is of type INTLIST* so its defined as INTLIST* lst. So I read in some numbers from a text file like 1 3 4 9.
It is supposed to create a linked list from this...so the first number would go to init_intlist(1); And that was defined above. Then it grabs the next number 3 in this case and calls insert_intlist(lst, 3). Well here is my insert_intlist and all I want to do is insert at the beginning of the list:
int insert_intlist(INTLIST** lst, int n )
{
INTLIST* lstTemp; //pointer to store temporary node to be added to linked list
lstTemp = (INTLIST *)malloc(sizeof(INTLIST)); //create enough memory for the node
lstTemp->datum = n; //assign the value
//check if there is anything in the list,
//there should be, but just in case
if(*lst == NULL)
{
*lst=lstTemp;
lstTemp->next=NULL;
}
else
{
lstTemp->next = *lst; //attach new node to the front
*lst = lstTemp; //incoming new node becomes the head of the list
}
return 0;
}
So if the list contained 1 initially this function would simply create a new node and then make this temp node->next point to the head of the list (which I thought was lst) and then reassign the head of the list to this new temp node.
It all looks like it is running right but when I try to print my list to the screen it only prints the number 1.
Anyone have any clues as to what I am doing wrong?
You're being passed a pointer to a pointer. You want to alter the pointer that is being pointed to, not the pointer to a pointer itself. Does that make sense?
if(lst == NULL)
Here you're checking to see if you were passed a NULL pointer. Good practice for error checking, but not for what you were doing right there. If lst is NULL, then you don't even have a pointer to a pointer, can't do anything, and should return a nonzero error code without doing anything else.
Once you're sure your pointer is not NULL, then you look at the pointer it's pointing to (*lst). The pointed-to pointer is the pointer to the first list item. If that pointer is NULL, then you change it to the new item's pointer. Basically, where you use lst you should be using *lst or (*lst). (REMEMBER: the * operator runs after the -> operator! So to get a field in the object pointed to by the pointer that is pointed to by lst [pant, pant], you use (*lst)->whatever.)
P.S. This kind of pointer work is critical to learn to be a good programmer, especially with C.
P.P.S. The other thing you got wrong is that instead of
insert_intlist(lst, i);
you're supposed to call it like
insert_intlist(&lst, i);
... and, for brownie points, check the return code for errors.
The first problem that pops into my mind is that in insert_intlist() you're doing lst = lstTemp;. This should be *lst = lstTemp;. This way you assign to the list pointer that you were supplied rather than to the list pointer pointer (which does not update anything outside of the function).
Since you are using a pointer to another pointer in the insert function, you can change at which memory location the latter actually points to. I changed the insert code a bit and it works fine:
int insert_intlist(INTLIST** lst, int n )
{
INTLIST* lstTemp; //pointer to store temporary node to be added to linked list
lstTemp = (INTLIST *)malloc(sizeof(INTLIST)); //create enough memory for the node
lstTemp->datum = n; //assign the value
//check if there is anything in the list,
//there should be, but just in case
if(*lst == NULL)
{
lstTemp->next=NULL;
*lst = lstTemp;
}
else
{
lstTemp->next = *lst; //attach new node to the front
*lst = lstTemp; //incoming new node becomes the head of the list
}
return 0;
}
EDIT: I see you edited your question. In that case, maybe you are calling the insert function in the wrong way in main(). Try this
int main()
{
INTLIST *head;
head = init_intlist(42);
insert_intlist(&head, 41);
display(head);
return 0;
}
Check to see if lstTemp->next == NULL after lstTemp->next=lst;

Resources