如何在C语言中编写和读取包含另一个结构体的结构体?

3
这是我的结构体:
typedef struct 
{
    char* description;
    char* alternativeAnswer[4];
    int rightAnswer;
}question;

typedef struct 
{
    question** questions;
    int size;
    int max;
}questionList;

我希望能将一个questionList保存到文件中,并从文件中读取。 但是如果我这样写:
fwrite(a_questionList,sizeof(questionList),1,outfile);

并且按照以下方式阅读:

fread(newQuestionList,sizeof(questionList),1,infile);

我发现只有 sizemax 能够成功保存和读取。那么如何保存和读取 questions 呢? 谢谢!

2
哦,questions已经成功保存和读取,但是questions只是一个指针,它所指向的东西并没有被保存和读取。 - user253751
有另一个调用,在其中单独fwrite列表,然后fwrite两个变量。fread也类似。类似于myfread和myfwrite... - Siddharth
2个回答

4

请注意,正如评论中所提到的,由于您正在使用指针来处理问题列表,因此此方法无法工作。对于char字符串,程序将读取字符,直到找到\0。但是对于其他任何东西,只会写入指针变量的值;也就是说,只有内存地址。

(顺便说一下,对于问题列表,使用双指针有点奇怪。我假设这是一个错误,并且您的意思是 question * questions。)

我的建议是为每个结构编写一个write_<structure>函数,并在更外层函数的内部组件中使用这些函数,从内向外遵循结构的层次结构。在这里,您只有一个间接级别和一个项目列表,但是该方法对于多级别、多列表问题非常有用。

但是需要注意的是,由于您正在使用指针,因此您最终将不得不在读取时预分配它们。而且,由于您没有在声明时指定这些字符串的长度(可以为同一指针分配10或10000个字符),因此您将不知道要读取每个字符串的字符数。出于这个原因,我还会为char字符串使用预定义的最大长度;否则,您最终将不得不在读取时进行预分配。这样做还可以将整个结构一次性写入。声明如下:

#define NUM_OF_QUESTIONS    10
#define MAX_STRING_LEN     256
#define NUM_OF_ALT_ANSWERS   4

typedef struct {
    char description[MAX_STRING_LEN];
    char alternativeAnswer[NUM_OF_ALT_ANSWERS][MAX_STRING_LEN];
    int rightAnswer;
} question;

typedef struct  {
    question questions[NUM_OF_QUESTIONS];
    int size;
    int max;
} questionList;

这样,您现在可以使用一个单独的fwrite和一个单独的fread一次性写入和读取整个问题列表。对于这种特殊情况,您将完成。

请注意,我固定了问题的数量。如果您不想这样做(也就是说,如果您仍然有question * questions),我的建议是使用前面(更具扩展性)建议的方法,即像这样:

int write_question(FILE * fHdl, question * q, int items) {
    return fwrite((void*)(q), sizeof(question), items, fHdl);
}

int write_questionList(FILE * fHdl, questionList * qList, int numOfQuestions) {
    int nBytes = write_question(fHdl, qList->questions, numOfQuestions);
    if (0 != nBytes) { 
        nBytes += fwrite((void*)(&(qList->size)), sizeof(int), 1, fHdl);
        nBytes += fwrite((void*)(&(qList->max)), sizeof(int), 1, fHdl);
    }
    return nBytes;
}

同样适用于阅读。


非常感谢!我还有两个问题。nBytes 是什么作用?强制转换 qqList->sizeqList->max 是必要的吗? - shadowfish
fwrite()函数的签名是size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);,它返回写入的字节数。这有助于您了解是否一切顺利。变量nBytes只获取这个数字。虽然上面的函数中没有使用它,但您可能希望在每次写入或结束后检查是否已写入/读取了预期的内容。并且fwrite/fread期望一个(const) void指针,所以您只需将其转换一下,这样编译器就不会报错。 - J C Gonzalez

3
您可以在您的结构定义中尝试类似以下的代码:
typedef struct 
{
    char* description;
    char* alternativeAnswer[4];
    int rightAnswer;
}question;

typedef struct 
{
    struct question* questions;
    int size;
    int max;
}questionList;

考虑以下示例代码:
#include <stdio.h>
#include <string.h>

struct student_college_detail
{
    int college_id;
    char college_name[50];
};

struct student_detail 
{
    int id;
    char name[20];
    float percentage;
    // structure within structure
    struct student_college_detail clg_data;
}stu_data;

int main() 
{
    struct student_detail stu_data = {1, "Alex", 90.5, 71145,
                                       "UCB"};
    FILE *outfile; 

    // open file for writing 
    outfile = fopen ("student_detail.dat", "w"); 
    if (outfile == NULL) 
    { 
        fprintf(stderr, "\nError opend file\n"); 
        exit (1); 
    } 

    // stu_data to file 
    fwrite (&stu_data, sizeof(struct student_detail), 1, outfile); 

    if(fwrite != 0)  
        printf("contents to file written successfully !\n"); 
    else 
        printf("error writing file !\n"); 

    // close file 
    fclose (outfile); 

    return 0;
}

struct question* questionsquestion** questions 有什么区别? - shadowfish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接