C程序打印换行符

C program printing newlines

下面是我的 K&R 练习 1-19 的 C 程序。

#include <stdio.h>
#define MAXLINE 999

int main (void) {
    printf("Line Reverser.\n");
    printf("This program reverses the input per line.\n");
    middle ();
}
int middle (void) {
    reverse ();
    printf("\n");
    middle ();
}
int reverse (void) {
    int i, c;
    char s[MAXLINE] = {0};
    for (i = 0; ((c = getchar()) != '\n') && (i <= MAXLINE); ++i) {
        s[i] = c;
    };
    if (c == '\n') {
        s[i] = c;
        ++i;
    };
    for (i = MAXLINE; (s[i] != '0') && i >= 0; --i) {
        printf("%c", s[i]);
    };
    return 0;
}

当我 运行 使用 Code::Blocks 时,如果输入是 asdf,我会得到以下输出。

Line Reverser.
This program reverses the input per line.
asdf










fdsa

我希望输出只是 fdsa,没有 10 个换行符。 我不明白为什么要打印 10 个换行符。我错过了什么?

编辑:我知道这可以更有效地完成,但这是我的第一次尝试,我将其作为一种学习经验,了解为什么要打印换行符。

您的代码大部分是正确的。在读取输入结束时,变量 i 已经保存了输入字符串的长度,因此只需以此为起点开始反转即可。您可能不需要在 s 末尾保存回车符 return,因为您不希望它出现在输出的开头。另请注意,在从 main 调用它之前,您需要声明 reverse。所以你可以把函数声明放在main上面而把定义留在下面,或者把整个函数定义移到main上面。所以,这样的事情是正确的:

#include <stdio.h>
#define MAXLINE 999

int reverse (void);

int main (void) {
    printf("Line Reverser.\n");
    printf("This program reverses the input per line.\n");
    reverse ();
}

int reverse (void) {
    int i, j, c;
    char s[MAXLINE] = {0};
    for (i = 0; ((c = getchar()) != '\n') && (i <= MAXLINE); ++i) {
        s[i] = c;
    }

    for (j = i; (s[j] != '0') && j >= 0; --j) {
        printf("%c", s[j]);
    }
    printf("\n");
    return 0;
}

当我 运行 你的程序时,我得到一个换行符。

$ ./test
Line Reverser.
This program reverses the input per line.
foo

oof$ 

有很多问题。首先,最后的 prinf("\n") 永远不会出现 运行,因为它紧跟在 return 之后。因此反转的行上没有换行符。

for (i = MAXLINE; (s[i] != '0') && i >= 0; --i) {
    printf("%c", s[i]);
};
return 0;
printf("\n"); // never runs

其次,代码明确地将尾随换行符放回 s。这就是为什么在输入和它的反转之间有一个额外的换行符。

if (c == '\n') {
    s[i] = (char)c;
    ++i;
};

我们可以通过简单的调试看到这一点printf("s = '%s'\n", s);

$ ./test
Line Reverser.
This program reverses the input per line.
foo
s = 'foo
'

oof$

简单的解决方法是不放置最后一个换行符,并在 return.

之前打印换行符
int reverse (void) {
    int i, c;
    char s[MAXLINE] = {0};
    for (i = 0; ((c = getchar()) != '\n') && (i <= MAXLINE); ++i) {
        s[i] = (char)c;
    };
    for (i = MAXLINE; (s[i] != '0') && i >= 0; --i) {
        printf("%c", s[i]);
    };
    printf("\n");
    return 0;
}

$ ./test
Line Reverser.
This program reverses the input per line.
foo
oof
$

还有一个错误,虽然它不是问题的原因。 (s[i] != '0') 正在检查 s[i] 是否是字符 0 而不是数字 0。使用您的测试数据,它实际上什么都不做。

for (i = MAXLINE; (s[i] != '0') && i >= 0; --i) {
    printf("%d: %c\n", i, s[i]);
}

这个循环之所以有效,是因为 s 被初始化为所有空字节。每个字符都被打印出来,但它们都是空的。我们也可以通过打印 i 来看到这一点。

for (i = MAXLINE; (s[i] != '0') && i >= 0; --i) {
    printf("%d: %c\n", i, s[i]);
}

$ ./test
Line Reverser.
This program reverses the input per line.
foo
999: 
998: 
...
4: 
3: 
2: o
1: o
0: f

从行尾而不是缓冲区末尾读取可以使这更简单、更有效。我们可以在阅读时记住字符串有多大。

#include <stdio.h>

void reverse(void) {
    // Use BUFSIZ from stdio
    char buf[BUFSIZ];

    // Read a line, but not the newline.
    // buf_idx remembers where the end of the line is.
    size_t buf_idx;
    int c;
    for(
        buf_idx = 0;
        ((c = getchar()) && (c != EOF) && (c != '\n') );
        buf_idx++
    ) {
        buf[buf_idx] = (char)c;
    }

    // A for loop always executes all its statements, even when the
    // condition fails, so we need to back up one.
    // Stick a null on the end of buf. It's not necessary, but just
    // in case we want to print it for debugging.
    buf[buf_idx--] = '[=17=]';


    // Print the characters from the end to the start.
    for( int i = (int)buf_idx; i >= 0; i-- ) {
        printf("%c", buf[i]);
    }

    // Print a trailing newline.
    printf("\n");
}

BUFSIZ 是由操作系统决定的读取缓冲区的合适大小。它由 stdio.h.

提供

没有必要花费 运行 时间来初始化 buf,因为我们只会从中读取我们所写的内容。尽管无论如何在末尾添加一个 null 可能是个好主意。