Problem with pointers in C - c

I have a problem with my pointers and structures in C (I know, I knooww, pretty basic!). I was practicing my procedural paradigm. It's the first time I use a debugger, because I haven't really needed it earlier in my life : < so I if you please help me I'll be thankful.
I defined the following structure to make a list:
typedef struct node {
int info;
struct node *next;
struct node *prev;
} node_t;
And then this function to fill it up:
void addNodo(node_t * list, int x){
node_t * pointer;
node_t * temp;
temp = (node_t *)malloc(sizeof(node_t));
temp->info = x;
temp->next = NULL;
temp->prev = NULL;
pointer = list;
if(pointer == NULL){ //it's empty so start it
list = temp;
return;
}
if (pointer->info <= x) { //I like my lists tidy so...
while((pointer->next != NULL) && (pointer->info <= x)){
pointer = pointer->next;
}
if(pointer->next == NULL){
pointer->next = temp;
temp->prev = pointer;
return;
}
pointer->next->prev = temp;
temp->next = pointer->next;
temp->prev = pointer;
pointer->next = temp;
return;
}
}
And then, doing this:
int main(int argc, char** argv) {
node_t * list = NULL;
addNodo(list, 1);
printf("x: %d", list->info);
return (EXIT_SUCCESS);
}
It's throwing me a Segmentation Error! When I debug it everything is fun and games until it passes the ++++ line, list address goes back to 0x0 and can't get it to work. I know there's an error somewhere, but to my knowledge of pointers, it's perfectly fine. Please, detect my error and teach me some pointers.

When you call addNode() you're passing in the pointer by value. So when you change it in the body of the function the change is lost and doesn't propagate outside the function. You need to declare it as:
void addNode(node_t **pointer, int x)
and then use *pointer in the function.
And when you call ity in main, pass in &list

The problem is that you cannot modify list inside the addNodo function. In C parameters are sent by value, so the changes you are doing inside "addNodo" is local to there.
You need to change addNodo function so, it actually receives the direction where is list.
void addNode(node_t **list, int x){
...
if(*pointer==NULL){
*list = temp;
}
}
Then in your main you should use:
addNode(&list, 1);

Well, you are making the mistake of passing the address of the list by value. So all the arguments of the function are made copies of and then your addNodo() works on the copied variables. Thus the original list does not get modified.
What you should be doing while calling is this:
addNodo(&list, 1);
In the function make these changes:
void addNodo(node_t ** list, int x)
/* This will enable you to get a copy of the address of the list variable.
Please note that this is also pass by value, C does not support pass by
reference */
Then make this change:
pointer = *list;
/* this will make the pointer point to the beginning of list as now
list is a pointer to pointer type */
Hope it helps you.
BTW, please go through a standard C book (I recommend K&R) to get familiar with passing arguments in C and what happens internally.

You're making a classic mistake:
void addNodo(node_t * list, int x)
...
list = temp;
return;
list isn't changed in the caller (main())
You can change the values in the memory list points at, but you can't change the value of list and have it be seen by the caller.
In order to do that, you'd need to pass a pointer to a pointer into the function:
void addNodo(node_t **list int x)
This allows you to change what list points at by doing:
*list = temp;

Related

Linked List head not being updated across function calls

