【问题标题】:C doesn't load info from file (fread, fwrite)C不从文件加载信息(fread,fwrite)
【发布时间】:2016-12-07 12:03:06
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SLENG   50 //just a random value

typedef struct Song 
{
    char *name;
    char *nameSong;
    char *timeSong;
    int date;
}  Song;

void saveToFile(Song *x, int *songCount) //Saves info  to the binary file
{
    FILE *f = fopen("array.txt", "w");
    if (f == NULL)
    {
        printf("Error\n");
    }
    fwrite(songCount, sizeof(int), 1, f);
    fwrite(x, sizeof(struct Song), (*songCount), f);
    fclose(f);
}

void readSong(Song *x, int *songCount) //Reads info fromt he file and writes it
{
    FILE *fr = fopen("array.txt", "r");
    if (fr == NULL)
    {
        printf("Error\n");
    }
    printf("Songs:\n");
    fread(songCount, sizeof(int), 1, fr);
    fread(x, sizeof(struct Song), (*songCount), fr);
    for(int i=0; i < (*songCount); i++)
    {
        printf("%d. %s %s %s %d\n", (i+1), x[i].name, x[i].nameSong, x[i].timeSong, x[i].date);
    }
    fclose(fr);
}

void insertSong(Song *x, int Count) //Inserts new song into the array.
{
    printf("\nInsert name of the band:\n");
    x[Count].name=malloc(SLENG * sizeof(char));
    scanf("%s", x[Count].name);

    printf("Insert name of the song:\n");
    x[Count].nameSong=malloc(SLENG * sizeof(char));
    scanf("%s", x[Count].nameSong);

    printf("Insert length of the song:\n");
    x[Count].timeSong=malloc(SLENG * sizeof(char));
    scanf("%s", x[Count].timeSong);

    printf("Insert then song was created:\n");
    scanf("%d", &(x[Count].date));
    printf("\n");
}

main()
{
    int songCount, menuOption;
    Song *x=malloc(SLENG*sizeof(char)+SLENG*sizeof(char)+SLENG*sizeof(char)+sizeof(int));
    printf("1. insert song\n 2. load from file\n ");
    scanf("%d", &menuOption);
    switch(menuOption)
    {
        case(1) :
            printf("Insert how many songs do you want to input?\n");
            scanf("%d", &songCount);
            for(int i=0; i<songCount; i++)
            {
                insertSong(x, i);
            }
            saveToFile(x, &songCount);
            break;
        case(2) :
            readSong(x, &songCount);
            break;
    }
}

我有一个计划要编写一个程序,该程序会将一些数据输入文件并可以从该文件中读取该数据,问题可能出在 fwrite 或 fread 上,因为每次我尝试加载并写入时它似乎都会崩溃文件中的数据。任何想法为什么它不能正常工作?我什至可以这样做,因为它是动态结构数组。提前致谢。

【问题讨论】:

  • 欢迎来到 Stack Overflow!听起来您可能需要学习如何使用调试器来逐步执行代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。进一步阅读:How to debug small programs.
  • 指针特定于单个进程。你不能保存指针。没有办法将指针加载到另一个进程中,即使它是同一个程序也是如此。要么使用数组,要么想出一种方法来serialize 每个结构中的数据。是的,指针就是你保存的全部。
  • 至于数组的问题,您总是无条件地为每个字符串分配SLENG 个字符。这真的不比拥有一个编译时固定大小的数组更好。
  • 您可能希望将字符串直接存储到像 typedef struct Song { char name[SLENG]; char nameSong[SLENG]; ... 这样的结构中,而不是使用指针。顺便说一句,您的评论 #define SLENG 50 //just a random value 是不恰当的;它不是只是一个随机值,而是您为字符串分配的长度。
  • 最后,您对Song 结构的分配是错误的。您需要分配 some_number * sizeof(Song) 字节。

标签: c arrays struct fwrite fread


【解决方案1】:

为了将结构保存到文件中,它必须只包含标量值,而不是指向内存对象的指针。修改你的结构以使用数组而不是指针:

typedef struct Song {
    char name[SLENG];
    char nameSong[SLENG];
    char timeSong[SLENG];
    int date;
} Song;

并相应修改代码,但注意:

  • 在文件中保存和读取结构需要以二进制模式打开文件"wb""rb"
  • 将二进制文件命名为array.txt非常容易引起误解
  • 写入文件时不需要传递计数的地址,但读取时需要传递数组指针的地址,因为您还不知道要分配多少内存。

这是修改后的代码:

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

#define SLENG   50   // this value is used in the file format

typedef struct Song {
    char name[SLENG];
    char nameSong[SLENG];
    char timeSong[SLENG];
    int date;
} Song;

int saveToFile(Song *x, int songCount) { //Saves info  to the binary file
    FILE *f = fopen("array.bin", "wb");
    if (f == NULL) {
        printf("Error\n");
        return -1;
    }
    fwrite(songCount, sizeof(int), 1, f);
    int written = fwrite(x, sizeof(struct Song), songCount, f);
    fclose(f);
    return written;
}

int readSong(Song **x, int *songCount) { //Reads info from the file and writes it
    int count = 0;
    FILE *fr = fopen("array.bin", "rb");
    if (fr == NULL)  {
        printf("Error\n");
        return -1;
    }
    printf("Songs:\n");
    fread(&count, sizeof(int), 1, fr);
    *x = calloc(count, sizeof(Song));
    if (*x == NULL) {
        printf("Cannot allocate %d bytes of memory\n", count);
        fclose(fr);
        return -1;
    }
    int found = fread(*x, sizeof(struct Song), count, fr);
    for (int i = 0; i < found; i++) {
        printf("%d. %s %s %s %d\n", i + 1,
               (*x)[i].name, (*x)[i].nameSong, (*x)[i].timeSong, (*x)[i].date);
    }
    fclose(fr);
    return *songCount = found;
}

void insertSong(Song *x, int Count) { //Inserts new song into the array.
    printf("\nInsert name of the band:\n");
    scanf("%49s", x[Count].name);

    printf("Insert name of the song:\n");
    scanf("%49s", x[Count].nameSong);

    printf("Insert length of the song:\n");
    scanf("%49s", x[Count].timeSong);

    printf("Insert then song was created:\n");
    scanf("%d", &(x[Count].date));
    printf("\n");
}

int main(void) {
    int songCount, menuOption;
    Song *x = NULL;

    printf("1. insert song\n 2. load from file\n ");
    scanf("%d", &menuOption);

    switch (menuOption) {
      case 1:
        printf("Insert how many songs do you want to input?\n");
        if (scanf("%d", &songCount) == 1) {
            x = calloc(songCount, sizeof(Song));
            for (int i = 0; i < songCount; i++) {
                insertSong(x, i);
            }
            saveToFile(x, songCount);
        }
        break;
      case 2:
        readSong(&x, &songCount);
        break;
    }
    free(x);
    x = NULL;

    return 0;
}

【讨论】:

  • 你在 calloc 函数中颠倒了参数
  • @Fefux:calloc()的参数顺序没有任何影响,但在C标准中确实记录为void *calloc(size_t nmemb, size_t size);,与size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);fwrite()不一致,尽管与bsearchqsort 一致。
  • 可以,但要符合文档
  • 感谢您的帮助,您真的救了我! :)
猜你喜欢
  • 2013-02-11
  • 1970-01-01
  • 1970-01-01
  • 2012-02-26
  • 2016-12-29
  • 2022-06-16
  • 2017-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多