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

发布于 2024-11-06 11:21:46 字数 623 浏览 0 评论 0原文

大家好,我遇到一个奇怪的问题,当我使用 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

Hi all I am having a strange issue, when i use scanf to input data it repeats strings and saves them as one i am not sure why.

Please Help

/* Assment Label loop - Loops through the assment labels and inputs the percentage and the name for it. */

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++;
}

Input Data

Prog1 20
Quiz 20
Prog2 20
Mdtm 15
Final 25

Output Via Console

Prog1QuizQuizProg2MdtmMdtmFinal

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

笑咖 2024-11-13 11:21:46

最终诊断

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

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

Prog1Quiz  20
Quiz       20
Prog2Mdtm  20
Mdtm       15
Final      25

You did not allowed for终端为空。而且您没有向我们展示导致该错误的原因!事实上,您从打印输出中省略了换行符,这一事实掩盖了问题。

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

这是一个基本的缓冲区溢出(事实上,由于数组在堆栈上,所以它是一个基本的堆栈溢出);您正在尝试将 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()< /code> 生成格式字符串“%4s%d”。编译后的代码如下:

Prog       1

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

尽管有麻烦的价值,如果您想让 scanf() 字符串调整到它正在读入的数据变量的大小,您必须执行类似于我在这里所做的操作 - 格式化字符串使用正确的尺寸值。

Final diagnosis

You don't show your declarations...but you must be allocating just 5 characters for the strings:

When I adjust the enum MAX_ASSESSMENTLEN from 10 to 5 (see the code below) I get the output:

Prog1Quiz  20
Quiz       20
Prog2Mdtm  20
Mdtm       15
Final      25

You did not allow for the terminal null. And you didn't show us what was causing the bug! And the fact that you omitted newlines from the printout obscured the problem.

What's happening is that 'Prog1' is occupying all 5 bytes of the string you read in, and is writing a null at the 6th byte; then Quiz is being read in, starting at the sixth byte.
When printf() goes to read the string for 'Prog1', it stops at the first null, which is the one after the 'z' of 'Quiz', producing the output shown. Repeat for 'Prog2' and 'Mtdm'. If there was an entry after 'Final', it too would suffer. You are lucky that there are enough zero bytes around to prevent any monstrous overruns.

This is a basic buffer overflow (indeed, since the array is on the stack, it is a basic Stack Overflow); you are trying to squeeze 6 characters (Prog1 plus '\0') into a 5 byte space, and it simply does not work well.


Preliminary diagnosis

First, print newlines after your data.

Second, check that scanf() is not returning errors - it probably isn't, but neither you nor we can tell for sure.

Third, are you sure that the data file contains what you say? Plausibly, it contains a pair of 'Quiz' and a pair of 'Mtdm' lines.

Your variable j is unused, incidentally.

You would probably be better off having the input loop run until you are either out of space in the receiving arrays or you get a read failure. However, the code worked for me when dressed up slightly:

#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;
}

For the quoted input data, the output results are:

Prog1      20
Quiz       20
Prog2      20
Mdtm       15
Final      25

I prefer this version, though:

#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;
}

Of course, if I'd set up the scanf() format string 'properly' (meaning safely) so as to limit the length of the assessment names to fit into the space allocated, then the loop would stop reading on the second attempt:

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

With MAX_ASSESSMENTLEN at 5, the snprintf() generates the format string "%4s%d". The code compiled reads:

Prog       1

and stops. The '1' comes from the 5th character of 'Prog1'; the next assessment name is '20', and then the conversion of 'Quiz' into a number fails, causing the input loop to stop (because only one of two expected items was converted).

Despite the nuisance value, if you want to make your scanf() strings adjust to the size of the data variables it is reading into, you have to do something akin to what I did here - format the string using the correct size values.

凉城已无爱 2024-11-13 11:21:46

我想,你需要

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

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

i guess, you need to put a

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

space between %s and %d here.

And it is not saving as one. You need to put newline or atlease a space after %s on print to see difference.

add:

when i tried

#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;
}

with inputs

123456
qwerty
sdfgh

output is:

12qwsdfghqwsdfghsdfgh

that proves that, the size of string array need to be bigger then decleared there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文