Проблемы с памятью при использовании кругового массива в очереди - PullRequest
0 голосов
/ 29 октября 2010

так что после некоторой отладки я пришел к этому в моей программе.Предполагается скопировать имя в круговой массив для очереди.Я не совсем уверен, что я делаю не так, и мог бы действительно помочь.

qPtr->front is an int
qPtr->numElements is an int
qPtr->queueSize is an int
name is a string


strcpy(qPtr->name[(qPtr->front+qPtr->numElements)%qPtr->queueSize], name);

здесь есть функция очереди

int enqueue(struct line* qPtr, int items, int time, char name[50])
{
    int i;
    if (qPtr->numElements != qPtr->queueSize)
    {
        qPtr->numItems[(qPtr->front+qPtr->numElements)%qPtr->queueSize] = items;
        qPtr->timeEntered[(qPtr->front+qPtr->numElements)%qPtr->queueSize] = time;
        strcpy(qPtr->name[(qPtr->front+qPtr->numElements)%qPtr->queueSize], name);

        (qPtr->numElements)++;
    }
}

Я определил, что это не когда она отключается, потому что, если я запускаю программу с закомментированием строки, у меня возникает проблемас ним работает нормально.Когда я запускаю программу с комментариями

strcpy(qPtr->name[(qPtr->front+qPtr->numElements)%qPtr->queueSize], name);

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

1 Ответ

1 голос
/ 29 октября 2010

Я должен спросить: вы фактически выделили пространство для переменных qptr->name[]. Если ваша структура просто что-то вроде:

struct line {
    int front;
    int numElements;
    int queueSize;
    char *name[100]; // or char **name where only first level is allocated.
}

тогда вы этого не сделаете, что приведет к неопределенному поведению, когда вы попытаетесь strcpy ввести имя.

Кроме этого, я бы предложил то же самое, что и всем, кто представляет проблему.

  • Что вы ожидали?
  • Что на самом деле произошло?
  • Покажите нам код (вы уже сделали этот бит, я включил его для полноты).

И временно вставьте в эту функцию некоторые операторы printf, чтобы вы могли видеть соответствующие поля до и после. Обычно это приводит к тому, что точно видит, что идет не так.


Судя по вашим комментариям, в вашей структуре есть массив из 50 символьных указателей, ни один из которых не был выделен. Вероятно, вы стремитесь к массиву символьных указателей, каждый из которых указывает на строку из 50 символов.

Я бы предложил, чтобы ваша структура содержала:

char *name[MAX_SZ]; // or a variable length array (either c99 or malloc trickery).

и изменить:

strcpy(qPtr->name[(qPtr->front+qPtr->numElements)%qPtr->queueSize], name);

до:

qPtr->name[(qPtr->front+qPtr->numElements)%qPtr->queueSize] = strdup (name);

Просто помните, что когда вы извлекаете это из списка, вы отвечаете за его освобождение, когда закончите.

Если вам не повезло оказаться в системе, в которой нет strdup, ну, вот тот, который я подготовил ранее: -)


Для чего-то я выкопал из своей базы кода старую реализацию, которую вы можете использовать по своему усмотрению:

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

// Would go in header file.

typedef enum {
    QERR_OKAY,
    QERR_NOMEM,
    QERR_INVALID,
    QERR_FULL
} eQueueErr;

typedef struct {
    size_t capacity;
    size_t used;
    size_t first;
    size_t next;
    char **list;
} tQueue;

const char *qErr (eQueueErr);
void qDump (char*,tQueue*);
tQueue *qCreate (size_t);
eQueueErr qPut (tQueue*,char*);
void qClear (tQueue*);
void qDestroy (tQueue*);

// Would go in C file.

// Returns textual representation of an error.

const char *qErr (eQueueErr e) {
    if (e == QERR_OKAY) return "Okay";
    if (e == QERR_NOMEM) return "NoMem";
    if (e == QERR_INVALID) return "Invalid";
    if (e == QERR_FULL) return "Full";
    return "?????";
}

// Dump function for debugging.

void qDump (char *desc, tQueue *q) {
    size_t i, j;
    printf ("%s: ", desc);
    printf ("capacity = %d, ", q->capacity);
    printf ("used = %d, ", q->used);
    printf ("first = %d, ", q->first);
    printf ("next = %d,", q->next);
    if (q->used > 0) {
        for (i = q->first, j = q->used; j > 0; i = (i + 1) % q->capacity, j--)
            printf (" %d=[%s]", i, q->list[i]);
    } else {
        printf (" no entries");
    }
    printf ("\n\n");
}

// Create a queue os a specified size.

tQueue *qCreate (size_t capacity) {
    tQueue *q;
    size_t i;

    // Need to create both the queue and the queue elements.

    if ((q = malloc (sizeof (tQueue))) == NULL)
        return NULL;
    if ((q->list = malloc (capacity * sizeof (char *))) == NULL) {
        free (q);
        return NULL;
    }

    // Set up accounting info and return it.

    q->capacity = capacity;
    q->used = q->first = q->next = 0;

    return q;
}

// Put something on the queue, return error if full, NULL or no memory available.

