函数在重新分配后不将数据保存到指向结构的指针
Function not saving data to pointer to structure after realloc
此函数应该将数据保存到结构指针动态数组的 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);
}
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
。这很危险,您应该改用 stdin
中的 fgets
。见此linkWhy is the gets function so dangerous that it should not be used?
您的代码有几个错误。
让我们从"non-blocking"错误开始。那些,即使它们真的很关键并且 必须 得到纠正,也不是您遇到崩溃的真正原因。
- 标准输入的刷新,
fflush(stdin);
是标准没有定义的东西,所以使用它会导致未定义的行为:在某些环境下它可以工作,在某些其他环境中它无法工作,并且可能存在它 似乎 工作但实际上有害的环境(最差的环境)。建议避开。
- 函数
gets()
是危险的,因为它不对用户插入的字符串的大小提供任何控制,它的使用 should be avoided.
void addBook()
函数中的问题
您尝试使用 realloc
:
增加可用 space
void *realloc(void *ptr, size_t size);
需要原来的指针和新的大小。但是你传递 library.books_count
那只是书的数量。这意味着,如果图书馆曾经包含 4 本书,您尝试仅分配 5 个字节。
您需要分配 library.books_count * sizeof(Sbook)
字节。
此外它returns一个新的指针。您需要将其分配给书籍指针:
library.bookp = realloc(library.bookp, library.books_count * sizeof(Sbook));
- 在
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)。
- 虽然可以pass structures to functions as values,但不推荐。第一个原因是你会重载进程的堆栈(整个结构将分配在堆栈区域,这在 PC 应用程序中相当大但在嵌入式系统中非常有限)。第二个原因会给你带来功能上的问题。
实际上,按值传递的参数是传递给函数的变量的副本。这意味着对它们所做的任何更改都不会反映到原始结构中。在您的情况下, library.bookp
指针的更新将在函数外部不可用,导致 (1) 原始结构指向无效的内存地址位置(成为 dangling pointer), (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;
}
此函数应该将数据保存到结构指针动态数组的 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);
}
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
。这很危险,您应该改用 stdin
中的 fgets
。见此linkWhy is the gets function so dangerous that it should not be used?
您的代码有几个错误。
让我们从"non-blocking"错误开始。那些,即使它们真的很关键并且 必须 得到纠正,也不是您遇到崩溃的真正原因。
- 标准输入的刷新,
fflush(stdin);
是标准没有定义的东西,所以使用它会导致未定义的行为:在某些环境下它可以工作,在某些其他环境中它无法工作,并且可能存在它 似乎 工作但实际上有害的环境(最差的环境)。建议避开。 - 函数
gets()
是危险的,因为它不对用户插入的字符串的大小提供任何控制,它的使用 should be avoided.
void addBook()
函数中的问题
您尝试使用
增加可用 spacerealloc
:void *realloc(void *ptr, size_t size);
需要原来的指针和新的大小。但是你传递 library.books_count
那只是书的数量。这意味着,如果图书馆曾经包含 4 本书,您尝试仅分配 5 个字节。
您需要分配 library.books_count * sizeof(Sbook)
字节。
此外它returns一个新的指针。您需要将其分配给书籍指针:
library.bookp = realloc(library.bookp, library.books_count * sizeof(Sbook));
- 在
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)。
- 虽然可以pass structures to functions as values,但不推荐。第一个原因是你会重载进程的堆栈(整个结构将分配在堆栈区域,这在 PC 应用程序中相当大但在嵌入式系统中非常有限)。第二个原因会给你带来功能上的问题。
实际上,按值传递的参数是传递给函数的变量的副本。这意味着对它们所做的任何更改都不会反映到原始结构中。在您的情况下, library.bookp
指针的更新将在函数外部不可用,导致 (1) 原始结构指向无效的内存地址位置(成为 dangling pointer), (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;
}