c# 从函数结构代码访问存储的数据

aydmsdu9  于 2023-06-04  发布在  C#
关注(0)|答案(2)|浏览(431)

在主函数中,用户必须输入ID。然后显示输入的ID数据(学生姓名、ID和课程)。
我需要编写缺少的部分,它必须旨在将用户输入的“ID”与从函数“populate()”存储的ID进行比较,然后它将如何显示来自函数内部的多个结构体的数据?
是否可以将学生结构s1 - s10作为变量访问?like; if(id == '1001'){ printf(“学生ID:%s\n学生姓名:%s\n课程:%s”,student s1);

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

struct Student {
    char id[4];
    char name[8];
    char course[5];
};

void populate() {
    FILE* fp;
    fp = fopen("students.csv", "w");

    struct Student s1 = {"1001", "John", "BSCS"};
    fprintf(fp, "%s,%s,%s\n", s1.id, s1.name, s1.course);

    struct Student s2 = {"1002", "Bob", "BSIT"};
    fprintf(fp, "%s,%s,%s\n", s2.id, s2.name, s2.course);

    struct Student s3 = {"1003", "Jane", "BSIT"};
    fprintf(fp, "%s,%s,%s\n", s3.id, s3.name, s3.course);

    struct Student s4 = {"1004", "Karla", "BSIT"};
    fprintf(fp, "%s,%s,%s\n", s4.id, s4.name, s4.course);

    struct Student s5 = {"1005", "Clarisse", "BSCS"};
    fprintf(fp, "%s,%s,%s\n", s5.id, s5.name, s5.course);

    struct Student s6 = {"1006", "Peter", "BSCS"};
    fprintf(fp, "%s,%s,%s\n", s6.id, s6.name, s6.course);

    struct Student s7 = {"1007", "Bob", "BSCS"};
    fprintf(fp, "%s,%s,%s\n", s7.id, s7.name, s7.course);

    struct Student s8 = {"1008", "Stewie", "BSIT"};
    fprintf(fp, "%s,%s,%s\n", s8.id, s8.name, s8.course);

    struct Student s9 = {"1009", "Bryan", "BSCS"};
    fprintf(fp, "%s,%s,%s\n", s9.id, s9.name, s9.course);

    struct Student s10 = {"1010", "Kent", "BSIT"};
    fprintf(fp, "%s,%s,%s\n", s10.id, s10.name, s10.course);

    fclose(fp);
}

void display(const char* id) {
    FILE* fp;
    fp = fopen("students.csv", "r");

    struct Student student;
    if (strcmp(student.id, id) == 0) {
        printf("Student Id: %s\n", student.id);
        printf("Student Name: %s\n", student.name);
        printf("Course: %s\n", student.course);
    }

    fclose(fp);
}

int main() {
    populate();

    char id[4];

    printf("Enter student_id: ");
    fgets(id, 4, stdin);

    display(id);

    return 0;
}
9jyewag0

9jyewag01#

具有storage auto的变量由编译器在堆栈上分配。它们还具有声明它们的块的作用域。因此,这些变量(s1-s10)在populate函数之外不可访问。如果从该函数返回,它们也会被释放。如果你想让它们在之后仍然存在,你必须把它们分配到其他地方。如果你想从外部访问它们,你可以在某个地方传递一个指向它们的指针,但这并不能解决释放问题。如果你返回一个指向局部变量的指针,你将得到未定义的行为,因为变量将被释放,指针将悬空(指向无意义)。所以你有两个选择

  • 将它们分配到堆栈上的其他位置:
int main()
{
    struct Student students[10];
    populate (&students);
[...]
}

void populate(struct Student * students)
{
    students[0] = {"1001", "John", "BSCS"};
[...]
}
  • 将它们分配到堆上:
struct Students *
populate ()
{
    struct Students * students;

    students = malloc (sizeof (struct Students) * 10);
    if (NULL == students) abort();
    
    students[0] = {"1001", "John", "BSCS"};
[...]
    return students;
}

作为第三种方法,你也可以用全局作用域来声明它们,但我不推荐这样做。(除非你只是有点黑客,但不是为了一些真实的东西)
请注意,我将10个变量改为一个数组,因为否则您必须传递10个单独的指针。

0h4hbjxa

0h4hbjxa2#

首先,字符串"1001"需要5字节的内存。必须始终考虑字符串结尾处的空终止字节('\0')。在内存中,它看起来像:

'1' | '0' | '0' | '1' | '\0'

您的结构定义

struct Student {
    char id[4];
    char name[8];
    char course[5];
};

将没有足够的空间来存储这些strings。C的一个警告是,数组(例如char id[4];)可能是initialized,因为字符串文字太大了一个字节。结果数组将省略null终止字节,您将不再拥有字符串。
因此,当结构初始化工作时,下面的

fprintf(fp, "%s,%s,%s\n", s1.id, s1.name, s1.course);

通过向printf说明符%s传递非字符串的内容,立即调用Undefined Behaviour
还有这里

char id[4];
printf("Enter student_id: ");
fgets(id, 4, stdin);

id总是太小,无法存储任何将写入populate文件的ID,因为fgets总是在成功时空终止缓冲区。另外,如果fgets读取了一个换行符,它也将被存储在缓冲区中。
是否可以访问struct Students1-s10作为变量?
变量s1s10表示automatic storage duration的对象。它们只存在于其封闭 blockduration中,在本例中是函数调用populate。当函数返回时,它们不再存在。
但你似乎混淆了两个概念:

  • 您是否需要可由不同函数调用访问的持久程序内存?
  • 或者,您想将数据写入文件,然后再检索它吗?

如果你想要前者,你应该在main中声明你的变量,并将指向这些对象的指针传递给你的不同函数。或者,变量可以在file scope处“全局”定义。
如果您想要后者,那么display需要从它打开的文件(fp)中实际读取信息。现在,struct Student student;是一个未初始化的结构,阅读它的成员(如strcmp(student.id, id))会调用Undefined Behaviour
旁白:任何时候你发现自己在枚举变量名(s1s2s3,...),你应该问问自己,如果一个 * 数组 * 不会更合适。
看起来最有可能的情况是,您正在寻找写入文件,然后搜索文件的内容。
考虑以下简化示例:

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

struct Student {
    char id[16];
    char name[32];
    char course[32];
};

int write_to_file(const char *fname)
{
    FILE *file = fopen(fname, "w");

    if (!file) {
        perror("fopen");
        return 0;
    }

    struct Student students[] = {
        { "1001", "John", "BSCS" },
        { "1002", "Bob", "BSIT" },
        { "1003", "Jane", "BSIT" },
        { "1004", "Karla", "BSIT" },
        { "1005", "Clarisse", "BSCS" },
        { "1006", "Peter", "BSCS" },
        { "1007", "Bob", "BSCS" },
        { "1008", "Stewie", "BSIT" },
        { "1009", "Bryan", "BSCS" },
        { "1010", "Kent", "BSIT" }
    };

    size_t length = sizeof students / sizeof *students;

    for (size_t i = 0; i < length; i++) {
        int rc = fprintf(file, "%s,%s,%s\n",
                    students[i].id,
                    students[i].name,
                    students[i].course);

        if (rc < 0) {
            perror("fprintf");
            fclose(file);
            return 0;
        }
    }

    fclose(file);
    return 1;
}

void find_in_file_by_id(const char *fname, const char *id)
{
    FILE *file = fopen(fname, "r");

    if (!file) {
        perror("fopen");
        return;
    }

    int success = 0;
    struct Student student;

    while (3 == fscanf(file, "%15[^,],%31[^,],%31[^\n]\n",
                student.id, student.name, student.course)) {
        if (0 == strcmp(student.id, id)) {
            printf("Found student: <%s> <%s> <%s>\n",
                    student.id,
                    student.name,
                    student.course);
            success = 1;
            break;
        }
    }

    fclose(file);

    if (!success)
        fprintf(stderr, "Student ID <%s> not found.\n", id);
}

int main(void)
{
    const char *file_name = "students.csv";

    if (!write_to_file(file_name))
        return EXIT_FAILURE;

    char input[256];

    printf("Enter student ID: ");

    if (!fgets(input, sizeof input, stdin))
        return EXIT_FAILURE;

    input[strcspn(input, "\n")] = '\0'; /* remove the newline */

    find_in_file_by_id(file_name, input);
}

示例用法:

$ ./a.out
Enter student ID: 1004
Found student: <1004> <Karla> <BSIT>
$ ./a.out
Enter student ID: 1234
Student ID <1234> not found.

相关问题