eQueueErr qPut (tQueue *q, char *s) {
    // Check if trying to put NULL or queue is full.

    if (s == NULL) return QERR_INVALID;
    if (q->used == q->capacity) return QERR_FULL;

    // Allocate new string and store if okay.

    q->list[q->next] = strdup (s);
    if (q->list[q->next] == NULL) return QERR_NOMEM;

    // Update accounting info and return success.

    q->next = (q->next + 1) % q->capacity;
    q->used++;

    return QERR_OKAY;
}

// Get an element from the queue (or NULL if empty).

char * qGet (tQueue *q) {
    char *s;

    // Just return NULL if empty.

    if (q->used == 0) return NULL;

    // Get it and adjust accounting info, then return it.

    s = q->list[q->first];
    q->first = (q->first + 1) % q->capacity;
    q->used--;

    return s;
}

// Clear a queue.

void qClear (tQueue *q) {
    size_t i, j;
    for (i = q->first, j = q->used; j > 0; i = (i + 1) % q->capacity, j--)
        free (q->list[i]);
    q->used = q->first = q->next = 0;
}

// Destroy a queue.

void qDestroy (tQueue *q) {
    qClear (q);
    free (q->list);
    free (q);
}

// Test program.

static char *nextLetter (void) {
    static char buffer[2];
    static char ch = 'A';
    buffer[0] = ch;
    buffer[1] = '\0';
    ch = (ch == 'Z') ? 'A' : (ch + 1);
    return buffer;
}

static void bigPut (tQueue *q, size_t num) {
    char *val;
    while (num-- > 0) {
        val = nextLetter();
        printf ("Putting '%s' returns: %s\n", val, qErr (qPut (q, val)));
        qDump ("After putting", q);
    }
}

static void bigGet (tQueue *q, size_t num) {
    char *val;
    while (num-- > 0) {
        val = qGet (q);
        printf ("Getting returns [%s]\n", val ? val : "<<null>");
        qDump ("After getting", q);
    }
}

int main (void) {
    tQueue *x;
    size_t i;
    char *val;

    if ((x = qCreate (5)) == NULL) return 1;
    qDump ("Create empty", x);

    printf ("Putting NULL returns: %s\n", qErr (qPut (x, NULL)));
    qDump ("After putting", x);

    bigPut (x, 6);
    bigGet (x, 4);
    bigPut (x, 2);
    bigGet (x, 4);
    bigPut (x, 3);

    qClear (x);
    qDump ("After clear", x);

    qDestroy (x);

    return 0;
}

При запуске этой программы генерируется следующий отладочный вывод:

Create empty: capacity = 5, used = 0, first = 0, next = 0, no entries

Putting NULL returns: Invalid
After putting: capacity = 5, used = 0, first = 0, next = 0, no entries

Putting 'A' returns: Okay
After putting: capacity = 5, used = 1, first = 0, next = 1, 0=[A]

Putting 'B' returns: Okay
After putting: capacity = 5, used = 2, first = 0, next = 2, 0=[A] 1=[B]

Putting 'C' returns: Okay
After putting: capacity = 5, used = 3, first = 0, next = 3, 0=[A] 1=[B] 2=[C]

Putting 'D' returns: Okay
After putting: capacity = 5, used = 4, first = 0, next = 4, 0=[A] 1=[B] 2=[C] 3=[D]

Putting 'E' returns: Okay
After putting: capacity = 5, used = 5, first = 0, next = 0, 0=[A] 1=[B] 2=[C] 3=[D] 4=[E]

Putting 'F' returns: Full
After putting: capacity = 5, used = 5, first = 0, next = 0, 0=[A] 1=[B] 2=[C] 3=[D] 4=[E]

Getting returns [A]
After getting: capacity = 5, used = 4, first = 1, next = 0, 1=[B] 2=[C] 3=[D] 4=[E]

Getting returns [B]
After getting: capacity = 5, used = 3, first = 2, next = 0, 2=[C] 3=[D] 4=[E]

Getting returns [C]
After getting: capacity = 5, used = 2, first = 3, next = 0, 3=[D] 4=[E]

Getting returns [D]
After getting: capacity = 5, used = 1, first = 4, next = 0, 4=[E]

Putting 'G' returns: Okay
After putting: capacity = 5, used = 2, first = 4, next = 1, 4=[E] 0=[G]

Putting 'H' returns: Okay
After putting: capacity = 5, used = 3, first = 4, next = 2, 4=[E] 0=[G] 1=[H]

Getting returns [E]
After getting: capacity = 5, used = 2, first = 0, next = 2, 0=[G] 1=[H]

Getting returns [G]
After getting: capacity = 5, used = 1, first = 1, next = 2, 1=[H]

Getting returns [H]
After getting: capacity = 5, used = 0, first = 2, next = 2, no entries

Getting returns [<<null>]
After getting: capacity = 5, used = 0, first = 2, next = 2, no entries

Putting 'I' returns: Okay
After putting: capacity = 5, used = 1, first = 2, next = 3, 2=[I]

Putting 'J' returns: Okay
After putting: capacity = 5, used = 2, first = 2, next = 4, 2=[I] 3=[J]

Putting 'K' returns: Okay
After putting: capacity = 5, used = 3, first = 2, next = 0, 2=[I] 3=[J] 4=[K]

After clear: capacity = 5, used = 0, first = 0, next = 0, no entries
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...