我已经查看了其他多个类似的问题,但没有一个适用于我的代码,因此我放弃了查找问题的尝试。
我正在尝试创建一个程序,将文件中的每一行(其中有一个书名)放入一个字符数组中,因为我需要稍后调用每本书,所以 book[1]、book[2]、等。但是,我无法弄清楚如何使用我的结构创建数组。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#define Num_Book 9
typedef struct book {
char *book_name;
size_t length;
ssize_t title;
}BOOK;
int main(int argc, char* argv[])
{
BOOK *Book;
Book = (BOOK *) malloc (sizeof(BOOK));
(*Book).book_name = NULL;
(*Book).length = 0;
char title_arr[Num_Book][50];
//this is the array that I tried creating,
//but it kept giving me warnings when I tried to compile
//opening my file
FILE *f_books;
f_books = fopen("books.txt", "r");
if (f_books == NULL)
{
printf("Cannot open file for reading.\n");
}
printf("Book list\n");
while (((*Book).title = getline(&(*Book).book_name, &(*Book).length, f_books)) != -1)
{
printf("%s", (*Book).book_name);
}
如果有人有任何想法,将不胜感激。谢谢!
最佳答案
最简单的方法是在 main()
中声明一个结构数组,使用您在预处理器指令中定义的 Num_Book
宏。由于您使用的是 getline()
,您甚至不需要手动分配内存来存储字符串;相反,您可以让 getline()
函数完成这项工作。请注意,getline()
不是标准 C 函数,而是 POSIX,也是 GNU 扩展。在某些系统上,您可能需要使用以下代码中包含的功能测试宏来启用此功能。
要利用 getline()
的自动内存分配功能,您需要为第一个参数传入一个空指针,第二个参数应该是一个指向 的指针包含零值的 size_t
变量。
在将数据读入结构的循环中,使用临时变量而不是直接分配给结构字段。这允许在最终分配之前检查当前字符串,这样空行就不会存储为书籍记录。
请记住 getline()
保留 \n
字符,因此如果当前行不为空,则终止换行符将替换为 \0
终止符。然后将临时变量保存的值分配给当前 BOOK struct
的适当字段,temp_name
和 temp_length
被重置为 NULL
和0
,并且i
递增。
您仍然需要释放由 getline()
分配的内存,因此这应该在程序结束之前完成。
请注意,在原始代码中,当您检查以确保文件 books.txt
已成功打开时,您没有在此处exit()
。如果文件无法打开,当程序像打开一样继续运行时,这将导致问题。您可以以不同的方式处理错误;例如,向用户询问不同的文件名可能是合适的。
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#define Num_Book 9
typedef struct book {
char *book_name;
size_t length;
ssize_t title;
} BOOK;
int main(void)
{
BOOK books[Num_Book];
FILE *f_books;
f_books = fopen("books.txt", "r");
if (f_books == NULL)
{
fprintf(stderr, "Cannot open file for reading.\n");
exit(EXIT_FAILURE);
}
printf("Book list\n");
char *temp_name = NULL;
size_t temp_length = 0;
ssize_t temp_title;
char *find;
size_t i = 0;
while ((temp_title = getline(&temp_name, &temp_length, f_books))
!= -1 && temp_name[0] != '\n') {
/* Replace newline with '\0' */
if ((find = strchr(temp_name, '\n')) != NULL) {
*find = '\0';
}
books[i].book_name = temp_name;
books[i].length = temp_length;
books[i].title = temp_title;
temp_name = NULL;
temp_length = 0;
printf("%s\n", books[i].book_name);
++i;
}
/* Still need to free allocated memory */
for (size_t j = 0; j < i; j++) {
free(books[j].book_name);
}
if (temp_name) {
free(temp_name);
}
if (fclose(f_books) != 0) {
fprintf(stderr, "Unable to close file\n");
exit(EXIT_FAILURE);
}
return 0;
}
程序输出:
Book list
The Sound and the Fury
So Long, and Thanks for All the Fish
Gargantua and Pantagruel
Foundation
如果需要为书籍动态分配空间,可以修改上面的代码。下面是执行此操作的版本,首先将变量 max_books
初始化为合理的起始值。空间被分配并分配给指向 BOOK
的指针,当添加新书时,如有必要,空间会重新分配。
添加所有书籍后,可以将分配裁剪到精确大小。请注意在 sizeof
参数中使用标识符而不是显式类型。如果在代码的 future 迭代中类型发生变化,这不太容易出错并且更容易维护。另请注意,如果发生分配错误,realloc()
将返回一个空指针。在这里,直接分配给 books
会导致先前存储的数据丢失和内存泄漏。为此,新分配的地址首先存储在temp
中; temp
的值仅在 NULL
不为 NULL
时才分配给 books
。
必须像以前一样释放相同的分配,但除此之外,还必须释放动态分配的数组。
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
typedef struct book {
char *book_name;
size_t length;
ssize_t title;
} BOOK;
int main(void)
{
FILE *f_books;
f_books = fopen("books.txt", "r");
if (f_books == NULL)
{
fprintf(stderr, "Cannot open file for reading.\n");
exit(EXIT_FAILURE);
}
char *temp_name = NULL;
size_t temp_length = 0;
ssize_t temp_title;
char *find;
size_t i = 0;
BOOK *books;
BOOK *temp;
size_t max_books = 10;
size_t num_books = 0;
if ((books = malloc((sizeof *books) * max_books)) == NULL) {
fprintf(stderr, "Unable to allocate books\n");
exit(EXIT_FAILURE);
}
while ((temp_title = getline(&temp_name, &temp_length, f_books))
!= -1 && temp_name[0] != '\n') {
++num_books;
/* Replace newline with '\0' */
if ((find = strchr(temp_name, '\n')) != NULL) {
*find = '\0';
}
/* Reallocate books if more space is needed */
if (num_books == max_books) {
max_books *= 2;
if ((temp = realloc(books, (sizeof *books) * max_books)) == NULL) {
fprintf(stderr, "Unable to reallocate books\n");
exit(EXIT_FAILURE);
}
books = temp;
}
/* Store book data */
books[i].book_name = temp_name;
books[i].length = temp_length;
books[i].title = temp_title;
temp_name = NULL;
temp_length = 0;
++i;
}
/* If you need books to be trimmed to minimum size */
if ((temp = realloc(books, (sizeof *books) * num_books)) == NULL) {
fprintf(stderr, "Unable to trim books allocation\n");
exit(EXIT_FAILURE);
}
books = temp;
/* Display list of books */
printf("Book list\n");
for (i = 0; i < num_books; i++) {
printf("%s\n", books[i].book_name);
}
/* Still need to free allocated memory */
for (i = 0; i < num_books; i++) {
free(books[i].book_name);
}
free(books);
if (temp_name) {
free(temp_name);
}
if (fclose(f_books) != 0) {
fprintf(stderr, "Unable to close file\n");
exit(EXIT_FAILURE);
}
return 0;
}
关于从文本文件创建数组以单独调用每一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42308168/