【问题标题】:Why is this code printing a random character inbetween the input and output lines?为什么这段代码在输入和输出行之间打印一个随机字符?
【发布时间】:2019-08-04 05:03:36
【问题描述】:

我正在尝试编写一个程序(用 C 语言),其中输入被反转并逐行反向打印。在大多数情况下,代码实际上就是这样做的。问题在于,对于我的某些(大部分)输入,我会在控制台中的输入和输出之间得到一个随机字符或一个额外的换行符。

例如,我启动程序,在控制台中输入“testing”,然后按回车键返回“gnitseT”。这已经成功地发生了,这是我所期望的。它看起来像这样:


测试

gnitseT


但是当我在控制台中输入“Hello”时,它看起来像这样:


你好

g(意外)

呵呵


或者,如果我在控制台中输入“running”,而不是在输入和输出行之间出现意外的“g”,我会得到一个额外的换行符。


跑步

这里换行

这里有额外的换行符(意外)

gninnuR


#include <stdio.h>




void reverse(int length, char s[])
{
    int i;

    for (i = length; i >= 0; i--)
    {
        printf("%c", s[i]);
    }
    printf("\n");

}


int main(void)
{
    char smain[2000];
    int c;
    int i;

    i = 0;
    while ((c = getchar()) != EOF)
    {
        smain[i] = c;
        i++;
        if (c == '\n')
        {
            reverse(i, smain);
            i = 0;
        }
    }

    return 0;
}

预期的行为是程序在按下回车键后将反向输入输出到控制台。

有时,尤其是在程序开始时,它会完美运行。

然后,它开始在我的输入和输出之间给我一个随机字符,或者它开始给我一个额外的换行符。

我希望它只以相反的顺序打印输入,而不会在输入和输出之间出现任何意外的奇数字符。

感谢您的帮助。

【问题讨论】:

  • 为什么cint 而不是char
  • 这样就可以处理EOF了。我把它改成了char,问题依旧。
  • 我认为您的 for 循环的开始和结束位置存在问题。
  • 另一个不错的OB1 示例。
  • 这确实是一个问题

标签: c arrays printf character


【解决方案1】:

您的直接问题是您正在阅读并尝试使用

打印超出存储在数组中的字符末尾的一个字符
for (i = length; i >= 0; i--) {
    printf("%c", s[i]);
}

为什么?在main() 中将length 字符添加到smain。在 C 中,数组从零开始。您的字符串中的字符来自 0 -&gt; length-1string 中的 nul-character 位于 s[length],但在这里您永远不会添加 nul-终止 字符,因此该索引处的值只是不确定的)。如果该元素尚未初始化(它不会出现在您的第一个单词或任何等于或长于您当时输入的最长单词的后续单词上)Undefined Behavior 因为您尝试阅读而导致结果并从数组中未初始化的元素打印一个不确定的值。您的终端将如何输出不确定是 undefined -- 并且很可能会导致打印 G

要纠正问题,请循环for (i = length - 1; i &gt;= 0; i++) 或非常简单:

while (length--)
    printf ("%c", s[length]);

putchar ('\n');     /* don't printf a single-character */

注意:不要调用可变参数printf函数来输出单个字符,这就是putchar()的作用)

把它放在一起并修复你的逻辑,这样你就不会添加和打印'\n' 作为你正在反转的每个单词的一部分,你可以这样做:

#include <stdio.h>

#define MAXC 2048   /* if you need a constant, #define one (or more) */

void reverse(int length, char s[])
{
    while (length--)
        printf ("%c", s[length]);

    putchar ('\n');     /* don't printf a single-character */
}


int main (void) {

    char smain[MAXC];
    int c, i = 0;

    while ((c = getchar()) != EOF) {
        if (c == '\n') {
            reverse(i, smain);
            i = 0;
        }
        else
            smain[i++] = c;
    }
    if (i)  /* protect against file with no POSIX end-of-file */
        reverse (i, smain);

    return 0;
}

注意:if {...} else {...} 逻辑防止添加'\n'

使用/输出示例

$ printf "Hello\nGoodbye\n" | ./bin/prnrevlines
olleH
eybdooG

没有 POSIX eof 也能正常工作,例如

$ printf "Hello\nGoodbye" | ./bin/prnrevlines
olleH
eybdooG

【讨论】:

  • 读取并尝试打印空字符”哪个空字符? OP 的代码中根本没有 C 字符串,只有一个 char-array。事实上,代码甚至可能通过读取和打印smain 的未初始化的ith 元素(假设第0 个元素是第一个)来调用未定义的行为。
  • "printf ("%c", s[length]); ... /* don't printf a single-character */" 好吧 ... ;)
  • 啊,没错。我脑子里有一根绳子。所以它只是很好的旧 UB 访问并尝试从未初始化的元素打印不确定的值 - 已修复。谢谢。
  • 谢谢!这做到了。真的很感激。主要问题似乎是反向函数的 for 循环试图打印数组中的额外元素(通过放置 (length - 1) 而不是长度来解决)。再次感谢。
  • 不客气。我希望它有所帮助。有一整类错误被称为“因一个错误而关闭”,正是这种错误(尽管它可能出现在数千种不同的情况下)。任何时候都涉及到循环和索引,如果发生了奇怪的事情,请仔细检查因一个错误而关闭
【解决方案2】:

第 29 行

++i;

这意味着“i”现在有长度+1所以,你已经离开了字符串,你可以把程序改成:

#include <stdio.h>




void reverse(int length, char s[])
{
    int i;

    for (i = length; i >= 0; i--)
    {
        printf("%c", s[i]);
    }
    printf("\n");

}


int main(void)
{
    char smain[2000];
    int c;
    int i;

    i = 0;
    while ((c = getchar()) != EOF)
    {
        smain[i] = c;
        if (c == '\n')
        {
            reverse(i, smain);
            i = 0;
        }
        else i++;
    }

    return 0;
}

【讨论】:

  • 谢谢!这段代码也可以工作,尽管它不能像上面那样通过 (length - 1) 来解决 for 循环问题。相反,它似乎通过在输入 '\n' 时不增加 i 来工作,这意味着数组长度将对应于输入。例如,如果用户输入 abc 并按 enter,i 将递增到 3。将有 4 个数组元素(a、b、c、'\n')填充数组中的 0-3。所以在 reverse 函数中,从 3 开始倒数(i 的值没有从长度中减去 1)不会导致函数尝试打印不存在的元素。再次感谢!
  • 以上只是我的理解。如果有错误,请告诉我。
猜你喜欢
  • 2020-01-16
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-03
  • 2019-06-13
  • 2016-04-20
相关资源
最近更新 更多