大家好,我遇到了一个奇怪的问题,当我使用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
这证明,字符串数组的大小需要更大,然后在那里清除。