struct 的字符串成员正在附加其他字符串成员,均使用 scanf 解析

Posted

技术标签:

【中文标题】struct 的字符串成员正在附加其他字符串成员,均使用 scanf 解析【英文标题】:String member of struct is appending other string member, both parsed with scanf 【发布时间】:2021-01-29 21:35:15 【问题描述】:

我对 C 有点陌生。所以,我动态创建了一个结构数组,并希望从用户那里获取输入并存储在数组中。

struct course
    char code[CODE_LENGTH];
    char name[NAME_LENGTH];
    int credits;
;

第二个字符串成员name 存储得很好。 第一个字符串成员 code 附加了第二个字符串成员。

程序代码:

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

#define CODE_LENGTH 7
#define NAME_LENGTH 3

struct course *createList()
    int n;
    printf("Enter no. of courses you wish to take: ");
    scanf("%d", &n);
    
    struct course *courses = (struct course*)malloc(sizeof(struct course)*n);

    for(int i=0;i<n;i++)
        printf("Enter Course Code: ");
        scanf("%s",courses[i].code);
        printf("Enter Course name: ");
        scanf("%s",courses[i].name);
        printf("Enter no. of credits: ");
        scanf("%d",&courses[i].credits);
        printf("\n");

        printf("%s\n%s ",courses[i].code,courses[i].name);
    
    return courses;

int main()
    struct course *c = NULL;
    int credit;
    c=createList();
    free(c);
    return 0;

输出:

Enter no. of courses you wish to take: 2
Enter Course Code: CS6101D
Enter Course name: DS
Enter no. of credits: 4

CS6101DDS
DS Enter Course Code: 

如果CODE_LENGTH 是7,code 怎么能存储更多,为什么还要附加另一个字符串? 帮帮我!

【问题讨论】:

C 和 C++ 是不同的编程语言。 无关:建议使用struct course *courses = malloc(n * sizeof *courses);而不是C中的struct course *courses = (struct course*)malloc(sizeof(struct course)*n);,它更短更安全。 【参考方案1】:

如果CODE_LENGTH 是 7,代码如何存储更多,为什么还要附加另一个字符串?

不能,事实上它只能存储6个字符加上空字节,你程序的不稳定行为是undefined behavior的结果。

您的代码极易受到缓冲区溢出的影响,您永远不应该在 scanf 中使用 %s 说明符,就像它一样,它并不比 gets 好,并且因为太危险且容易受到攻击而从标准中删除缓冲区溢出攻击,必须将输入限制为目标缓冲区的大小:

printf("Enter Course Code: "); 
scanf("%6s", courses[i].code);// %6s, 7 - 1, last element stores null byte
printf("Enter Course name: "); 
scanf("%2s", courses[i].name) //same idea

请注意,如果输入大于缓冲区的容量,剩余的字符将保留在stdin 缓冲区中,并由下一个scanf 解析,您可能需要将其清除。我刚刚回答了一个关于如何以稳健的方式仍然使用 scanf check it out 的问题。


题外话:

struct course *courses = (struct course*)malloc(sizeof(struct course)*n);

您应该删除演员表,它不是必需的,并且可以隐藏分配错误。

使用变量本身来推断大小也是一个好习惯,它使代码更易于维护:

struct course *courses = malloc(sizeof *courses * n);

【讨论】:

【参考方案2】:

您可能正在读取 7(或更多?)字符的字符串,例如 CS6101D,这将需要存储 8 chars,因为NUL 终止符'\0' 需要多一个charscanf 会自动添加。

因此,您的代码正试图在courses[i].code[8] 上写入,它具有超出范围的索引。这是 C 中未定义的行为,可能会导致任何结果,包括您得到的结果。

【讨论】:

以上是关于struct 的字符串成员正在附加其他字符串成员,均使用 scanf 解析的主要内容,如果未能解决你的问题,请参考以下文章

golang中struct成员变量的标签(Tag)说明和获取方式

不可变值类型 [string] 只有名为 append 的变异成员

Golang中的struct能不能比较

struct包装:如何在开头添加struct成员?

如何将interface 转成struct数组

结构体struct和联合体union(联合)有啥区别呢?