I trying to implement my own linked list and have been messing around with the code learning about dynamic memory allocation and pointers and such. When I try to add something to my linked list I get a segfault, and upon using the debugger I realized that it was because initially my linked list's head pointer was not pointing to null and then my add function was not recognizing the head as being empty. But I have an initialize function that is setting the linked list's head pointer to NULL but for some reason once I exit out of the initialize function and into the add function, the head is no longer pointing to NULL.
Here's my code:
list.h
typedef struct node{
int value;
struct node *next;
} Node;
typedef struct list{
Node *head;
} List;
list.c
void initialize(List *l){
if(l != NULL){
l = malloc(sizeof(List));
l->head = NULL;
}
}
void add(List *l, int a){
//Code
}
int main(){
List l;
initialize(&l)
add(&l, 2);
}
As soon as I step into the add function and print out *l, I see that the head is not pointing to 0x0. And I've been scratching my head as to why it's not. I thought it was something to do with pass by value but I don't think it is. What am I doing wrong here?
Yes, pass-by-value is your culprit. You are passing a pointer by value.
Suppose l in your main() is at address 0xABCD. Then your main() gets compiled to
int main(void) {
List l;
initialize(0xABCD);
add(0xABCD, 2);
}
and your initialize() call looks like this (suppose malloc() succeeds and allocates memory at address 0xCDEF:
void initialize(List *l) {
if(l != 0x0) {
l = 0xCDEF; // malloc()
l->head = 0x0;
}
}
That l = 0xCDEF does not propagate to main(), because l was passed by value.
What you want to do is
void initialize(List **l) {
if(l != NULL) {
*l = malloc(sizeof(List)); // note dereferencing the passed-by-value pointer
(*l)->head = NULL;
}
}
int main(void) {
List * l;
initialize(&l);
add(l, 2);
}
which will pass pointer to pointer to list (actually the address of the pointer in your main(). It allows the code in initialize() to change the l variable in main().
Alternatively, you can use
List * list_init() {
List * retval = malloc(sizeof(List));
if(retval == NULL) { // you should check malloc return value
// abort(), print warning or just
return NULL;
}
retval->head = NULL;
return retval;
}
int main(void) {
List * l = list_init();
if(l == NULL) {
// handle the error
}
add(l, 2);
}
You declare a List in main() that lives on the stack. You pass a pointer to that List to initailize(). You then create a new List on the heap. When you return from initialize() you still are using the List on the stack that you had in the beginning. The List on the heap is leaked and you cannot access it. So you never initialized the List you pass as a pointer to add(). You can forget about initialize() and just have
l.head = NULL;
instead.
Did you code compile this line l->malloc(sizeof(list)); seems odd.
Create a structure with only one argument is not really useful, a simple typedef should do the job : typedef Node* List

C-modifying the address of a global variable inside a void function

Working on a linked list where I'm storing a pointer to head as a global variable. My question is: How can I assign a (new)value (in this case address) to head from within a void function?
EDIT
Alright here's some code:
Note: this is not how i would design this, but we're not supposed to stray from the spec.
typedef struct NODE Node;
typedef Node *NodePtr;
struct NODE{
char *item;
Node *next;
};
NodePtr first = NULL; //global
//insert function
Boolean insert( char *new_string ) {
printf("insert called\n");
if(first == NULL) {
first = malloc(sizeof(Node));
first->next = NULL;
first->item = new_string;
}
else {
NodePtr inserted = malloc(sizeof(Node));
inserted->next = first;
inserted->item = new_string;
first = inserted;
}
return 1;
}
the problem is that when i use insert() in a function. it works fine. i get a working list. but when another function tries to access first, its empty.
Am I right in assuming that modifying the global variables within the function does not alter the actual first ptr? I know I could pass in a pointer to first as an argument, but I'm not supposed to modify the prototype design.
You'll need to pass in the pointer and a pointer to pointer to head.. Update pointer to head, and head-> next to old head
if it is a global variable just assign the value like you would have done if it was a local variable in your void function.
assuming your struct is similar to this:
struct list {
int data;
struct list* next;
};
and you have the global variable
struct list* L
you can make a new node by making a new node, making the next variable to the head, and making your global value point to the new node:
newnode->next = L;
L = newnode

C function returning structure data through one of the arguments

I have an issue when using pointer parameters in a function to return values. The function correctly loads all values inside the function, but then somehow fails to pass the pointer value to the variable in the arguments.
In my case, i wrote a function witch returns 1 or 0 depending on whether allocation of memory in question failed or not, and as one of the parameters, takes a pointer to a list that needs to be entered. The structure of the list looks like this:
typedef struct sList {
int id;
char first_name[30];
char last_name[30];
struct sList *next;
} tList;
The function looks like this:
int readList(tList *start, int n){
tList *head = NULL;
tList *tail = NULL;
int i;
for (i = 0; i < n; i++){
tList *tmp = malloc(sizeof(tList));
if (tmp == NULL) return 0;
scanf("%d %s %s", &tmp->id, &tmp->first_name, &tmp->last_name);
tmp->next = NULL;
if (!head) head = tmp;
else tail->next = tmp;
tail = tmp;
}
start = head;
return 1;
}
And the main method:
void main(){
tList *start = NULL;
int n;
scanf("%d", &n);
readList(start, n);
tList *tmp = start;
while (tmp){
printf("%d %s %s\n", tmp->id, tmp->first_name, tmp->last_name);
tmp = tmp->next;
}
system("PAUSE");
return;
}
During debugging, i have concluded that the list head and start inside the function have all the entered values, but as soon as I leave the function and return to the main program the start list goes bananas. So, my question is, am I doing something wrong, because, to my knowledge, this should work in theory. Thanks in advance.
If you want to change a variable from within a function, you need to pass a pointer to it and dereference that pointer within said function. That's how C emulates pass-by-reference.
When that variable is itself a pointer, that means you need to pass a pointer to the pointer, such as with:
int readList(tList **pStart, int n){
// blah blah blah, setting up head.
*pStart = head;
return 1;
}
int main(void){
tList *start = NULL;
int n;
scanf("%d", &n);
readList(&start, n); // Note this, using address-of
// more blah
return 0;
}
The text below is an aside to your specific problem but I thought I'd mention it for completeness.
Your main function doesn't conform to the canonical ones allowed by the standard - I've changed it to make that more acceptable but it may not be necessary for your particular implementation, depending on how lax it is. It's still a good idea to follow the standard.
It's also dangerous to assume (in robust code) that scanf() always works. If it returns zero (number of items successfully scanned), n will almost certainly not be what you expect.
You make the same mistake with readList() in that you don't check its return value either. It also has the annoying aspect of causing memory leaks if an allocation fails.

understanding the difference between two linked list implementations in c

For a month or two since i started learning data-structures , using C, i have been following a particular method of writing linked list. Which looks like this.
#include<stdio.h>
#include<stdlib.h>
struct Node{
int exponent;
int coeff;
struct Node *next;
};
typedef struct Node N;
N *st = NULL;
void insert(N *node, int c, int e){
N *temp;
node->exponent = e;
node->coeff = c;
if(st == NULL){
node->next = st;
st = node;
} else {
temp = st;
while(temp->next != NULL){
temp = temp->next;
}
node->next = temp->next;
temp->next = node;
}
printf(" %p", st); //this is written on purpose, not that i write it everytime
}
and i call this from the main method,
N *node = malloc(sizeof *node);
insert(node, 1, 2);
The output of the printf for four such calls is
00340D18 00340D18 00340D18 00340D18
i.e the value of the start pointer remains constant, but if i make a small change in the code
typedef struct Node N;
void insert(N *node, N *st, int c, int e){
N *temp;
node->exponent = e;
node->coeff = c;
if(st == NULL){
node->next = st;
st = node;
} else {
temp = st;
while(temp->next != NULL){
temp = temp->next;
}
node->next = temp->next;
temp->next = node;
}
printf(" %p", st);
}
and declare the the start pointer in the main method
N *strt = NULL;
node = malloc(sizeof *node);
insert(node, strt, 1, 1);
then run this four times like in the previous case, the values of start pointer gets changed
after each call
00560D18 00560D30 00560D48 00560D60
Why does this happen?
And if i want to pass the start pointer as a parameter what changes should be made?
Why does this happen?
This happens because the change to st is invisible to the caller. That is st = node has no effect whatsoever for the caller. The function changes its own copy and after the function returns, if the caller prints strt, it will still be NULL.
This is a somewhat subtle consequence of the fact that in C arguments are passed by value, even pointers. So you pass strt by value. You can change st->whatever because it's a pointer and changes will propagate to the caller but changing strt itself will not work.
And if i want to pass the start pointer as a parameter what changes
should be made
This is a regular question on this site and there is also a C FAQ that describes the problem. A simple if somewhat cumbersome change that you can do is have the function take a
N **st and pass &strt.
This is because strt in your main method and st in the modified function insert are two different variables. The function call
insert(node, strt, 1, 1);
copies the value of strt which is defined in main to the function parameter st which is a different variable and is allocated on the stack when the function insert is invoked. Any changes made to st is visible inside the function only because it's a local variable. It goes out of scope once the function returns. Therefore, strt defined in main is still pointing to null and never gets changed. This means that the condition st == NULL is always true and the if block in insert is always executed and the local variable st is set to the newly created node each time the function insert is called. This would, in fact, cause memory leak because you lose the handle on the node once the function insert returns.
What you should do is to pass an address of the variable strt to insert so that the changes made to it is visible in main. Since you always append the new node at the end of the linked list, I suggest a few more changes.
void insert(N *node, N **st, int c, int e) {
N *temp = *st;
node->exponent = e;
node->coeff = c;
node->next = NULL; // set it explicitly to NULL
if(*st == NULL) { // if head of the linked list is NULL
*st = node;
}
else {
while(temp->next != NULL) // reach the end of the linked list
temp = temp->next;
temp->next = node; // add the new node at the end
}
printf("%p", *st);
}
And in main, invoke the function as
// in main method
N *strt = NULL;
node = malloc(sizeof *node);
insert(node, &strt, 1, 1);

C -- (void*) to int

I'm implementing a simple priority queue in C for a kernel and so I can't use any standard libraries. The queue holds a head node and each node points to the next in the queue.
typedef struct node node;
struct node {
node *next;
void *data;
};
typedef struct {
node *head;
int n;
} queue;
As you can see, each node holds it data in a void*. I'm having trouble converting this data to lets say an int when I pop the data off the stack.
//push data
int int_data = 100;
push(q, &int_data);
//...
//pop data
node* popped = pop(q);
int *pop_data = popped->data;
printf("pop data (100): %d\n", *pop_data);
Why can't I get the original value here? I seem to be printing a pointer value. Alternatively, is there a better way to handle this?
== edit (sorry should have included these):
void push(queue *q, void *data)
{
node new;
new.data = data;
node *new_ptr = &new;
if(is_empty(q))
{
q->head = new_ptr;
q->n++;
return;
}
int i;
node *curr = q->head;
for(i=0; i<q->n; i++)
{
curr = curr->next;
}
curr->next = new_ptr;
q->n++;
}
node* pop(queue *q)
{
node *curr = q->head;
q->head = curr->next;
return curr;
}
Is your code all in one function? If not, int int_data is getting popped off the stack (not your queue, the actual stack) which is probably why you are printing garbage; you are storing the address of a local variable.
I would suggest changing void* data to int data. (If you need to, you can store an address in an int and can cast it back to a pointer later.)
int int_data = 100;
push(q, int_data);
node* n = pop(q);
int num = n->data;
After reviewing your code again, you have the same problem when adding a new node. node new falls out of scope at the end of the function, so basically all of your nodes in your queue are pointing to invalid memory.
If the "pop" operation is in a different function:
The problem is likely because you're pushing a local variable into your queue.
When you go to pop, this address is no longer valid (or at least not pointing to an int value), so you're printing something strange. As the data is no longer pointing to your int, it probably looks like a memory address.
You can use the glib GPOINTER_TO_INT macro:
#define GPOINTER_TO_INT(p) ((gint) (glong) (p))
But please, take note with the doc note:
YOU MAY NOT STORE POINTERS IN
INTEGERS. THIS IS NOT PORTABLE IN ANY
WAY SHAPE OR FORM. These macros ONLY
allow storing integers in pointers,
and only preserve 32 bits of the
integer; values outside the range of a
32-bit integer will be mangled.
are you setting data = int_data (i.e. int --> void*) or data = &int_data (i.e. int* --> void *) ? In the former case, you have to write printf("pop data (100): %d\n", pop_data);

Resources