我正在使用" C编程语言"进行练习。 Brian W. Kernighan撰写的第2版& Dennis M. Ritchie。
练习1.9 让我困惑。所以这就是:
我很困惑这个。我在这里发布我的问题,因为其他学习者并没有像我想要的那样做这个练习。在这里,使用"编写一个程序将其输入复制到输出,用一个空格替换每一个空格的字符串"。
-
来表示空白:
Input: ----hello
Output: -hello
但我想要这个:
Input: ----hello
Output: ----hello
Input: ----
Output: -
所以这是我的计划:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int character; /* input character */
int non_blank = 0; /* is any non blank character */
while ((character = getchar()) != EOF) {
if (character != '\n') {
putchar(character);
if (character != ' ') {
non_blank = 1;
}
}
else {
if (non_blank == 0 ) {
putchar('\b'); /* go to previous line (blabla\n|cursor|) (blabla|cursor|\n) */
putchar('\r'); /* carriage return */
putchar(' '); /* put one space */
putchar('\0'); /* and put the end of line */
}
non_blank = 0;
}
}
return EXIT_SUCCESS;
}
但是空格不会被删除。
Input: ------|\n
Output: -|-----
以下是我对转义序列的实验:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("bbbbbbbbbbbbbbb");
putchar('\b'); /* jump to previous line */
putchar('\r');
putchar('b');
putchar('\0');
return EXIT_SUCCESS;
}
|
是一个游标。
Output: b|
但是当我添加换行符时,它不起作用。如何使用换行符?
答案 0 :(得分:0)
所需的算法应该是这样的:
implement a state machine with two states. NotInSpaces and InSpaces
(with just two states, a boolean would work)
no special treatment for '\n'
set state to NotInSpaces
Loop: (exit loop on EOF)
getchar
if char is space
then if state is NotInSpaces
then set state to InSpaces
output space
endif
else
output char
endif
end Loop:
output '\n' // to force output buffer flush
答案 1 :(得分:0)
代码的问题在于,只要您处理完字符就会打印字符,并且一旦检测到它们必须压缩到一个空格,就会尝试擦除它们。
您的方法是有效的,但您必须首先知道\b
仅使光标返回一个空格(不删除),因此正确的方法是发出\b \b
(退格,用于覆盖字符的空间和另一个用于将光标留在正确位置的退格键。
另一种方法是等待打印任何内容,直到我们知道该行是否以非空白字符串终止,或者它是否仅以\n
字符结束。
以下代码计算空白字符并管理两个状态以应对该问题。当然,您将能够遵循代码,并且我已尝试使用注释进行记录。
#include <stdio.h>
int main()
{
int c;
int state = 0;
int nblanks = 0;
/* read chars up to EOF */
while((c = getchar()) != EOF) {
switch (state) {
case 0: /* no nonblank character read */
switch (c) {
/* accumulate number of blanks to be printed in case
* we see a nonblank char before \n */
case ' ': nblanks++; break;
/* in this case we have seen nblanks before a \n, so
* we have to print only one blank and \n */
case '\n':
puts(" "); /* just one space */
nblanks = 0; /* reset counter */
break;
/* nonblank char */
default:
/* print all the blanks up to here */
printf("%*s%c", nblanks, "", c);
state = 1; /* switch state */
break;
} /* switch */
break;
/* we have read at least a nonblank char, so we must
* echo the line until the end. */
case 1:
if (c == '\n') {
state = 0;
nblanks = 0;
} /* if */
putchar(c);
break;
} /* switch */
} /* while */
} /* main */
它与K&amp; R第二版完全兼容,因此您只需编译并运行。
或许最难以遵循的声明是中间的printf()
行。星号*
允许我使用printf参数指定字段的宽度,并且传递空字符串""
允许我打印带有nblanks
空格的字符串。最终的%c
格式是打印刚刚读取的非空白字符。这导致了紧凑而有效的代码。
最后,你有一些错误的想法:
\b
只返回终端中的一个字符(一个字符,而不是一行)。我不仅在打印到终端或打印机时工作。它不适用于文件(该文件会将退格作为普通字符放在里面)\r
使光标转到第一个显示列。这仅适用于屏幕和打印机。它不能在文件中工作,它将作为普通字符包含在内。\0
是C程序用来完成字符串的字符(知道它们在内存中的位置)它不是输出设备的特殊字符,它什么也不做(它是ASCII NUL字符) ,在输出终端上什么都不做)\b \b
方法,它将不会删除空白,因为空间不会擦除已打印的内容。那么,你必须遵循第二种方法。