[英]Going through a text file line by line in C
I have been working on a small exercise for my CIS class and am very confused by the methods C uses to read from a file. 我一直在为CIS班级做一个小练习,对C用来从文件中读取的方法感到非常困惑。 All that I really need to do is read through a file line by line and use the information gathered from each line to do a few manipulations.
我真正需要做的就是逐行读取文件,并使用从每一行收集的信息进行一些操作。 I tried using the getline method and others with no luck.
我尝试使用getline方法和其他没有运气的方法。 My code is currently as follows:
我的代码当前如下:
int main(char *argc, char* argv[]){
const char *filename = argv[0];
FILE *file = fopen(filename, "r");
char *line = NULL;
while(!feof(file)){
sscanf(line, filename, "%s");
printf("%s\n", line);
}
return 1;
}
Right now I am getting a seg fault with the sscanf method and I am not sure why. 现在我用sscanf方法遇到段错误,我不确定为什么。 I am a total C noob and just wondering if there was some big picture thing that I was missing.
我是一个C菜鸟,只是想知道我是否缺少一些大图景。 Thanks
谢谢
So many problems in so few lines. 这么少的行就有这么多问题。 I probably forget some:
我可能会忘记一些:
So 所以
#include <stdio.h>
int main(int argc, char* argv[])
{
char const* const fileName = argv[1]; /* should check that argc > 1 */
FILE* file = fopen(fileName, "r"); /* should check the result */
char line[256];
while (fgets(line, sizeof(line), file)) {
/* note that fgets don't strip the terminating \n, checking its
presence would allow to handle lines longer that sizeof(line) */
printf("%s", line);
}
/* may check feof here to make a difference between eof and io failure -- network
timeout for instance */
fclose(file);
return 0;
}
To read a line from a file, you should use the fgets
function: It reads a string from the specified file up to either a newline character or EOF
. 要从文件中读取一行,应使用
fgets
函数:它从指定文件中读取一个字符串,直到一个换行符或EOF
为止。
The use of sscanf
in your code would not work at all, as you use filename
as your format string for reading from line
into a constant string literal %s
. 在代码中完全不能使用
sscanf
,因为您使用filename
作为格式字符串,以便从line
读取到常量字符串常量%s
。
The reason for SEGV is that you write into the non-allocated memory pointed to by line
. 使用SEGV的原因是您写入了
line
指向的未分配内存。
Say you're dealing with some other delimiter, such as a \\t
tab, instead of a \\n
newline. 假设您要处理其他分隔符,例如
\\t
选项卡,而不是\\n
换行符。
A more general approach to delimiters is the use of getc()
, which grabs one character at a time. 一种更通用的定界符方法是使用
getc()
,它一次捕获一个字符。
Note that getc()
returns an int
, so that we can test for equality with EOF
. 请注意,
getc()
返回一个int
,以便我们可以使用EOF
测试是否相等。
Secondly, we define an array line[BUFFER_MAX_LENGTH]
of type char
, in order to store up to BUFFER_MAX_LENGTH-1
characters on the stack (we have to save that last character for a \\0
terminator character). 其次,我们定义一个数组类型为
char
的数组line[BUFFER_MAX_LENGTH]
,以便在堆栈上最多存储BUFFER_MAX_LENGTH-1
字符(我们必须将最后一个字符保存为\\0
终止符)。
Use of an array avoids the need to use malloc
and free
to create a character pointer of the right length on the heap. 使用数组避免了使用
malloc
和free
在堆上创建正确长度的字符指针的需要。
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
/* get a character from the file pointer */
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
fprintf(stdout, "%s\n", line);
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
fprintf(stdout, "%s\n", line);
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
If you must use a char *
, then you can still use this code, but you strdup()
the line[]
array, once it is filled up with a line's worth of input. 如果必须使用
char *
,那么仍然可以使用此代码,但是一旦它充满了行的输入值,便可以strdup()
line[]
数组。 You must free
this duplicated string once you're done with it, or you'll get a memory leak: 完成后,必须
free
此重复的字符串,否则会发生内存泄漏:
#define BUFFER_MAX_LENGTH 1024
int main(int argc, char* argv[])
{
FILE *file = NULL;
char line[BUFFER_MAX_LENGTH];
int tempChar;
unsigned int tempCharIdx = 0U;
char *dynamicLine = NULL;
if (argc == 2)
file = fopen(argv[1], "r");
else {
fprintf(stderr, "error: wrong number of arguments\n"
"usage: %s textfile\n", argv[0]);
return EXIT_FAILURE;
}
if (!file) {
fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
return EXIT_FAILURE;
}
while(tempChar = fgetc(file))
{
/* avoid buffer overflow error */
if (tempCharIdx == BUFFER_MAX_LENGTH) {
fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
return EXIT_FAILURE;
}
/* test character value */
if (tempChar == EOF) {
line[tempCharIdx] = '\0';
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
break;
}
else if (tempChar == '\n') {
line[tempCharIdx] = '\0';
tempCharIdx = 0U;
dynamicLine = strdup(line);
fprintf(stdout, "%s\n", dynamicLine);
free(dynamicLine);
dynamicLine = NULL;
continue;
}
else
line[tempCharIdx++] = (char)tempChar;
}
return EXIT_SUCCESS;
}
In addition to the other answers, on a recent C library (Posix 2008 compliant), you could use getline . 除了其他答案,在最新的C库(符合Posix 2008的情况)上,您可以使用getline 。 See this answer (to a related question).
请参阅此答案 (针对相关问题)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.