下面是我的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条换行符。我想念什么?
编辑:我知道可以更有效地完成此操作,但这是我的第一次尝试,我将其作为学习打印换行符原因的学习经验。
答案 0 :(得分:1)
您的代码大部分是正确的。在读取输入结束时,变量i
已保存输入字符串的长度,因此只需将其用作开始反转的点即可。您可能不需要在s
的末尾保存回车符,因为您不希望它在输出的开头。还要注意,在从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;
}
答案 1 :(得分:1)
运行程序时,我得到一个换行符。
$ ./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$
简单的解决方法是不将最后一个换行符放在第一个换行符中,并在返回之前打印换行符。
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--] = '\0';
// 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
的原因,因为我们只从那里读取我们编写的内容。无论如何,最好在末尾添加一个空值。