如何将标准输入读入字符串变量,直到C中的EOF为止?

时间:2010-03-23 00:13:44

标签: c stdin

我收到“总线错误”,试图将stdin读入char*变量。 我只想阅读stdin以上的所有内容并将其放在变量中,然后继续处理变量。

我的代码如下:

char* content;
char* c;
while( scanf( "%c", c)) {
 strcat( content, c);
}

fprintf( stdout, "Size: %d", strlen( content));

但不知怎的,我总是通过调用cat test.txt | myapp返回“Bus error”,其中myapp是上面编译的代码。

我的问题是如何在EOF之前将stdin读成变量?正如您在代码中看到的,我只想打印来自stdin的输入大小,在这种情况下,它应该等于文件test.txt的大小。

我认为只使用scanf就足够了,也许可以通过缓冲方式阅读stdin

5 个答案:

答案 0 :(得分:17)

首先,您传递未初始化的指针,这意味着scanfstrcat将写入您不拥有的内存。其次,strcat期望两个以空字符结尾的字符串,而c只是一个字符。这将再次使其读取您不拥有的内存。您不需要scanf,因为您没有进行任何实际处理。最后,一次读取一个字符是不必要的慢。这是解决方案的开始,为最终字符串使用可调整大小的缓冲区,为fgets调用使用固定缓冲区

#define BUF_SIZE 1024
char buffer[BUF_SIZE];
size_t contentSize = 1; // includes NULL
/* Preallocate space.  We could just allocate one char here, 
but that wouldn't be efficient. */
char *content = malloc(sizeof(char) * BUF_SIZE);
if(content == NULL)
{
    perror("Failed to allocate content");
    exit(1);
}
content[0] = '\0'; // make null-terminated
while(fgets(buffer, BUF_SIZE, stdin))
{
    char *old = content;
    contentSize += strlen(buffer);
    content = realloc(content, contentSize);
    if(content == NULL)
    {
        perror("Failed to reallocate content");
        free(old);
        exit(2);
    }
    strcat(content, buffer);
}

if(ferror(stdin))
{
    free(content);
    perror("Error reading from stdin.");
    exit(3);
}

编辑:正如Wolfer所提到的,输入中的NULL将导致在使用fgets时过早终止字符串。如果可用,getline是更好的选择,因为它处理内存分配并且没有NUL输入问题。

答案 1 :(得分:7)

你的问题是你从未分配过ccontent,因此它们没有指向任何定义的位置 - 它们可能指向某些未分配的内存,或者某些内容没有存在的。然后你将数据放入其中。您需要先分配它们。 (这就是总线错误通常意味着的;你试图进行无效的内存访问。)

(或者,由于c始终只包含一个字符,因此您可以将其声明为char c并将&c传递给scanf。当需要时,不需要声明一个字符串会做的。)

一旦你这样做,你就会遇到确保content足够长以容纳所有输入的问题。您需要猜测您期望的输入量并至少分配那么长的时间(如果超过该值,则会出错),或者如果时间不够长,您需要一个策略来重新分配它。 / p>

哦,你也会遇到strcat期望字符串而不是单个字符的问题。即使您将c作为char*scanf调用也不会使其成为字符串。单字符字符串(在内存中)是一个字符,后跟一个空字符,表示字符串的结尾。 scanf,在扫描单个字符时,不会在其后插入空字符。结果,strcpy不会知道字符串结尾的位置,并且会在内存中寻找空字符。

答案 2 :(得分:6)

既然你不关心实际内容,为什么还要打扰一个字符串呢?我还会使用getchar()

int    c;
size_t s = 0;

while ((c = getchar()) != EOF)
{
  s++;
}

printf("Size: %z\n", s);

此代码将正确处理文件中包含'\0'个字符的情况。

答案 3 :(得分:1)

这里的问题是你引用了一个没有通过malloc分配内存的指针变量,因此结果将是未定义的,并且不是唯一的,通过在未定义的指针上使用strcat指向任何东西,你最终得到了一个总线错误!

这将是所需的固定代码....

char* content = malloc (100 * sizeof(char));
char c;
if (content != NULL){
   content[0] = '\0'; // Thanks David!
   while ((c = getchar()) != EOF)
   {
       if (strlen(content) < 100){
           strcat(content, c);
           content[strlen(content)-1] = '\0';
       }
   }
}
/* When done with the variable */
free(content);

代码强调了程序员管理内存的责任 - 对于每个malloc,如果没有free,则会发生内存泄漏!

修改:感谢 David Gelhar ,因为他在我的故障中指出了他的错误!我修复了上面的代码以反映修复...当然在现实生活中,也许100的固定值可以改为#define,以便通过加倍扩展缓冲区超过realloc的内存量并将其修剪为大小......

答案 4 :(得分:0)

假设你想获得(短于MAXL-1个字符串)字符串而不是用char处理你的文件char,我做了如下:

#include <stdio.h>
#include <string.h>
#define MAXL 256

main(){
  char s[MAXL];
  s[0]=0;
  scanf("%s",s);
  while(strlen(s)>0){
    printf("Size of %s : %d\n",s,strlen(s));
    s[0]=0;
    scanf("%s",s);
  };
}