How to initialize my pointer to NULL - c

Learning C, I'm trying to implement a little program. I have two structs like this:
typedef struct QueueNode_ QueueNode;
typedef struct TQueue_ TQueue;
struct QueueNode_ {
QueueNode* next;
const Task task;
};
struct TQueue_ {
QueueNode* first;
QueueNode* last;
};
Next I defined a method to initialize my queue:
void initializeQueue(TQueue* queue){
queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
queue->first = NULL;
printf("%d", queue->first == NULL);
queue->last = NULL;
}
And the main:
int main() {
puts("TQueue example:");
TQueue q;
initializeQueue(&q);
printf("%d", q.first == NULL);
}
I though that the above would print 11 but it prints 10 meaning that my pointer first is not set to null. I'm pretty sure that I miss something basic...
Why the above prints 10 and how to initialize properly the pointer of first to NULL in my initializeQueue method?
Thanks!

The problem is that in C, arguments are always passed by value, unless explicitly passed as a pointer, so generally speaking you should not assign the arguments directly: it is confusing.
void initializeQueue(TQueue* queue) {
queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
See? Upon entering the function, queue points to the queue from main, but then you allocate a new struct and make queue point to it. So the queue from main is never initialized!
The solution, remove the malloc:
void initializeQueue(TQueue* queue){
queue->first = NULL;
printf("%d", queue->first == NULL);
queue->last = NULL;
}
Or if you prefer to go fully dynamic, to not take the queue as an argument but return a newly allocated one:
TQueue *initializeQueue(){
TQueue* queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
queue->first = NULL;
printf("%d", queue->first == NULL);
queue->last = NULL;
return queue;
}
And modify the main function accordingly.

This line is the fault:
queue = malloc(sizeof(TQueue)); //check if malloc returns NULL!
You have already allocated memory for the structure in the main function, so you don't need to do it again.
In fact, what the line is doing is allocating memory, assigning it to the pointer (and remember that arguments are passed by value so it overwrites the local copy) and you change only that structure in the function, not the one passed in by the call.

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

Trying to return a string from a queue in C/free problems

I've been working on a lab for a CSC class for a while, and unfortunately I'm a bit rusty with C (as you'll probably notice from the code). I'm encountering two particular problems, both related to memory management.
1) In the dequeue operation, I'm attempting to return a string value from the node at the end of the queue. Since I'm also trying to use free() and kill off that node once I retrieve the data, I need to use a method like strcpy() to grab the data. The program segfaults whenever I try to use strcpy, and Valgrind claims invalid r/w.
2) dequeue also is not properly updating the stringQueue struct for reasons I cannot understand. I have similar code for stacks where the alterations persist, but I can keep running dequeue all day and it won't actually remove the end node.
The relevant code:
typedef struct node {
char data [strMax];
struct node * next;
} queueNode;
typedef struct {
queueNode * head;
queueNode * tail;
} stringQueue;
char * dequeue(stringQueue *queue) {
char * data = malloc(strMax * sizeof(char));
if(empty(*queue)) {
return "Null list!";
}
else if(!(queue->head)->next) { // One item in the queue.
data = (queue->head)->data;
//free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else { // Multiple items in the queue.
data = (queue->tail)->data;
free(queue->tail);
queueNode * trace = queue->head;
while(trace->next) // Seek the last node in the queue.
trace = trace->next;
queue->tail = trace;
}
return data;
}
Your main problem is in lines like data = (queue->head)->data;. You can't assign array like this. you should memcpy. (strcpy is for null-terminated strings, and I guess that it's not so)
edit: you can also use strncpy, to avoid buffer-overflow.
You probably want to declare data as a char * = NULL at first. Then when you want to return it use data = asprintf("%s", (queue->tail)->data);. That will only do the string allocation and copying when needed, and only the required size. Then your calling code must take responsibility for freeing that data itself.
You currently have a char[] in your node struct in memory on the heap. Later on, you are setting a pointer to the data member of the struct, then freeing the struct in memory. You are left with a 'dangling pointer' that points to where the struct used to be. Trying to use that pointer will end in almost certain doom (or worse, unpredictable behaviour).
I see a few problems with your code...
First you do not test that your queue argument is not NULL. Then you haven't included your definition of empty() but probably testing that queue->head is NULL should tell you that the list is empty. Here you are dereferencing it prior testing it's a valid pointer, very dangerous.
Secondly, you are mallocing some data which is not used properly. When you do the affection data = (queue->head)->next; you are loosing the pointer to your allocated memory, you probably want to do a strncpy() here like strncpy(data, queue->head->data, strMax). After this you can uncomment your free(). The function calling your dequeue one will have to free() that string later when it's not used anymore.
Why not allocate your data only when you are sure that the list is not empty? If you do not want to do this, you then have to free() that unsuded malloc'ed memory.
See the code below.
queueNode* find_before_tail(stringQueue* queue)
{
queueNode* node = NULL;
if (!queue || !queue->head)
return NULL;
node = queue->head;
while (node->next != queue->tail && node->next)
node = node->next;
return node;
}
char * dequeue(stringQueue *queue) {
char *data = NULL;
queueNode* to_queue = NULL;
if(!queue || !queue->head) {
/* Nothing to dequeue here... */
return NULL;
}
data = malloc(strMax * sizeof(char));
if (!data) {
printf("Error with malloc()...\n");
return NULL;
}
/* Only one element */
if(!(queue->head)->next == queue->head) {
strncpy(data, queue->head->data, strMax);
free(queue->head);
queue->head = NULL;
queue->tail = NULL;
}
else {
strncpy(data, queue->tail->data, strMax);
to_dequeue = queue->tail;
queue->head = queue->head->next;
queue->tail = find_before_tail(queue);
if (!queue->tail)
return NULL;
queue->tail->next = NULL;
free(to_dequeue);
}
data[strMax - 1] = 0;
return data;
}
There are probably some other issues with the rest of your code, judging by this one but hopefully it gives you some basis.
EDIT WITH YOUR QUEUE CODE
Here again you are not testing the return value of malloc(). Here is a version with a non-cyclic linked list (I've also updated the dequeue() function above to work with this).
int enqueue(stringQueue *queue, char *item)
{
queueNode * newNode = NULL;
if (!queue || !item)
return EINVAL;
newNode = malloc(sizeof(queueNode));
if (!newNode) {
perror("malloc()");
return errno;
}
strncpy(newNode->data, item, strMax);
newNode->data[strMax - 1] = 0;
if (!queue->head) {
/* Element is queue and tail */
queue->tail = newNode;
}
newNode->next = queue->head;
queue->head = newNode;
return 0; /* Everything was fine */
}
I have not tested the code but it should be very similar to this. In this scenario, when you have only one element, this_element->next is NULL and not pointing to itself.

C pointer shenanigans

I'm trying to implement a Queue in C (using a Linked List) to store pointers to data. The en-queuing seems to be working fine, but some trouble with pointers upon de-queuing.
In my main():
void* data = malloc(sizeof(int));
dequeue(&Q, data);
printf("(%d) %d\n", k, *(int*)data);
dequeue():
int dequeue(struct queue *q, void *value)
{
struct queue_node *tmp;
if (!q->first) {
value = 0;
return 1;
}
value = q->first->data;
tmp = q->first;
if (q->first == q->last)
q->first = q->last = NULL;
else
q->first = q->first->next;
free(tmp);
return 0;
}
Based on my debugging, it seems that the value of the *data pointer in the main() for loop doesn't retain the value that it's set to in dequeue(). What am I missing?
Edit:
struct queue_node
{
struct queue_node *next;
void* data;
};
struct queue
{
struct queue_node *first;
struct queue_node *last;
};
The queue_node's data holds a pointer to some value (here it is an int, but it may not be true always, otherwise you'd use an int instead...)
Since this value was allocated with malloc (and is not a local variable) you need to also free it at some point.
So, change the function's signature to accept a void**, don't allocate space for an int in main() but call dequeue with &data as a parameter, where void * data = 0. Don't forget to free data when done.
In dequeue, set *value = q->first->data.
You're setting the value of the "value" variable, which is a pointer local to the function.
If you want to set the value to which it points, use:
*value = 0;
and:
*value = q->first->data;
Edit (after question edit): Since queue_node.data is itself a pointer, it makes more sense to pass a void**, as #Andrei notes above.
Assuming data is a (void *) and you want the (int) value pointed to by data, you'll have to replace
value = q->first->data;
with
*(int *)value = *(int *)q->first->data;
in the function deque();

