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

问题描述 投票:0回答:5

我尝试将

stdin
读入
char*
变量时遇到“总线错误”。 我只想读取过来的全部内容
stdin
并将其首先放入变量中,然后继续处理该变量。

我的代码如下:

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

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

但不知怎的,我总是通过调用

cat test.txt | myapp
返回“总线错误”,其中
myapp
是上面编译的代码。

我的问题是如何读取

stdin
直到 EOF 到变量中?正如您在代码中看到的,我只想打印通过 stdin 输入的大小,在这种情况下它应该等于文件的大小
test.txt

我认为只使用

scanf
就足够了,也许可以缓冲方式来阅读
stdin

c stdin
5个回答
22
投票

首先,您传递未初始化的指针,这意味着

scanf
strcat
将写入您不拥有的内存。 其次,
strcat
需要两个以 null 结尾的字符串,而 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 提到的,使用 fgets 时,输入中的 NULL 将导致字符串提前终止。 getline 如果可用的话是更好的选择,因为它处理内存分配并且不存在 NUL 输入问题。


9
投票

既然你不关心实际内容,为什么还要费心构建一个字符串呢? 我也会用

getchar()
:

int    c;
size_t s = 0;

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

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

此代码将正确处理文件中包含

'\0'
字符的情况。


7
投票

你的问题是你从未分配过

c
content
,所以它们没有指向任何定义的地方——它们可能指向一些未分配的内存,或者根本不存在的东西。 然后你将数据放入其中。 您需要先分配它们。 (这就是总线错误的典型含义;您尝试进行无效的内存访问。)

(或者,由于

c
始终只包含一个字符,因此您可以将其声明为
char c
并将
&c
传递给 scanf。不需要声明一串字符。)

一旦这样做,您将遇到确保

content
足够长以容纳所有输入的问题。 要么你需要猜测你期望有多少输入并至少分配那么长的时间(如果超过这个长度就会出错),要么你需要一个策略来在它不够长的情况下以更大的尺寸重新分配它。

哦,您还会遇到

strcat
需要一个字符串而不是单个字符的问题。 即使您将
c
保留为
char*
scanf
调用也不会使其成为字符串。 单字符字符串是(在内存中)一个字符后跟一个空字符以指示字符串的结尾。
scanf
,当扫描单个字符时,不会在其后面添加空字符。 因此,
strcpy
不会知道字符串的结尾在哪里,并且会在内存中徘徊寻找空字符。


2
投票

这里的问题是,您引用的指针变量没有通过

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
调整内存大小...


0
投票

假设您想要获取(短于MAXL-1字符)字符串而不是逐个字符地处理您的文件,我做了如下操作:

#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);
  };
}
© www.soinside.com 2019 - 2024. All rights reserved.