Избавление от всех ошибок в программе Stack - PullRequest
0 голосов
/ 26 февраля 2020

Вывод valgrind:

$ printf "push $RANDOM\npush $RANDOM\npush $RANDOM\npop\nprint\n" | valgrind --leak-check=full ./stacknode
==10735== Memcheck, a memory error detector
==10735== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10735== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10735== Command: ./stacknode
==10735==
==10735== error calling PR_SET_PTRACER, vgdb might block
[0] = 19620
[1] = 30170
[0] = 19620
[1] = 30170
==10735==
==10735== HEAP SUMMARY:
==10735==     in use at exit: 738 bytes in 9 blocks
==10735==   total heap usage: 15 allocs, 6 frees, 8,994 bytes allocated
==10735==
==10735== 18 bytes in 3 blocks are definitely lost in loss record 1 of 2
==10735==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10735==    by 0x4ED9A09: strndup (strndup.c:43)
==10735==    by 0x108A4D: stack_push (in /home/fathima1997/projects/Homework2/stacknode)
==10735==    by 0x108BF4: main (in /home/fathima1997/projects/Homework2/stacknode)
==10735==
==10735== 720 bytes in 6 blocks are definitely lost in loss record 2 of 2
==10735==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10735==    by 0x4EBBB8B: getdelim (iogetdelim.c:62)
==10735==    by 0x108B77: main (in /home/fathima1997/projects/Homework2/stacknode)
==10735==
==10735== LEAK SUMMARY:
==10735==    definitely lost: 738 bytes in 9 blocks
==10735==    indirectly lost: 0 bytes in 0 blocks
==10735==      possibly lost: 0 bytes in 0 blocks
==10735==    still reachable: 0 bytes in 0 blocks
==10735==         suppressed: 0 bytes in 0 blocks
==10735==
==10735== For counts of detected and suppressed errors, rerun with: -v
==10735== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Исходный код:

/*
 * Search this source code for a comment with XXX. You must
 * implement this missing functionality. When you run the program
 * input should look like any of the following:
 *    push hi
 *    push whoah
 *    pop
 *    print
 *    push tho
 *    print
 *
 * I will execute something like the following and check that valgrind
 * reports no errors.
 *
 * In my shell:
 * $ printf "push $RANDOM\npush $RANDOM\npush $RANDOM\npop\nprint\n" | valgrind --leak-check=full 
   ./stack
 */

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

struct node {
    char* value;
    struct node* next;
};

struct stack {
    struct node* root;
    int length;
};

struct stack*
    stack_create(void)
{
    struct stack* r;

    r = malloc(sizeof * r);
    if (r == NULL)
        return NULL;

    r->root = NULL;

        return r;

}

/*
 * XXX: You must implement this function. It should remove
 * the top item on the stack and free the memory of both
 * the value and the node that was removed.
 */
void
stack_pop(struct stack* stack)
{
    /*
    assert(stack != NULL);
    assert(stack->root > 0);
    (stack->root)--;
    */

    if (stack->root == NULL){
        printf("You can't pop from an empty stack");
}
    else {
        struct node* top;
        top = stack->root;
        stack->root = top->next;
        free(top);
        return;
    }

}

bool
stack_push(struct stack* stack, const char* value)
{
    struct node* node;

    node = malloc(sizeof * node);
    if (node == NULL)

        return false;

    node->value = strndup(value, strlen(value) - 1);

    node->next = stack->root;
    stack->root = node;
        return true;
}

void
stack_print(struct stack* stack)
{
    struct node* cursor;
    size_t i = 0;

    for (cursor = stack->root; cursor != NULL; cursor = cursor->next)
        printf("[%zu] = %s\n", i++, cursor->value);

    return;
}

void
stack_destroy(struct stack* stack)
{
    struct node* cursor, * next;
    for (cursor = stack->root; cursor != NULL; cursor = next) {
        next = cursor->next;
        free(cursor);
    }
    free(stack);

    return;
}

int
main(void)
{
    struct stack* stack;

    stack = stack_create();

    for (;;) {
        char* token;
        char* line = NULL;
        size_t length = 0;
        ssize_t r;
        const size_t push_l = strlen("push ");

        r = getline(&line, &length, stdin);
        if (r == -1)
            break;

        if (strncmp(line, "push ", push_l) == 0) {
            line += push_l;

            if (stack_push(stack, line) == false)
                fprintf(stderr, "Stack push failed.\n");
        }
        else if (strcmp(line, "pop\n") == 0) {
            stack_pop(stack);
        }
        else if (strcmp(line, "print\n") == 0) {
            stack_print(stack);
        }
        else {
            fprintf(stderr, "Unknown command: must be one of push, pop and print.\n");
        }
    }

    stack_print(stack);
    stack_destroy(stack);

    return 0;
}

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

СОВЕТ: стек -> root - это указатель, а не массив или что-то еще. Если стек -> root имеет значение X (другими словами, это ссылка на объект, сохраненный в (X). X.next содержит следующий узел, поэтому стек -> root должен указывать на X.next.

1 Ответ

0 голосов
/ 26 февраля 2020

1) Проверьте страницу руководства для getline () - вам нужно освободить буфер. Вы устанавливаете его в NULL на каждой итерации цикла for; Вам было бы лучше закодировать это как:

char* line = NULL;
size_t length = 0;
while (getline(&line, &length, stdin) >= 0) {
...
}
if (line) free(line);
...

, так как идиоматический c навсегда l oop лучше всего применять, когда существует несколько условий выхода l oop, или он действительно никогда не выходит.

2) в stack_pop () и stack_destroy () вы освобождаете узел без освобождения value - строка, созданная с помощью strndup (). Почему бы просто не strdup () кстати; это более ясно и точно.

...