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

时间:2011-05-08 21:17:51

标签: objective-c c

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

请帮助

/ * Assment Label loop - 循环遍历assment标签并输入百分比和名称。 * /

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

/ * Print Statement * /

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

输入数据

Prog1 20
Quiz 20
Prog2 20
Mdtm 15
Final 25

通过控制台输出

Prog1QuizQuizProg2MdtmMdtmFinal

2 个答案:

答案 0 :(得分:3)

最终诊断

您没有显示声明......但您必须为字符串分配5个字符:

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

Prog1Quiz  20
Quiz       20
Prog2Mdtm  20
Mdtm       15
Final      25

您不允许终端为null。你没有告诉我们是什么导致了这个错误!而且你从打印输出中省略了换行符这一事实掩盖了这个问题。

发生的事情是'Prog1'占用了你读入的字符串的所有5个字节,并在第6个字节写入空值;然后从第六个字节开始读入测验。 当printf()去读取'Prog1'的字符串时,它会在第一个空值处停止,这是'测验'的'z'之后的那个,产生显示的输出。重复'Prog2'和'Mtdm'。如果在“最终”之后有一个条目,它也会受到影响。你很幸运,周围有足够的零字节可以防止任何可怕的超支。

这是一个基本的缓冲区溢出(事实上,由于数组在堆栈上,它是一个基本的Stack Overflow);你试图将6个字符(Prog1加'\0')压缩成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 reading\n");
            exit(1);
        }
        i++;
    }

    /* Print Statement */

    i = 0;
    while (i < totalGradedItems)
    {
        printf("%-9s %3d\n", 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 %3d\n", 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)

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

Prog       1

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

尽管有令人讨厌的价值,如果你想让你的scanf()字符串调整到它所读取的数据变量的大小,你必须做一些类似于我在这里做的事情 - 使用正确的尺寸值。

答案 1 :(得分:0)

我想,你需要放一个

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

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