目标 c,Scanf() 字符串两次接受相同的值



大家好,我遇到了一个奇怪的问题,当我使用scanf输入数据时,它会重复字符串并将它们保存为一个,我不知道为什么。

请帮忙

/* 断言标签循环

- 循环遍历断言标签并输入百分比和名称。

i = 0;
j = 0;
while (i < totalGradedItems)
{
    scanf("%s%d",  assLabel[i], &assPercent[i]);
    i++;
}

/* 打印报表 */

i = 0;
while (i < totalGradedItems)
{
    printf("%s", assLabel[i]);
    i++;
}

输入数据

Prog1 20
Quiz 20
Prog2 20
Mdtm 15
Final 25

通过控制台输出

Prog1QuizQuizProg2MdtmMdtmFinal

最终诊断

您不显示您的声明...但是您必须只为字符串分配 5 个字符:

当我将枚举MAX_ASSESSMENTLEN从 10 调整为 5 时(请参阅下面的代码),我得到输出:

Prog1Quiz  20
Quiz       20
Prog2Mdtm  20
Mdtm       15
Final      25

您不允许终端空。 而且您没有向我们展示导致错误的原因! 而且您从打印输出中省略换行符的事实掩盖了问题。

正在发生的事情是,"Prog1"占据了你读入的字符串的所有5个字节,并在第6个字节处写入一个null;然后从第六个字节开始读入Quiz。当printf()读取"Prog1"的字符串时,它会在第一个空值处停止,即"测验"的"z"之后的空值,从而产生显示的输出。 对"Prog2"和"Mtdm"重复此操作。 如果在"决赛"之后有一个条目,它也会受到影响。 您很幸运,周围有足够的零字节来防止任何可怕的溢出。

这是一个基本的缓冲区溢出(

事实上,由于数组在堆栈上,所以它是一个基本的堆栈溢出);你试图将6个字符(Prog1加'')压缩到一个5字节的空间中,它根本无法正常工作。


初步诊断

首先,在数据后打印换行符。

其次,检查 scanf() 是否没有返回错误 - 它可能不是,但你和我们都无法确定。

第三,你确定数据文件包含你所说的吗? 合理地,它包含一对"测验"和一对"Mtdm"行。

顺便说一下,您的变量j未使用。

最好让输入循环运行,直到接收数组中的空间不足或读取失败。 但是,代码在稍微打扮时对我有用:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    char assLabel[10][10];
    int  assPercent[10];
    int i = 0;
    int totalGradedItems = 5;
    while (i < totalGradedItems)
    {
        if (scanf("%9s%d",  assLabel[i], &assPercent[i]) != 2)
        {
            fprintf(stderr, "Error readingn");
            exit(1);
        }
        i++;
    }
    /* Print Statement */
    i = 0;
    while (i < totalGradedItems)
    {
        printf("%-9s %3dn", assLabel[i], assPercent[i]);
        i++;
    }
    return 0;
}

对于引用的输入数据,输出结果为:

Prog1      20
Quiz       20
Prog2      20
Mdtm       15
Final      25

不过,我更喜欢这个版本:

#include <stdio.h>
enum { MAX_GRADES = 10 };
enum { MAX_ASSESSMENTLEN = 10 };
int main(void)
{
    char assLabel[MAX_GRADES][MAX_ASSESSMENTLEN];
    int  assPercent[MAX_GRADES];
    int i = 0;
    int totalGradedItems;
    for (i = 0; i < MAX_GRADES; i++)
    {
        if (scanf("%9s%d", assLabel[i], &assPercent[i]) != 2)
            break;
    }
    totalGradedItems = i;
    for (i = 0; i < totalGradedItems; i++)
        printf("%-9s %3dn", assLabel[i], assPercent[i]);
    return 0;
}

当然,如果我"正确"(意味着安全)设置scanf()格式字符串以限制评估名称的长度以适应分配的空间,那么循环将在第二次尝试时停止读取:

...
char format[10];
...
snprintf(format, sizeof(format), "%%%ds%%d", MAX_ASSESSMENTLEN-1);
...
    if (scanf(format, assLabel[i], &assPercent[i]) != 2)

当 5 MAX_ASSESSMENTLEN时,snprintf()生成格式字符串"%4s%d" 。 编译的代码如下:

Prog       1

并停止。 "1"来自"Prog1"的第 5 个字符;下一个评估名称为"20",然后将"测验"转换为数字失败,导致输入循环停止(因为仅转换了两个预期项中的一个)。

尽管有麻烦的值,如果你想让你的scanf()字符串适应它正在读取的数据变量的大小,你必须做一些类似于我在这里做的事情 - 使用正确的大小值格式化字符串。

我想,你需要放一个

scanf("%s%d",  assLabel[i], &assPercent[i]);

此处为 %s 和 %d 之间的空格。

而且它不是作为一个整体保存。您需要在打印的%s之后放置换行符或插入一个空格以查看差异。

加:

当我尝试时

#include <stdio.h>
int main (int argc, const char * argv[])
{
    char a[1][2];
    for(int i =0;i<3;i++)
    scanf("%s",a[i]);
    for(int i =0;i<3;i++)
        printf("%s",a[i]);
    return 0;
}

带输入

123456
qwerty
sdfgh

输出为:

12qwsdfghqwsdfghsdfgh

这证明,字符串数组的大小需要更大,然后在那里清除。

最新更新