【问题标题】:scanf does not workscanf 不工作
【发布时间】:2015-04-18 16:41:25
【问题描述】:

我正在实现一个程序,该程序从标准输入或文件中读取学生 ID 和姓名,并使它们按姓名排序并按数字排序。有趣的是我不明白为什么但 scanf 不起作用。这是我使用 scanf 时的代码:

int n=0;
while(n<SIZE){
    scanf("%d %s\n",&std_array[n].id, std_array[n].name);
    n++;
}
for(int i=0; i<SIZE; i++)
    printf("%d %s\n",std_array[i].id,std_array[i].name);

这是我的结构:

struct Student {
char *name;
int id;};

当我从文件中读取并打印它们时,输出是:

> 12586546 (null) 0 (null) 0 (null) 0 (null) 0 (null) 0 (null) 0 (null)
> 0 (null) 0 (null) 0 (null)

虽然文件有一些数字和名称,如 21456764 john 45797654 fred 等,但它没有成功读取。

注意:我知道我们像你们建议的那样修复 struct 的方式,但我必须学习使用 char 指针执行此操作的方式...

【问题讨论】:

  • 您应该始终测试scanf的结果项计数

标签: c pointers scanf dynamic-memory-allocation


【解决方案1】:

当这样做时:

struct Student {
char *name; // This does not allocate memory
int id;};

这里,name 是一个指针,没有分配内存,表现得像一个未初始化的literal字符串

试图修改它会产生未定义的行为

替换为:

struct Student {
char name[50];
int id;};

struct Student {
char name[] = "Initial value gives maximum length. Do not write more!";
int id;};

【讨论】:

  • 好的,我看到了区别,但是如果我使用 malloc,那也能解决问题吗?
  • @yağızözbekevren 通过创建可变字符串,您需要通过指定大小或初始化来指定限制。
  • name is basically an uninitialized literal string....是吗?恕我直言,这是一个指针,对吧?
  • 详细信息:“尝试修改它会产生未定义的行为。”嗯,更好的说法是“尝试修改 name 指向的内容是未定义的行为,因为它未初始化。”。 OP post的整个想法是正确修改指针name
【解决方案2】:

这会根据需要为指针分配内存。中间变量用于保存字符串,然后在结构中只分配足够的内存加 1 用于终止 '\0'。

int n=0;
char name[100];//longest possible name
while(n<SIZE && ( scanf("%d%99s",&std_array[n].id, name) == 2)) {// successfully scanned two items
    std_array[n].name = malloc ( strlen ( name) + 1));
    if ( std_array[n].name == NULL) {
        printf ( "malloc failed\n");
        // break or return or exit(1) as appropriate
    }
    strcpy ( std_array[n].name, name);
    n++;
}
for(int i = 0; i < n; i++)
    printf("%d %s\n",std_array[i].id,std_array[i].name);

最终你会想要释放内存

for ( i = 0; i < n; i++) {
    free ( std_array[i].name);
}

【讨论】:

  • 这会有所帮助。现在就试试。
  • 1) 建议 "%d%99s" 而不是 "%d %s\n" :将输入限制为 99 并删除 '\n' 2) 使用 for(int i=0; i&lt;n; i++)n,而不是 SIZE
【解决方案3】:

第 1 点

在使用之前将内存分配给name。否则,如果未初始化使用,它不会指向任何 有效 内存来读取或写入。您可以使用malloc() 来分配内存。另外,一旦完成,请不要忘记在使用完内存后free()

第 2 点

scanf() 中删除\n

【讨论】:

    【解决方案4】:

    这是修改后的代码

    struct Student
    {
    char name[20];
    int id;
    };
    struct Student std_array[SIZE];
    int n=0;
    while(n<SIZE)
    {
        scanf("%d %s", &std_array[n].id, std_array[n].name);
        n++;
    }
    n=0;
    while(n<SIZE)
    {
        printf("%d %s\n", std_array[n].id, std_array[n].name);
        n++;
    }
    

    希望这会有所帮助...,

    【讨论】:

    • 嗯,我明白,但这是我的家庭作业。讲师告诉用“char *name”和“int id”制作这个结构。我必须学会这样做......
    • 你还需要测试scanf的返回值才能正确
    【解决方案5】:

    正如用户 3121023 告诉我的那样,它起作用了。固定代码如下:

    struct Student {
    char *name;
    int id;
    };
    
    struct Student std_array[SIZE];
    int cmpfunc (const void * a, const void * b);
    struct Student *order_by_number(struct Student *array);
    
    int main(int argc, char **argv){
    
    int n=0;
    char name[100];
    while(n<SIZE){
        scanf("%d %s\n",&std_array[n].id, name);
        std_array[n].name = malloc(strlen(name)+1);
        strcpy(std_array[n].name ,name);
        n++;
    }
    for(int i=0; i<SIZE; i++)
        printf("%d %s\n",std_array[i].id,std_array[i].name);
    
    order_by_number(std_array);
    
    for(int i=0; i<SIZE; i++)
        printf("%d %s\n",std_array[i].id,std_array[i].name);
    }
    

    我已经完成了,你们帮助我。结案:)

    【讨论】:

    • scanf("%d %s\n" 很弱。 1) 未检查返回值。检查2。 2) 字符串大小不受限制"%99s" 优于"%s" 3) " ""%d %s\n" 中不需要。 4) "%d %s\n" 中的 "\n" 肯定是控制台 I/O 的问题,因为它要求 scanf() 在检测到额外的非空白或 EOF 之前不返回。最好放下。它不会简单地扫描 1 '\n'
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    相关资源
    最近更新 更多