是否有一个很好的替代fgets?

我只是一名年轻的计算机科学专业的学生,​​目前我对从stdin读取字符串的最佳做法感到困惑。 我知道有很多方法可以做到这一点,有些方法比其他方法更安全,等等……我目前需要一个防止缓冲区溢出的函数,并在末尾添加一个空终止符(\ 0)的字符串。 我发现fgets对此非常有用,但是…它会停止用\ n或EOF读取! 如果我希望用户一次输入多行,该怎么办? 还有其他function可以帮助我做到这一点吗? 对不起,如果这个问题对你们中的某些人来说似乎很愚蠢,那么请理解我! 任何帮助,将不胜感激。

 #define INITALLOC 16 /* #chars initally alloced */ #define STEP 8 /* #chars to realloc by */ int getline(char **dynline) { int i, c; size_t nalloced; /* #chars currently alloced */ if ((*dynline = malloc(INITALLOC)) == NULL) return 0; nalloced = INITALLOC; for (i = 0; (c = getchar()) != EOF; ++i) { /* buffer is full, request more mem */ if (i == nalloced) if ((*dynline = realloc(*dynline, nalloced += STEP)) == NULL) return 0; /* store the newly read character */ (*dynline)[i] = c; } /* zero terminate the string */ (*dynline)[i] = '\0'; if (c == EOF) return 0; /* return 0 on EOF */ return 1; } 

此函数动态分配内存,因此调用者需要free内存。 getline在EOF或失败时返回0,在成功时返回1。

如果遇到换行符并且fgets返回,则可以根据需要多次再次运行它,以便根据需要读取多行。 循环对此很有用。

如果遇到EOF,你已到达文件的末尾(/ stream)并且没有必要再次运行它,因为没有什么可以读取的。

下面是一个示例,显示从stdin读取整个字符串到EOF的逻辑。

有很多方法可以做到这一点,这只是一个,但它显示了一般逻辑。

结果缓冲区随着输入的读取而增长,并且没有界限 – 所以如果永远不会达到EOF,最终会耗尽内存并且程序将退出。 一个简单的检查可以避免这种情况,或者根据您的应用程序,您可以处理数据,而不需要存储数据。

 #include  #include  #include  #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] = '\0'; // result contains the entire contents from stdin until EOF. printf("%s", result); free(result); return 0; } 

在POSIX系统上,你有getline 。 它能够在堆分配的内存中读取任意宽的行(直到耗尽资源)。

你也可以反复调用fgetc …(顺便说一句,你应该为你准确定义什么是字符串)

在Linux上,您可以使用GNU readline从终端读取可编辑的行(即,当它是tty时的stdin )。

要读取某种字符串,可以使用fscanf ,例如%50s%[AZ]等…

您可以使用fread读取数组(字节或其他二进制数据)

您可能会读取整行并稍后解析它(可能使用sscanf )。 您可以读取多行并在堆内存中构建一些字符串(例如,在具有它的系统上使用asprintf或strdup )。