我正在尝试使用C语言从stdin读取未知长度行。
我在网上看到了这个:
char** str;
gets(&str);
但它似乎给我带来了一些问题,我真的不明白这样做是怎么做的。
你能解释一下为什么这个例子工作/不起作用 以及实现它的正确方法是什么(使用malloc?)
答案 0 :(得分:6)
您不希望指向char
的指针,使用char
的数组
char str[128];
或指向char
char *str;
如果您选择指针,则需要使用malloc
str = malloc(128);
然后您可以使用fgets
fgets(str, 128, stdin);
并删除跟踪换行符
char *ptr = strchr(str, '\n');
if (ptr != NULL) *ptr = '\0';
要读取任意长行,可以使用getline
(添加到GNU版本的libc中的函数):
#define _GNU_SOURCE
#include <stdio.h>
char *foo(FILE * f)
{
int n = 0, result;
char *buf;
result = getline(&buf, &n, f);
if (result < 0) return NULL;
return buf;
}
或使用fgets
和realloc
char *getline(FILE * f)
{
size_t size = 0;
size_t len = 0;
size_t last = 0;
char *buf = NULL;
do {
size += BUFSIZ; /* BUFSIZ is defined as "the optimal read size for this platform" */
buf = realloc(buf, size); /* realloc(NULL,n) is the same as malloc(n) */
/* Actually do the read. Note that fgets puts a terminal '\0' on the
end of the string, so we make sure we overwrite this */
if (buf == NULL) return NULL;
fgets(buf + last, size, f);
len = strlen(buf);
last = len - 1;
} while (!feof(f) && buf[last] != '\n');
return buf;
}
使用
调用它char *str = getline(stdin);
if (str == NULL) {
perror("getline");
exit(EXIT_FAILURE);
}
...
free(str);
答案 1 :(得分:3)
首先,gets()
无法阻止缓冲区溢出。这使得它从最新的C标准中删除它是如此危险。不应该使用它。但是,通常的用法类似于
char buffer[20];
gets(buffer); /* pray that user enters no more than 19 characters in a line */
您的用法是将gets()
指针传递给指向char的指针。这不是gets()
所期望的,所以你的代码甚至都不会编译。
评论中反映的祷告元素是gets()
如此危险的原因。如果用户输入20个(或更多)字符,gets()
将很乐意在buffer
的末尾写入数据。程序员无法在代码中阻止这种情况(缺少访问硬件来电子输入输入过多数据的用户,这超出了标准C的范围)。
然而,要回答您的问题,唯一的方法是分配一些大小的缓冲区,以某种受控方式读取数据直到达到该大小,如果需要重新分配以获得更大的大小,并继续直到换行(或结束)遇到文件或输入时的其他错误情况。
malloc()
可用于初始分配。 malloc()
或realloc()
可用于重新分配(如果需要)。请记住,当不再需要数据时,必须释放以这种方式分配的缓冲区(使用free()
) - 否则结果是内存泄漏。
答案 2 :(得分:1)
使用getline()函数,这将返回行的长度,以及指向已分配内存区域中行内容的指针。 (确保在完成后将行指针传递给free())
答案 3 :(得分:0)
“使用 fgets 从 c 中的 stdin 读取未知长度的行”
延迟响应 - Windows 方法:
OP 没有指定 Linux 或 Windows,但针对这个问题发布的可行答案似乎都有 getline() 函数,即 POSIX only。 getline()
和 popen()
等函数非常有用且强大,但遗憾的是 Windows 环境中不包含这些函数。
因此,在 Windows 环境中实现这样的任务需要不同的方法。链接 here 描述了一种可以从 stdin
读取输入的方法,并且已经在开发它的系统上进行了高达 1.8 GB 的测试。 (也在链接中进行了描述。)_下面的简单代码片段已使用以下命令行进行测试,以在 stdin
上读取大量数据:
cd c:\dev && dir /s // approximately 1.8Mbyte buffer is returned on my system
简单例子:
#include "cmd_rsp.h"
int main(void)
{
char *buf = {0};
buf = calloc(100, 1);//initialize buffer to some small value
if(!buf)return 0;
cmd_rsp("dir /s", &buf, 100);//recursive directory search on Windows system
printf("%s", buf);
free(buf);
return 0;
}
cmd_rsp()
在上面的链接中有完整的描述,但它本质上是一个 Windows 实现,包括 popen()
和 getline()
之类的功能,打包成这个非常简单的函数。
答案 4 :(得分:-3)
如果您想输入未知长度的字符串或输入,请尝试使用以下代码。
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main()
{
char *m;
clrscr();
printf("please input a string\n");
scanf("%ms",&m);
if (m == NULL)
fprintf(stderr, "That string was too long!\n");
else
{
printf("this is the string %s\n",m);
/* ... any other use of m */
free(m);
}
getch();
return 0;
}
请注意%ms,%和GNU扩展名一样..