所以我在Ritchie / Kernighan的C编程语言第2版中进行练习。特别练习1.9。 "编写程序将其输入复制到输出中,用一个空格将每个字符串替换一个空格。"
我相信我的解决方案是正确的但每次我点击进入屏幕输出我的线而不是等待EOF。这是预期的行为吗?我只使用他在书中介绍的功能和关键词。
如果我有多个换行符,我怎么强迫它等到我输入eof才输出? Putchar一次只能处理一个角色,所以也许它不可能。
什么是退格?他是用空格键指的是空白区域吗?
/*
Copys its input to its output, replacing each string with multiple blanks with one.
Input - "I am running."
Output - "I am running."
*/
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
for (int c = getchar(); c != EOF; ){
while (c == ' '){
c = getchar();
if (c != ' '){
putchar(' ');
}
}
putchar(c);
c = getchar();
}
return 0;
}
改进了验证:
int _tmain(int argc, _TCHAR* argv[])
{
int c;
while ((c = getchar()) != EOF){
while (c == ' '){
c = getchar();
if (c == EOF){
break;
}
if (c != ' '){
putchar(' ');
}
}
putchar(c);
}
return 0;
}
答案 0 :(得分:1)
看一下theory-behind-getchar-and-putchar-functions它解释了为什么你在每行之后得到输出。
要在程序输出之前强制程序等待EOF,您需要使用某种缓冲区,请查看print-multiple-lines-by-getchar-and-putchar
答案 1 :(得分:1)
您的putchar()
按您希望的方式工作,因为stdin
是行缓冲的,这不是您应该理所当然的。你最好收集字符串,解析它们并将它们作为输出。
这就是我要做的事情:
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 2048
int main(void)
{
char buff[2048];
char *buff_temp = buff;
char *buff_ptr = buff;
unsigned int len = 0;
while (fgets(buff_ptr, sizeof buff, stdin) != NULL) {
len += strlen(buff_ptr) + 1;
buff_ptr += strlen(buff_ptr);
}
buff_ptr = buff;
while (--len) {
while (*buff_ptr == ' ' && buff_ptr[1] == ' ') {
--len;
++buff_ptr;
}
*buff_temp++ = *buff_ptr++;
}
printf("%s\n", buff);
}
答案 2 :(得分:0)
您的程序在EOF之前收集所有输入并且然后立即回复所有输入是不正确的。严格来说,逐行收集和回显输入甚至都不正确 - 只有因为标准输入是行缓冲而得到这个结果,这是常见的,但不是必需的。它实际上做什么是一个逐个字符的回声。
相反,您需要在某种持有空间中记录输入字符,直到您看到EOF,然后回显该空间的全部内容。在输入的形式或大小上没有任何约束,实现它的最简单方法可能是将输入缓冲在临时文件中,直到回复它为止。您也可以缓冲内存中的数据,但是您需要注意保留足够的内存和/或根据需要动态增加缓冲区的大小。
“Backspace”是由退格键(不是空格键)生成的代码,通常被解释为删除紧接在输入位置之前的字符的信号。在ASCII中,即字符8(十进制)。
答案 3 :(得分:0)
退格键是一个由键盘产生的字符(通常有一个键说“&#39;退格&#39;”
使用&#39;煮熟的&#39;输入时,退格区在将输入行传递给程序之前编辑输入行非常方便。 (当命中enter / carriageReturn时,它会被传递给程序。)
通常,当从键盘输入文本时,EOF将永远不会发生。但是,可以从键盘强制执行EOF(取决于操作系统)ctrl-z或ctrl-d
答案 4 :(得分:0)
有很多方法可以解决这个问题。正如其他人已正确显示的那样,如果您知道您的输入不会超过一定的大小,则可以声明static buffer
足以保存您的数据。但是,如果您发现自己处于不知道需要阅读多少数据的情况,那么您可以转向dynamically allocating
缓冲区,这样您就可以增长(或{{1} })根据需要调整缓冲区的大小。以下提供了该方法。 (您可以将文本文件重定向到它作为测试)。
另外,目前还不清楚,如果你想跳过所有空行,或者你只是想在realloc
之前看到输入。无论如何,如果你想跳过空白行,你可以在分配EOF
后在阅读循环中添加一个简单的测试。
p = line;
此示例使用/* skip blank lines */
if (*p == '\n' || *p == '\r')
continue;
代替getline
,这为您提供了2个优势。 (1) fgets
如果您将其初始化为getline
,则会为您分配行缓冲区;并且(2)它返回读取的实际字符数,无需调用NULL
。如果您有疑问,请告诉我们:
strlen
<强>构建/编译强>
没有realloc DEBUG信息:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *realloc_void_on (void *p, size_t o, size_t n, size_t psz);
int main (void) {
char *line = NULL; /* pointer to use with getline () */
char *p = NULL; /* pointer to parse getline return */
ssize_t nchr = 0; /* actual chars read per-line */
size_t n = 0; /* max chars to read (0 - no limit) */
char *buff = NULL; /* buffer to hold all lines read */
char *ep = NULL; /* end pointer for buff */
size_t cbuffsz = 0; /* current buffer size */
size_t nbuffsz = 0; /* new buffer size */
size_t offset = 0; /* offset to orient end pointer */
/* read each line from stdin */
while ((nchr = getline (&line, &n, stdin)) != -1)
{
p = line; /* assign line address to pointer */
/* set required new buff size, realloc, set end ptr, update cbuffsz */
nbuffsz += nchr + 1;
buff = realloc_void_on (buff, cbuffsz, nbuffsz, sizeof *buff);
ep = buff + offset;
cbuffsz = nbuffsz;
while (*p) { /* for each character in line */
*ep++ = *p; /* add char to buff, increment ep */
offset++; /* increment offset */
if (*p == '\t' || *p == ' ') { /* if space, or tab */
while (*p == '\t' || *p == ' ') /* read/discard following spaces */
p++;
}
else
p++; /* if not space, increment pointer */
}
}
/* output complete buffer */
#ifdef DEBUG
printf ("\nBuffer:\n-----\n%s-----\n\n", buff);
#else
printf ("%s\n", buff);
#endif
/* free allocated memory */
if (line) free (line);
if (buff) free (buff);
return 0;
}
/* reallocate memory for p of type size psz, from o to n.
* accepts any pointer p, with current allocation o,
* with the type size psz and reallocates memory to
* n, intializing the new memory to zero and returning
* a pointer to the newly allocated block of memory on
* success, exit otherwise.
*/
void *realloc_void_on (void *p, size_t o, size_t n, size_t psz)
{
void *tmp = realloc (p, n * psz);
#ifdef DEBUG
printf ("\n reallocating %zu to %zu\n", o, n);
#endif
if (!tmp) {
fprintf (stderr, "Error: pointer reallocation failure.\n");
exit (EXIT_FAILURE);
}
p = tmp;
memset (p + o, 0, (n - o) * psz); /* memset new ptrs 0 */
return p;
}
使用realloc DEBUG信息(包括gcc -Wall -Wextra -o buildbuf buildbuf.c
调试信息):
gdb
<强>输入强>
gcc -Wall -Wextra -g -DDEBUG -o buildbuf buildbuf.c
<强>输出强>
I am running.