【问题标题】:Creating an array from a text file to call each line individually从文本文件创建一个数组以单独调用每一行
【发布时间】:2017-02-17 22:03:07
【问题描述】:

我查看了多个其他类似的问题,但没有一个适用于我的代码,因此我放弃了查找内容的尝试。

我正在尝试创建一个程序,它将具有书名的每一行从文件中转换为字符数组,因为我需要稍后调用每本书,所以 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);
}

如果有人有任何想法,不胜感激。谢谢!

【问题讨论】:

  • 为什么会出现ssize_t title; 元素?您不使用它或初始化它,这令人担忧。你知道你需要处理多少本书吗?您可以预先分配BOOK 结构的数组,还是需要使用malloc() 等手动(动态)分配?
  • Book = (BOOK *) malloc (sizeof(BOOK)); 不会为 BOOK 结构的 book_name 字段创建任何空间。您需要先将文件中的字符串读入缓冲区,然后为 book_name 分配空间。

标签: c arrays struct


【解决方案1】:

最简单的方法是在main() 中声明一个结构数组,使用您在预处理器指令中定义的Num_Book 宏。由于您使用的是getline(),因此您甚至不需要手动分配内存来存储字符串;相反,您可以让getline() 函数完成工作。请注意,getline() 不是标准 C 函数,而是 POSIX,也是 GNU 扩展。在某些系统上,您可能需要使用下面代码中包含的功能测试宏来启用此功能。

要利用getline() 的自动内存分配功能,您需要为第一个参数传入一个空指针,第二个参数应该是指向包含零值的size_t 变量的指针。

在将数据读入结构的循环中,使用临时变量而不是直接分配给结构字段。这允许在最终分配之前检查当前字符串,因此空行不会存储为书籍记录。

请记住getline() 保留\n 字符,因此如果当前行非空,则终止换行符将替换为\0 终止符。然后将临时变量持有的值赋给当前BOOK struct的相应字段,temp_nametemp_length重置为NULL0i递增。

你仍然需要释放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 参数中使用标识符而不是显式类型。如果类型在未来的代码迭代中发生变化,这不太容易出错并且更容易维护。另请注意,realloc() 将在发生分配错误时返回空指针。在这里,直接分配给books 会导致先前存储的数据丢失,并导致内存泄漏。为此,新分配的地址首先存储在temp中; temp 的值仅在不是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;
}

【讨论】:

  • 我最后合上了书,但忘记从我的复制和粘贴代码中添加,但这真的很有帮助!
  • 如果我不确定具体的书籍数量,需要使用 getline 来计算我有多少本书,我该如何使用它以便我仍然可以调用 '(printf( "%s\n", books[i].book_name);' 在 while 循环之外
  • @Wheeeeeecode——我添加了一个使用动态分配的版本。它跟踪存储的书籍数量并在阅读循环之外打印结果。
猜你喜欢
  • 1970-01-01
  • 2016-03-09
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
  • 2020-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多