Ошибка доступа к памяти для массива символов в структуре - C - PullRequest
0 голосов
/ 29 мая 2020

Я пытаюсь создать очередь, используя связанный список в C. Я использую две структуры для представления очереди и каждого узла, которые выглядят следующим образом.

#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;

Затем я использую эти следующие функции для инициализации очереди и узлов.

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;
}

При запуске моей функции постановки в очередь я получаю ошибку seg из-за функции strcpy, и при отладке gdb сообщает, что не может получить доступ к памяти узла, который я пытаюсь добавить. Код постановки в очередь выглядит следующим образом:

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;
}

Я также включу свою основную функцию в качестве дополнительной информации.

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

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

Насколько я могу судить, должно быть достаточно места для копирования заданную строку к узлу. Кто-нибудь знает, что происходит с ошибками и какие исправления?

Ответы [ 3 ]

1 голос
/ 29 мая 2020

Как уже упоминалось, вы передаете свои структуры по значению. В C правильным способом сделать это является указатель на указатель. Обратите внимание, что я не пробовал компилировать это, но, надеюсь, идея ясна.

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;
}
1 голос
/ 29 мая 2020

Функция initQueue_ch не имеет смысла.

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

Параметр функции q является локальной переменной функции. Изменение переменной внутри функции не влияет на аргумент, передаваемый функции.

Более того, также нет смысла динамически выделять очередь. Функция может выглядеть следующим образом:

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

И в основном вы можете написать

Queue_ch queue;
initQueue_ch( &queue );

Такая же проблема существует с функцией initQueueNode_ch

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

Снова функция имеет дело с копией значения переданного аргумента. Изменение копии не влияет на исходный аргумент.

Функция в целом не имеет смысла. Вам нужна функция, которая выделяет новый узел.

Это может выглядеть, например, следующим образом:

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;
}

Функция enqueue_ch, которая имеет тот же недостаток передачи указателя на очередь по значению может выглядеть как

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;
}

Вот демонстрационная программа.

#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;
}
0 голосов
/ 29 мая 2020
int initQueue_ch(Queue_ch* q)
{
    q = (Queue_ch*)malloc(sizeof(Queue_ch));
    q->count = 0;
    q->front = NULL;
    q->rear = NULL;
    return 0;
}

Эта функция не работает. Он игнорирует переданное ему значение q и не возвращает указатель на инициализированную очередь. C строго передается по значению.

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

Этот код никогда не дает queue никакого значения и передает значение мусора в initQueue_ch (которое он игнорирует), а затем значение мусора в enqueue_ch .

...