函数在重新调用后没有将数据保存到结构体指针中。

问题描述 投票:0回答:2

这个函数的作用是将数据保存到 library.books_count 结构指针的动态数组的实例。然而它并没有。一个类似的函数 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);
}
c pointers structure dynamic-memory-allocation realloc
2个回答
0
投票

你的代码包含几个错误。

让我们从以下几个方面入手 "无障碍" 的错误。那些,即使他们可以真正的批评和。不得不 被纠正,并不是你遇到的崩溃的真正原因。

  • 标准输入的冲。fflush(stdin); 是标准没有定义的东西,所以使用它就会导致 未定义行为* 在某些环境中可以起作用,在另一些环境中则不能起作用,而且在某些环境中(最坏的环境)可能会起作用。看来 来工作,但其实它是有害的。建议避免使用。
  • 功能介绍 gets() 是危险的,因为它没有对用户插入的字符串的大小提供任何控制,而且它的用法是 应避免.

本报告中的问题 void addBook() 功能

  1. 您可以尝试使用以下方法增加可用空间 realloc:

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

它需要原始指针和新的大小。但你传递的是 library.books_count 那只是书的数量。意思是说,如果图书馆以前有4本书,你试着把它分配给 5个字节 仅仅是。

而您需要分配 library.books_count * sizeof(Sbook) 字节。

此外,它还返回一个新的指针。你需要把它分配给图书指针。

library.bookp = realloc(library.bookp, library.books_count * sizeof(Sbook));
  1. main() 你初始化一个 i 变量,但你从来没有更新过它,因为你直接把书的数量存储在了 library.books_count.

然后你把它传给 addexistingBooks(),而且这是多余的,因为你可以用 library.books_count 本身的循环,就像你实际做的那样。你可以使用它作为循环变量,但你不需要有这个参数。只要用

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)。)

  1. 虽然有可能 将结构作为值传递给函数我们不建议这样做。第一个原因是你会使进程的堆栈过载(整个结构将被分配在堆栈区域,这在PC应用中是相当大的,但在嵌入式系统中是相当有限的)。第二个原因是会给你带来功能问题。

事实上,通过值传递的参数是 副本 的变量,这意味着对它们的任何改变都不会反映到原始结构中。这意味着对它们的任何改变都不会反映到原始结构中。在你的例子中,更新 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
投票

定义 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);

加时赛,我看到在你的 menu 功能,您可以使用 gets. 很危险的,你应该用 fgetsstdin 取而代之的是 请看这个链接 为什么get函数如此危险,不应该使用?

© www.soinside.com 2019 - 2024. All rights reserved.