0

I am attempting to create a queue using a linked list in C. I am using two structs to represent the queue and each node which are as follows.

#define DATA_MAX 100

struct QueueNode_ch 
{
    struct QueueNode_ch* next;
    char data[(DATA_MAX + 1)];
};
typedef struct QueueNode_ch QueueNode_ch;

struct Queue_ch
{
    struct QueueNode_ch* front;
    struct QueueNode_ch* rear;
    int count;
};
typedef struct Queue_ch Queue_ch;

I then use these the following functions to initialize the queue and the nodes.

int initQueue_ch(Queue_ch* q)
{
    q = (Queue_ch*)malloc(sizeof(Queue_ch));
    q->count = 0;
    q->front = NULL;
    q->rear = NULL;
    return 0;
}

int initQueueNode_ch(QueueNode_ch* node)
{
    node = (QueueNode_ch*)malloc(sizeof(QueueNode_ch));
    node->next = NULL;
    node->data[0] = '\0';
    return 0;
}

Upon running my enqueue function I get a seg fault due to a strcpy function and when debugging gdb says it cannot access the memory of the node I am attempting to add. The enqueue code is as follows:

int enqueue_ch(Queue_ch* q, char* data)
{
    if(strlen(data) > (DATA_MAX + 1))
        return 1;
    QueueNode_ch* tmp;
    initQueueNode_ch(tmp);
    strncpy(tmp->data, data, DATA_MAX);
    if(isEmpty_queue_ch(q))
        q->rear = q->front = tmp;
    else
    {
        q->rear->next = tmp;
        q->rear = tmp;
    }
    q->count++;
    return 0;
}

I will also include my main function as additional information.

#include <stdio.h>
#include "Queue.h"

int main()
{
    Queue_ch* queue;
    initQueue_ch(queue);
    enqueue_ch(queue, "hello");
    return 0;
}

As far as I can tell there should be plenty of space to copy the given string to the node. Would anyone have any idea what is failing and possible fixes?

