【问题标题】:C - garbage characters even with null terminator, structuresC - 即使带有空终止符,结构的垃圾字符
【发布时间】:2017-04-15 06:10:24
【问题描述】:

因此,作为学校作业的一部分,我必须创建一个应用程序来使用结构处理各种字段的输入。在 main 之外定义如下

typedef struct stud {
    struct number {
        int studNum;
    } number;
    struct name {
        char firstName[NAME_SIZE];
        char lastName[NAME_SIZE];
    } name;
    struct cellNum {
        int areaCode;
        int prefix;
        int suffix;
    } cellNum;
    struct courses {
        struct fall {
            char className[NAME_SIZE];
            float mark;
        } fall;
        struct winter {
            char className[NAME_SIZE];
            float mark;
        } winter;
    } courses;
} stud;

NAME_SIZE 定义为 30

我访问结构如下

stud studArray[100]; // max 100 students
stud *studPtr;

for (int i = 0; i < studCount; i++) {
    studPtr = &studArray[i];
    initializeStrings(studPtr[i]);
    getNum(studPtr[i]);
    getName(studPtr[i]);
    getCell(studPtr[i]);
    getCourses(studPtr[i]);
}

initializeStrings 是我添加空终止符的地方

void initializeStrings(stud student) {
    student.name.firstName[NAME_SIZE - 1] = '\0'; 
    student.name.lastName[NAME_SIZE -1] = '\0';
    student.courses.fall.className[NAME_SIZE -1] = '\0';
    student.courses.winter.className[NAME_SIZE -1] = '\0';
}

这就是问题所在:在我的各种函数中,当我尝试访问写入字符串的任何信息时,我会得到一个看起来像横向 T 的垃圾字符的输出,但前提是我以不同的功能访问数据。

示例:这是获得 2 门课程和分数的代码

void getCourses(stud student) {
    getchar();
    printf("\n%s", "Enter Course name - Fall 2016: ");
    fgets(student.courses.fall.className, NAME_SIZE - 1, stdin);
    fflush(stdin); // suggested by my prof to fix the issue, did nothing

    printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
    scanf("%f", &student.courses.fall.mark);

    getchar();
    printf("\n%s", "Enter Course name - Winter 2017: ");
    fgets(student.courses.winter.className, NAME_SIZE - 1, stdin);

    printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
    scanf("%f", &student.courses.winter.mark);
}

如果我输入 helloWorld 作为课程名称,系统会正确打印 输入 helloWorld 收到的标记

但是当我尝试从我的打印功能打印数据时:

void printData(stud student) {
// various other values (none of which work)
printf("\t%s\t%s\t%f\n", "Fall2016", student.courses.fall.className, student.courses.fall.mark);
}

我得到垃圾数据输出(image

欢迎任何帮助/代码批评

编辑:谢谢 Eddiem 和其他所有人,你们为我指明了正确的方向。

【问题讨论】:

  • printData(stud) 在哪里被调用?我在代码 sn-p 2 中看不到它。
  • 在一个单独的 for 循环中 sn-p 2 for (int i = 0; i &lt; studCount; i++) { printData(studPtr[i]); } 这允许在打印决赛桌之前输入 2 个或更多学生
  • 您将struct 传递给initializeStrings 和其他struct 成员到无法返回的函数,因为您只传递了一个副本。您可以使用 stud studArray[100] = {0}; 初始化您的结构
  • fflush(stdin); 调用未定义的行为
  • 很好的问题。坚持下去。

标签: c string struct character garbage


【解决方案1】:

这段代码真的没有意义。首先,为什么不将stud* 指针传递给您在下面调用的每个函数?无论如何,您在这里的方式是初始化studPtr 以指向studArray 数组中的特定元素,但随后仍将i 索引到该指针中。你可能会通过studPtr[0],但这很奇怪。

原码:

stud studArray[100]; // max 100 students
stud *studPtr;

for (int i = 0; i < studCount; i++) {
    studPtr = &studArray[i];
    initializeStrings(studPtr[i]);
    getNum(studPtr[i]);
    getName(studPtr[i]);
    getCell(studPtr[i]);
    getCourses(studPtr[i]);
}

我建议进行如下修改:

void initializeStrings(stud *student) {
    student->name.firstName[NAME_SIZE - 1] = '\0'; 
    student->name.lastName[NAME_SIZE -1] = '\0';
    student->courses.fall.className[NAME_SIZE -1] = '\0';
    student->courses.winter.className[NAME_SIZE -1] = '\0';
}

如果函数当前采用stud 参数,则需要对每个函数进行这些修改。然后,将循环初始化更改为:

for (int i = 0; i < studCount; i++) {
    initializeStrings(&studArray[i]);
    getNum(&studArray[i]);
    getName(&studArray[i]);
    getCell(&studArray[i]);
    getCourses(&studArray[i]);
}

【讨论】:

  • 谢谢!完美运行
【解决方案2】:

这是不对的:

studPtr = &studArray[i];
initializeStrings(studPtr[i]);

假设您要访问数组的第三个元素,因此 i 为 3。这为您提供了第三个条目的偏移量:

studPtr = &studArray[i];

现在你使用一个索引......

initializeStrings(studPtr[i]);

因此,您访问的元素比您已经访问的第三个元素更远;即元素 6。您可以看到您将离开数组的末尾,或者访问尚未初始化的元素。

所以使用任何一个

studPtr = &studArray[i];
initializeStrings(studPtr);

initializeStrings(&studArray[i]);

这两个相当于同一个东西,并且指向同一个地方。

【讨论】:

    【解决方案3】:

    问题是您没有通过引用传递(也就是使用指针)。如果你不使用指针,那么像getCourses 这样的函数会修改临时数据而不是直接修改数据。因此,原始数据中的垃圾值永远不会被删除。

    改变

    void getCourses(stud student) { // no pointer = copy data to temporary memory, original data is unmodified in this function.
    getchar();
    printf("\n%s", "Enter Course name - Fall 2016: ");
    fgets(student.courses.fall.className, NAME_SIZE - 1, stdin);
    fflush(stdin); // suggested by my prof to fix the issue, did nothing
    
    printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
    scanf("%f", &student.courses.fall.mark);
    
    getchar();
    printf("\n%s", "Enter Course name - Winter 2017: ");
    fgets(student.courses.winter.className, NAME_SIZE - 1, stdin);
    
    printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
    scanf("%f", &student.courses.winter.mark);
    }
    

    void getCourses(stud *student) { // notice the pointer used. Original data is to be modified.
    getchar();
    printf("\n%s", "Enter Course name - Fall 2016: ");
    fgets(student->courses.fall.className, NAME_SIZE - 1, stdin);
    fflush(stdin); // suggested by my prof to fix the issue, did nothing
    
    printf("\n%s%s%s", "Enter mark received for ", student.courses.fall.className, ": ");
    scanf("%f", &student->courses.fall.mark);
    
    getchar();
    printf("\n%s", "Enter Course name - Winter 2017: ");
    fgets(student->courses.winter.className, NAME_SIZE - 1, stdin);
    
    printf("\n%s%s%s", "Enter mark received for ", student.courses.winter.className, ": ");
    scanf("%f", &student->courses.winter.mark);
    }
    

    此外,您必须修改 for 循环以处理指针。即把getCourses(studPtr[i]);改成getCourses(&amp;studPtr[i]);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-12
      • 2010-09-21
      • 2016-01-13
      • 1970-01-01
      • 1970-01-01
      • 2011-04-15
      • 1970-01-01
      相关资源
      最近更新 更多