Problem with pointers in 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;

A queue using structs and dynamic memory allocation

I am tasked with making a queue data structure in C, as a linked list. Our lecturer gave us a large amount of code to implement a stack, but we have to adapt it to create a queue. The code our lecturer gave us ends up not compiling and segfaulting at the exact same point as the code I wrote for the queue. I'm very new to structs, malloc and C in general, so there could be something painfully obvious I've overlooked.
Here is the code I am using:
#include <stdio.h>
#include <stdlib.h>
struct node{
int data; //contains the actual data
struct node *prev; //pointer to previous node (Closer to front)
struct node *next; //pointer to next node (Closer to back)
};
typedef struct node *Nodepointer;
struct queue{
Nodepointer front;
Nodepointer back;
};
typedef struct queue *Queuepointer;
main(){
Queuepointer myqueue; //create a queue called myqueue
init(myqueue); //initialise the queue
Nodepointer new = (Nodepointer)malloc(sizeof(struct node));
myqueue->front = new;
}
int init(Queuepointer q){
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
}
The idea is that the queue struct 'contains' the first and last nodes in a queue, and when a node is created, myqueue is updated. However, I cannot even get to that part (pop and push are written but omitted for brevity). The code is segfaulting at the line
myqueue->front = new;
with the following gdb output:
Program received signal SIGSEGV, Segmentation fault.
0x08048401 in main () at queue.c:27
27 myqueue->front = new;
Any idea what I'm doing wrong?
When you call init:
int init(Queuepointer q){
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
}
You're passing a pointer to a queue into the function, and initializing where that pointer points (in memory) within the function. By setting q = ..., you're assigning a new value to q.
Unfortunately, the calling function does not see this. You need to pass a pointer to a pointer instead:
int init(Queuepointer * qp){
Queuepointer q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
// Set qp:
*qp = q;
}
Then change the calling function:
init(&myqueue);
init(myqueue); passes by value a pointer to unallocated memory.
init does nothing on it, consequently (instead, writing random things at random location).
Then, myqueue->stuff does it again.
You should have used pointer to pointer.
Init will receive queue**, and called as init(&myqueue).
Inside, *myqueue=()malloc stuff
Also, I recommend you against these typedefs. They are rather bad style.
The first problem I see is that the "init" function writes the allocated pointer in "q", that is NOT your original "myqueue". Remember that C passes its arguments by value. A possible correction (not perfect, just a hint) is
Queuepointer init(void)
Queuepointer q;
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
return q;
}
`
And in "main":
myqueue = init();
Also beware that in your program you don't initialize the element allocated by malloc. malloc doesn't in general clean the memory it allocates.
Regards
You are passing myqueue by value so the allocation happened at init() is for the copy of myqueue not to myqueue.
So the correct version is:
int init(Queuepointer* q){
*q = (Queuepointer)malloc(sizeof(struct queue));
*q->front = NULL;
*q->back = NULL;
}
and you can call init() from main
init(&myqueue);
int init(Queuepointer q){
q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
}
Minor nitpick, but your init function has no return value so perhaps change it to:
void init(Queuepointer *q) {
or
int init(Queuepointer * qp){
Queuepointer q = (Queuepointer)malloc(sizeof(struct queue));
q->front = NULL;
q->back = NULL;
*qp = q;
if(q) {
return 1;
} else return 0;
}
Adjust according to how you want to perform error checking.

Resources