2
  • 3
    (Queue_ch* q) { q = Arguments are passed by value. The original queue is not initialized. Commented May 29, 2020 at 17:36
  • regarding: if(strlen(data) > (DATA_MAX + 1)) The function strlen() returns the OFFSET to the trailing NUL byte, Suggest: if( strlen( data) > DATA_MAX ) Commented May 30, 2020 at 23:21

4 Answers 4

1

As others have mentioned, you're passing your structs by value. In C, the proper way to do this is with a pointer to a pointer. Note that I haven't tried compiling this, but hopefully the idea is clear.

int initQueue_ch(Queue_ch** q)
{
    *q = (Queue_ch*)malloc(sizeof(Queue_ch));
    (*q)->count = 0;
    (*q)->front = NULL;
    (*q)->rear = NULL;
    return 0;
}

int initQueueNode_ch(QueueNode_ch** node)
{
    *node = (QueueNode_ch*)malloc(sizeof(QueueNode_ch));
    (*node)->next = NULL;
    (*node)->data[0] = '\0';
    return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Ahh I see this makes sense. This solved the problem. Thank you!
@Peter Glad to help. Instead of malloc, you can also use calloc rather than explicitly setting the members to NULL or 0. Saves a couple of lines of code.
1

The function initQueue_ch does not make sense.

int initQueue_ch(Queue_ch* q)
{
    q = (Queue_ch*)malloc(sizeof(Queue_ch));
    q->count = 0;
    q->front = NULL;
    q->rear = NULL;
    return 0;
}

The function parameter q is a local variable of the function. Changing the variable within the function does not have effect on the argument supplied to the function.

Moreover there is also no sense to allocate a queue dynamically. The function can look the following way

void initQueue_ch( Queue_ch *q )
{
    q->count = 0;
    q->front = NULL;
    q->rear  = NULL;
}

And in main you could write

Queue_ch queue;
initQueue_ch( &queue );

The same problem exists with the function initQueueNode_ch

int initQueueNode_ch(QueueNode_ch* node)
{
    node = (QueueNode_ch*)malloc(sizeof(QueueNode_ch));
    node->next = NULL;
    node->data[0] = '\0';
    return 0;
}

Again the function deals with a copy of the value of the passed argument. Changing the copy does not influence on the original argument.

The function is in whole does not make sense. What you need is a function that allocates a new node.

It can look for example the following way

QueueNode_ch * createQueueNode_ch( const char *data )
{
    QueueNode_ch *node = malloc( sizeof( QueueNode_ch ) );

    if ( node != NULL )
    {
        node->next = NULL;
        strcpy( node->data, data );
    }

    return node;
}

The function enqueue_ch that has the same drawback of passing a pointer to a queue by value can look like

int enqueue_ch( Queue_ch *q, const char *data )
{
    int success = strlen( data ) < DATA_MAX + 1;

    if ( success )
    {
        QueueNode_ch *node = createQueueNode_ch( data );

        success = node != NULL;

        if ( success )
        {
            if ( q->rear == NULL )
            {
                q->front = q->rear = node;
            }
            else
            {
                q->rear = q->rear->next = node;
            }

            ++q->count;
        }
    }

    return success;
}

Here is a demonstrative program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DATA_MAX 100

struct QueueNode_ch 
{
    struct QueueNode_ch* next;
    char data[(DATA_MAX + 1)];
};
typedef struct QueueNode_ch QueueNode_ch;

struct Queue_ch
{
    struct QueueNode_ch* front;
    struct QueueNode_ch* rear;
    int count;
};
typedef struct Queue_ch Queue_ch;

void initQueue_ch( Queue_ch *q )
{
    q->count = 0;
    q->front = NULL;
    q->rear  = NULL;
}

QueueNode_ch * createQueueNode_ch( const char *data )
{
    QueueNode_ch *node = malloc( sizeof( QueueNode_ch ) );

    if ( node != NULL )
    {
        node->next = NULL;
        strcpy( node->data, data );
    }

    return node;
}

int enqueue_ch( Queue_ch *q, const char *data )
{
    int success = strlen( data ) < DATA_MAX + 1;

    if ( success )
    {
        QueueNode_ch *node = createQueueNode_ch( data );

        success = node != NULL;

        if ( success )
        {
            if ( q->rear == NULL )
            {
                q->front = q->rear = node;
            }
            else
            {
                q->rear = q->rear->next = node;
            }

            ++q->count;
        }
    }

    return success;
}

void deleteQueue_ch( Queue_ch *q )
{
    while ( q->front != NULL )
    {
        QueueNode_ch *node = q->front;
        q->front = q->front->next;
        free( node );
    }

    q->rear = q->front;
    q->count = 0;
}

int main(void) 
{
    Queue_ch queue;
    initQueue_ch( &queue );

    enqueue_ch( &queue, "hello" );

    deleteQueue_ch( &queue );

    return 0;
}

Comments

0
int initQueue_ch(Queue_ch* q)
{
    q = (Queue_ch*)malloc(sizeof(Queue_ch));
    q->count = 0;
    q->front = NULL;
    q->rear = NULL;
    return 0;
}

This function is unusable. It ignores the value of q passed into it and does not return a pointer to the queue it initialized. C is strictly pass by value.

int main()
{
    Queue_ch* queue;
    initQueue_ch(queue);
    enqueue_ch(queue, "hello");
    return 0;
}

This code never gives queue any value and passes a garbage value to initQueue_ch (which it ignores) and then a garbage value to enqueue_ch.

1 Comment

Okay I see my mistake. Thank you for your help!
0

If you are initializing using malloc() then return the pointer() instead of passing pointer to function like following.

struct wordlist* wordlist_create(void)
{
    struct wordlist* wordListPtr = (struct wordlist*) malloc(sizeof(struct wordlist));
    wordListPtr->count = 0;

    wordListPtr->root = getTrieNode();

    return wordListPtr;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.