fgets 有好的替代品吗?
Is there a good alternative to fgets?
我只是一名年轻的计算机科学专业的学生,目前我对从 stdin 读取字符串的最佳做法是什么有点困惑。我知道有很多方法可以做到这一点,有些方法比其他方法更安全,等等......
我目前需要一个函数来防止缓冲区溢出并将空终止符 (\0) 附加到字符串的末尾。我发现 fgets 对此非常有用,但是......它停止读取 \n 或 EOF!如果我希望用户一次输入多行怎么办?还有其他功能可以帮助我做到这一点吗?
如果这个问题对你们中的某些人来说似乎很愚蠢,我很抱歉,但是请理解我!
任何帮助将不胜感激。
#define INITALLOC 16 /* #chars initally alloced */
#define STEP 8 /* #chars to realloc by */
#define END (-1) /* returned by getline to indicate EOF */
#define ALLOCFAIL 0 /* returned by getline to indicate allocation failure */
int getline(char **dynline)
{
int i, c;
size_t nalloced; /* #chars currently alloced */
if ((*dynline = malloc(INITALLOC)) == NULL)
return ALLOCFAIL;
nalloced = INITALLOC;
for (i = 0; (c = getchar()) != EOF; ++i) {
/* buffer is full, request more memory */
if (i == nalloced)
if ((*dynline = realloc(*dynline, nalloced += STEP)) == NULL)
return ALLOCFAIL;
/* store the newly read character */
(*dynline)[i] = c;
}
/* zero terminate the string */
(*dynline)[i] = '[=10=]';
if (c == EOF)
return END;
return i+1; /* on success, return #chars read successfully
(i is an index, so add 1 to make it a count */
}
此函数动态分配内存,因此调用者需要free
内存。
这段代码并不完美。如果在重新分配时出现故障,NULL
会覆盖之前的 perfectly-good 数据,从而导致内存泄漏和数据丢失。
如果遇到换行符并且 fgets
returns,您可以根据需要多次 运行 以读取任意多行。循环对此很有用。
如果遇到 EOF,则说明您已到达文件 (/stream) 的末尾,运行再次打开它是没有意义的,因为没有什么可读的了。
下面的示例显示了从 stdin 读取整个字符串到 EOF 的逻辑。
有很多方法可以做到这一点,这只是其中一种,但它显示了一般逻辑。
结果缓冲区随着输入的读取而增长,并且没有限制 - 所以如果永远不会达到 EOF,您最终将 运行 内存不足并且程序将退出。一个简单的检查可以避免这种情况,或者根据您的应用程序,您可以在数据传入时对其进行处理,而不需要将其全部存储。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LINE_BUFFER_SIZE 256
// Each time this is exhausted, the buffer will be increased in size by this amount again.
#define INITIAL_BUFFER_SIZE 2048
int main (int argc, char **argv) {
char *result = malloc(INITIAL_BUFFER_SIZE);
if (!result) {
// Out of memory.
return 1;
}
size_t totalBytesRead = 0;
size_t bytesAllocated = INITIAL_BUFFER_SIZE;
char buf[LINE_BUFFER_SIZE];
while (fgets(buf, LINE_BUFFER_SIZE, stdin)) {
size_t bytesRead = strlen(buf);
size_t bytesNeeded = totalBytesRead + bytesRead + 1;
if (bytesAllocated < bytesNeeded) {
char *newPtr = realloc(result, bytesAllocated + INITIAL_BUFFER_SIZE);
if (newPtr) {
result = newPtr;
bytesAllocated += INITIAL_BUFFER_SIZE;
}
else {
// Out of memory.
free(result);
return 1;
}
}
memcpy(result + totalBytesRead, buf, bytesRead);
totalBytesRead += bytesRead;
}
result[totalBytesRead] = '[=10=]';
// result contains the entire contents from stdin until EOF.
printf("%s", result);
free(result);
return 0;
}
在 POSIX 系统上,您有 getline。它能够在堆分配的内存中读取任意宽的行(直到耗尽资源)。
您也可以重复调用 fgetc ...(顺便说一句,您应该 确切地定义 什么是适合您的字符串)
在 Linux 上,您可以从终端读取 可编辑的 行(即 stdin
是 tty) using GNU readline。
要读取 一些 类型的字符串,您可以将 fscanf 与例如%50s
或 %[A-Z]
等...
并且您可以使用 fread
读取数组(字节或其他一些二进制数据)
您可能会从他们那里阅读整行和 parse it later (perhaps using sscanf
). You could read several lines and build some strings in heap memory (e.g. using asprintf or strdup 在具有它的系统上)。
我只是一名年轻的计算机科学专业的学生,目前我对从 stdin 读取字符串的最佳做法是什么有点困惑。我知道有很多方法可以做到这一点,有些方法比其他方法更安全,等等...... 我目前需要一个函数来防止缓冲区溢出并将空终止符 (\0) 附加到字符串的末尾。我发现 fgets 对此非常有用,但是......它停止读取 \n 或 EOF!如果我希望用户一次输入多行怎么办?还有其他功能可以帮助我做到这一点吗? 如果这个问题对你们中的某些人来说似乎很愚蠢,我很抱歉,但是请理解我! 任何帮助将不胜感激。
#define INITALLOC 16 /* #chars initally alloced */
#define STEP 8 /* #chars to realloc by */
#define END (-1) /* returned by getline to indicate EOF */
#define ALLOCFAIL 0 /* returned by getline to indicate allocation failure */
int getline(char **dynline)
{
int i, c;
size_t nalloced; /* #chars currently alloced */
if ((*dynline = malloc(INITALLOC)) == NULL)
return ALLOCFAIL;
nalloced = INITALLOC;
for (i = 0; (c = getchar()) != EOF; ++i) {
/* buffer is full, request more memory */
if (i == nalloced)
if ((*dynline = realloc(*dynline, nalloced += STEP)) == NULL)
return ALLOCFAIL;
/* store the newly read character */
(*dynline)[i] = c;
}
/* zero terminate the string */
(*dynline)[i] = '[=10=]';
if (c == EOF)
return END;
return i+1; /* on success, return #chars read successfully
(i is an index, so add 1 to make it a count */
}
此函数动态分配内存,因此调用者需要free
内存。
这段代码并不完美。如果在重新分配时出现故障,NULL
会覆盖之前的 perfectly-good 数据,从而导致内存泄漏和数据丢失。
如果遇到换行符并且 fgets
returns,您可以根据需要多次 运行 以读取任意多行。循环对此很有用。
如果遇到 EOF,则说明您已到达文件 (/stream) 的末尾,运行再次打开它是没有意义的,因为没有什么可读的了。
下面的示例显示了从 stdin 读取整个字符串到 EOF 的逻辑。
有很多方法可以做到这一点,这只是其中一种,但它显示了一般逻辑。
结果缓冲区随着输入的读取而增长,并且没有限制 - 所以如果永远不会达到 EOF,您最终将 运行 内存不足并且程序将退出。一个简单的检查可以避免这种情况,或者根据您的应用程序,您可以在数据传入时对其进行处理,而不需要将其全部存储。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LINE_BUFFER_SIZE 256
// Each time this is exhausted, the buffer will be increased in size by this amount again.
#define INITIAL_BUFFER_SIZE 2048
int main (int argc, char **argv) {
char *result = malloc(INITIAL_BUFFER_SIZE);
if (!result) {
// Out of memory.
return 1;
}
size_t totalBytesRead = 0;
size_t bytesAllocated = INITIAL_BUFFER_SIZE;
char buf[LINE_BUFFER_SIZE];
while (fgets(buf, LINE_BUFFER_SIZE, stdin)) {
size_t bytesRead = strlen(buf);
size_t bytesNeeded = totalBytesRead + bytesRead + 1;
if (bytesAllocated < bytesNeeded) {
char *newPtr = realloc(result, bytesAllocated + INITIAL_BUFFER_SIZE);
if (newPtr) {
result = newPtr;
bytesAllocated += INITIAL_BUFFER_SIZE;
}
else {
// Out of memory.
free(result);
return 1;
}
}
memcpy(result + totalBytesRead, buf, bytesRead);
totalBytesRead += bytesRead;
}
result[totalBytesRead] = '[=10=]';
// result contains the entire contents from stdin until EOF.
printf("%s", result);
free(result);
return 0;
}
在 POSIX 系统上,您有 getline。它能够在堆分配的内存中读取任意宽的行(直到耗尽资源)。
您也可以重复调用 fgetc ...(顺便说一句,您应该 确切地定义 什么是适合您的字符串)
在 Linux 上,您可以从终端读取 可编辑的 行(即 stdin
是 tty) using GNU readline。
要读取 一些 类型的字符串,您可以将 fscanf 与例如%50s
或 %[A-Z]
等...
并且您可以使用 fread
读取数组(字节或其他一些二进制数据)您可能会从他们那里阅读整行和 parse it later (perhaps using sscanf
). You could read several lines and build some strings in heap memory (e.g. using asprintf or strdup 在具有它的系统上)。