我写这个函数是从文件中读取一行:
const char *readLine(FILE *file) {
if (file == NULL) {
printf("Error: file pointer is null.");
exit(1);
}
int maximumLineLength = 128;
char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);
if (lineBuffer == NULL) {
printf("Error allocating memory for line buffer.");
exit(1);
}
char ch = getc(file);
int count = 0;
while ((ch != '\n') && (ch != EOF)) {
if (count == maximumLineLength) {
maximumLineLength += 128;
lineBuffer = realloc(lineBuffer, maximumLineLength);
if (lineBuffer == NULL) {
printf("Error reallocating space for line buffer.");
exit(1);
}
}
lineBuffer[count] = ch;
count++;
ch = getc(file);
}
lineBuffer[count] = '\0';
char line[count + 1];
strncpy(line, lineBuffer, (count + 1));
free(lineBuffer);
const char *constLine = line;
return constLine;
}
该函数正确地读取文件,使用printf我看到constLine字符串也被正确读取。
然而,如果我像这样使用函数:
while (!feof(myFile)) {
const char *line = readLine(myFile);
printf("%s\n", line);
}
Printf输出胡言乱语。为什么?
在readLine函数中,返回一个指向行数组的指针(严格地说,是指向该行数组第一个字符的指针,但这里的区别无关紧要)。由于它是一个自动变量(即,它“在堆栈上”),当函数返回时,内存将被回收。你看到的是乱七八糟的东西,因为printf把它自己的东西放到了堆栈上。
您需要从函数返回一个动态分配的缓冲区。你已经有一个了,它是lineBuffer;你所要做的就是把它截断成所需的长度。
lineBuffer[count] = '\0';
realloc(lineBuffer, count + 1);
return lineBuffer;
}
ADDED(对评论中后续问题的回应):readLine返回一个指向组成该行的字符的指针。这个指针是处理该行内容所需要的指针。当你用完这些字符占用的内存时,你也必须通过它来释放内存。下面是如何使用readLine函数:
char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
You can't use the value of `line` again (though you can assign a new value
to the `line` variable if you want). */
如果你的任务不是发明逐行读取函数,而只是逐行读取文件,你可以使用一个典型的代码片段,包括getline()函数(参见手册页):
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/etc/motd", "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu:\n", read);
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
提供一个可移植的通用getdelim函数,通过msvc, clang, gcc测试。
/*
* An implementation conform IEEE Std 1003.1-2017:
* https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
*
* <nio.h>:
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nio.h
* <nio.c>:
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nio.c
*
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
/*
* LINE_MAX dependents on OS' implementations so check it first.
* https://github.com/junjiemars/c/blob/c425bd0e49df35a2649327664d3f6cd610791996/src/posix/nlim_auto_check
*/
#define NM_LINE_MAX 4096 /* Linux */
#if (MSVC)
typedef SSIZE_T ssize_t;
# if !defined(SSIZE_MAX)
# define SSIZE_MAX ((ssize_t)((size_t)((ssize_t)-1) >> 1))
# endif
#endif
ssize_t getdelim(char **restrict lineptr, size_t *restrict n, int delimiter,
FILE *restrict stream);
#if defined(getline)
# undef getline
#endif
#define getline(lp, n, f) getdelim((lp), (n), 0x0a, (f))
ssize_t
getdelim(char **restrict lineptr, size_t *restrict n, int delimiter,
FILE *restrict stream)
{
int c;
char *p, *p1;
ssize_t len;
if (NULL == lineptr || NULL == n || NULL == stream
|| (UCHAR_MAX < delimiter || delimiter < 0))
{
errno = EINVAL;
return EOF;
}
if (feof(stream) || ferror(stream))
{
return EOF;
}
if (0 == *lineptr)
{
if (0 == *n)
{
*n = NM_LINE_MAX;
}
*lineptr = malloc(*n);
if (0 == *lineptr)
{
return EOF;
}
}
p = *lineptr;
len = 0;
while (EOF != (c = fgetc(stream)))
{
if (SSIZE_MAX == (ssize_t) len)
{
errno = EOVERFLOW;
return EOF;
}
if ((size_t) len == (*n - 1))
{
*n <<= 1;
p1 = realloc(*lineptr, *n);
if (0 == p1)
{
return EOF;
}
*lineptr = p1;
p = p1 + len;
}
*p++ = (char) c;
len++;
if (c == delimiter)
{
break;
}
}
if (ferror(stream))
{
return EOF;
}
*p = 0;
return len;
}
int
main(void)
{
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/some-file", "r");
if (fp == NULL)
exit(1);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu :\n", read);
printf("%s", line);
}
if (ferror(fp)) {
/* handle error */
}
free(line);
fclose(fp);
return 0;
}
实现从文件中读取和获取内容的方法(input1.txt)
#include <stdio.h>
#include <stdlib.h>
void testGetFile() {
// open file
FILE *fp = fopen("input1.txt", "r");
size_t len = 255;
// need malloc memory for line, if not, segmentation fault error will occurred.
char *line = malloc(sizeof(char) * len);
// check if file exist (and you can open it) or not
if (fp == NULL) {
printf("can open file input1.txt!");
return;
}
while(fgets(line, len, fp) != NULL) {
printf("%s\n", line);
}
free(line);
}
希望这对你有所帮助。编码快乐!