Функция не сохраняет данные в указатель на структуру после realloc - PullRequest
0 голосов
/ 27 апреля 2020

Предполагается, что эта функция сохраняет данные в library.books_count экземпляре динамического c массива указателей на структуры. Но это не так. Подобная функция addexistingBooks() делает это без нареканий. В чем проблема в realloc()?

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

typedef struct
{
    char book_name[32];
    char book_genre[32];
    char author[32];
    int page_count;
    float price;

}Sbook;

typedef struct
{
    char library_name[32];
    Sbook * bookp;
    int books_count;
}Slib;

void menu(char String[50]);
void addexistingBooks(Slib library, int i);
void addBook(Slib library, int i);

int main()
{
    Slib library;
    int i=0;
    char Choice[30];
    printf("Enter amount of books inside the library: ");
    scanf("%d", &(library.books_count));
    library.bookp = (Sbook *)calloc(library.books_count,sizeof (Sbook));
    fflush(stdin);
    addexistingBooks(library, i);

    menu(Choice);
    if(strcmp(Choice,"add")==0)
    {
        addBook(library, i);
    }
    free(library.bookp);
    return 0;
}

void menu(char String[30])
{
    printf("Welcome to the library. If you read about heresy, prepare to be purged \n");
    printf("Please choose a command, by writing the appropriate command: \n");
    printf("1. Write 'add' to add a book. \n");
    printf("2. Write 'remove' to remove a book. \n");
    printf("3. Write 'redact' to redact a book. \n");
    printf("4. Write 'Sort by criteria' to sort the books, where criteria can stand for: 1.bookname, 2.author, 3.genre, 4.price. \n");
    printf("Enter your command: ");
    gets(String);
}

void addexistingBooks(Slib library, int i)
{
    for(i=0;i<library.books_count;i++)
    {
        printf("Enter the name of the book: \n");
        fgets(library.bookp[i].book_name,32,stdin);
        printf("Enter the genre of the book: \n");
        fgets(library.bookp[i].book_genre,32,stdin);
        printf("Enter the author of the book: \n");
        fgets(library.bookp[i].author,32,stdin);
        printf("Enter the page count of the book: \n");
        scanf("%d", &(library.bookp[i].page_count));
        printf("Enter the price of the book: \n");
        scanf("%f", &(library.bookp[i].price));
        fflush(stdin);
    }
}

void addBook(Slib library, int i)
{
        (library.books_count)++;
        realloc(library.bookp,library.books_count);
        fflush(stdin);
        if(library.bookp==NULL)
        {
            exit(1);
        }
        printf("Enter the name of the book: \n");
        fgets(library.bookp[i].book_name,32,stdin);
        printf("Enter the genre of the book: \n");
        fgets(library.bookp[i].book_genre,32,stdin);
        printf("Enter the author of the book: \n");
        fgets(library.bookp[i].author,32,stdin);
        printf("Enter the page count of the book: \n");
        scanf("%d", &(library.bookp[i].page_count));
        printf("Enter the price of the book: \n");
        scanf("%f", &(library.bookp[i].price));
        fflush(stdin);
}

Ответы [ 2 ]

0 голосов
/ 28 апреля 2020

Ваш код содержит несколько ошибок.

Давайте начнем с "неблокирующих" ошибок. Те, которые, даже если они могут быть действительно критическими и должны быть исправлены, не являются реальной причиной того, что вы испытываете sh.

  • Грипп sh стандартного ввода, fflush(stdin); - это то, что не определено стандартом, поэтому его использование приводит к неопределенному поведению : в некоторых средах это может работать, в других - не может работать и может быть средой (худшей), в которой кажется работать, но на самом деле это вредно. Рекомендуется избегать этого.
  • Функция gets() опасна, поскольку она не обеспечивает какого-либо контроля над размером строки, вставленной пользователем, и ее использования следует избегать .

Проблемы в функции void addBook()

  1. Вы пытаетесь увеличить доступное пространство, используя realloc:

    void * reallo c (void * ptr, size_t size);

Требуется исходный указатель и новый размер. Но вы передаете library.books_count это просто количество книг. Это означает, что если в библиотеке было 4 книги, вы пытаетесь выделить 5 байт * только 1038 *.

Вместо этого вам нужно выделить library.books_count * sizeof(Sbook) байт.

Кроме того, он возвращает новый указатель. Вам нужно присвоить его указателю книги:

library.bookp = realloc(library.bookp, library.books_count * sizeof(Sbook));
В main() вы инициализируете переменную i, но никогда не обновляете ее, поскольку храните номера книг непосредственно в library.books_count.

Затем передаете ее addexistingBooks(), и это избыточно, потому что вы можете использовать library.books_count для l oop, как вы это делаете. Вы можете использовать его как переменную l oop, но вам не нужно иметь этот параметр. Просто

void addexistingBooks(Slib library, )
{
    int i; /* If your C version is C99 or later, you can declare it in the loop itself */

    for(i=0;i<library.books_count;i++)
    {
        /* Omissis */
    }
}

Наконец вы передаете его в addBook(), и он не только избыточен (так как вы можете просто сохранить новую книгу по индексу library.books_count-1, но он активно вреден, потому что вы всегда обновляете индекс 0 (потому что значение параметра i равно 0).

Хотя можно передавать структуры в функции в качестве значений , это не рекомендуется. Первая причина заключается в том, что вы будете перегружать стек процесса (вся структура будет размещена в области стека, которая довольно велика в приложениях P C, но довольно ограничена во встроенных системах). Вторая причина вызовет функциональные проблемы.

Фактически, параметры, передаваемые по значению, являются копиями переменных, переданных в функцию. Это означает, что любое изменение, внесенное в них, не будет отражено в исходных структурах. В вашем случае обновление указателя library.bookp будет недоступно за пределами функции, в результате чего (1) исходная структура будет указывать на недопустимый адрес в памяти (становится висячий указатель ), (2) утечка вновь выделенной памяти, из-за которой никто не сможет free().

передавать структуры по адресу, вместо этого используя указатели на структуры . Функция addBook() с учетом удаления параметра i будет выглядеть следующим образом:

void addBook(Slib *library)
{
    int i = library->books_count;

    (library->books_count)++;
    library->bookp = realloc(library->bookp, library->books_count * sizeof(Sbook));

    /* and so on... the value of 'i' is now library->books_count-1 */
}

/* Call from main */
int main()
{
    Slib library;

    /* Omissis */

    menu(Choice);
    if(strcmp(Choice,"add")==0)
    {
        addBook(&library, i);
    }
    free(library.bookp);
    return 0;
}
0 голосов
/ 27 апреля 2020

Определение функции realloc,

 void *realloc(void *ptr, size_t size);

Итак, ваша realloc функция:

realloc(library.bookp,library.books_count);

должна измениться на:

library.bookp = realloc(library.bookp,sizeof(Sbook)*library.books_count);

OT, я вижу в вашей menu функции, вы используете gets. Это опасно, вы должны использовать fgets из stdin вместо. См. В этой ссылке Почему функция get так опасна, что ее не следует использовать?

...