使用 fgets() 和 strtok() 读取带有逗号分隔符的文件

发布于 2024-10-06 08:05:20 字数 1031 浏览 2 评论 0原文

我有一个文本文件,其中包含三个以逗号分隔的字段。 我的文本文件内容示例:12345,真正的编程新手,BS ME 要将文件加载到程序中,我使用了下面的代码......我的问题是,有时代码可以工作,有时则不能(没有错误消息出现,程序只是自行关闭并且不继续)。我还观察到文本文件是空白的(没有写入任何内容)它会自动关闭并且不会继续。我们将非常感谢您的帮助。谢谢!

int read(){
     FILE *stream = NULL;
     int ctr;
     char linebuffer[45];
     char delims[]=", ";
     char *number[3];
     char *token = NULL;
     stream = fopen("student.txt", "rt");
     if (stream == NULL) stream = fopen("student.txt", "wt");
     else {
          printf("\nReading the student list directory. Wait a moment please...");
          while(!feof(stream)){            
                ctr=0;
                fgets(linebuffer, 46, stream);
                token = strtok(linebuffer, delims);
                while(token != NULL){
                  number[ctr] = linebuffer;
                  token = strtok(NULL, delims); 
                  ctr++;
                }
          recordCtr++;                      
          }                     
     recordCtr--;
     }
     fclose(stream);
}    

I have a text file with three fields separated by comma.
Example of the content of my text file: 12345, true programming newbie, BS ME
To load the file into the program, i used the below code.... my problem is that sometimes the code works and sometimes it doesn't (no error message appears the program just closes itself and doesn't continue). i also observed the text file is blank (nothing is written) it automatically closes itself and doesn't continue. Your help would be highly appreciated. Thanks!

int read(){
     FILE *stream = NULL;
     int ctr;
     char linebuffer[45];
     char delims[]=", ";
     char *number[3];
     char *token = NULL;
     stream = fopen("student.txt", "rt");
     if (stream == NULL) stream = fopen("student.txt", "wt");
     else {
          printf("\nReading the student list directory. Wait a moment please...");
          while(!feof(stream)){            
                ctr=0;
                fgets(linebuffer, 46, stream);
                token = strtok(linebuffer, delims);
                while(token != NULL){
                  number[ctr] = linebuffer;
                  token = strtok(NULL, delims); 
                  ctr++;
                }
          recordCtr++;                      
          }                     
     recordCtr--;
     }
     fclose(stream);
}    

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

咽泪装欢 2024-10-13 08:05:20

一旦找到令牌,您就永远不会复制它。您无法复制linebuffer,因为加载下一行时,其中的数据将被覆盖。

此行:

number[ctr] = linebuffer;

应引用 token 来保存最近找到的令牌,但事实并非如此。它可能应该是这样的:1

strcpy(number[ctr], token);

但是你必须更改声明以确保有空间:

char number[3][32];

显然,这会带来缓冲区溢出风险,如果有一个很长的令牌,则不会合身。如何最好地处理这个问题留作练习。 :)

1 为什么临时向量用于存储两个数字和一个字符串(名称)时被称为“数字”,这超出了我的理解。

You never copy the token once you've found it. You can't copy linebuffer, as the data in there will be overwritten as the next line is loaded.

This line:

number[ctr] = linebuffer;

should reference token to save the most recently found token, but it doesn't. It should probably read something like1:

strcpy(number[ctr], token);

but then you'd have to change the declaration to make sure there's space:

char number[3][32];

Obviously, this introduces a buffer overrun risk, if there's a very long token it won't fit. How to best handle that is left as an exercise. :)

1 Why the temporary vector is called "number" when it is used to store two numbers and one string (the name) is beyond me.

原野 2024-10-13 08:05:20

您的 fgets() 调用需要指定 45 作为大小,否则当 fgets 写入 NULL 终止符时您会溢出缓冲区。这会将“delims”字符串设置为空字符串。

此外,即使函数声明声明它返回 int,您也不会返回任何值。

我不知道你的“struct Student”的定义是什么,但是在使用strcpy()时你可能会溢出缓冲区。您还可以减少“recordCtr”。为什么?如果无法打开文件进行写入,为什么还要打开文件进行写入?为什么?如果也失败,则对 NULL 指针调用 fclose。我怀疑这有多大帮助。

我刚刚注意到你没有初始化“number”。如果第一行没有得到三个数字,则可以从未初始化的指针中获取 strcpy()。它可能有一个 NULL 值,因此程序会出现段错误。

另外,您还有一个大小为 3 的数组,但如果您读取的行包含超过 3 个逗号分隔的字段,则会导致数组溢出。

可能还有许多其他错误。

许多程序员只是懒得去做所有好的编码实践,比如检查返回值、初始化变量等等。他们通常会得到这样的代码。如果你想成为一名真正优秀的程序员,请尝试并养成做所有这些事情的习惯,或者至少始终考虑是否需要这样做。

这段代码中有很多潜在的错误。如果一行长度超过 45 个字符会发生什么?你不删除换行符。您不会将字符串转换为数字(尽管 number[1] 似乎是字符串数据,所以为什么将其存储在名为“numbers”的数组中?)或检查 fgets 是否实际返回了任何数据或检查您有多少条数据得到。

Your fgets() call needs to specify 45 as the size or you oveflow the buffer when fgets writes the NULL terminator. That will set the "delims" string to be an empty string.

Also you are not returning any value even though the function declaration states it returns an int.

I don't know what the definition of your "struct student" is, but you may be overflowing buffers when using strcpy(). Also you decrement "recordCtr". Why? Why do you open the file for writing if you can't open it for writing? Why? If that fails too, you call fclose on a NULL pointer. I doubt that helps much.

I just noticed that you do not initialise "number". If you don't get three numbers on the first line, you then strcpy() from an uninitialised pointer. It probably has a NULL value so the program will segfault.

Also you have an array of size 3, but if the line you read has more than 3 comma separated fields you will overflow the array.

There are probably many other errors as well.

A lot of programmers just can't be bothered to do all the good coding practices like checking return values, initialising variables, and so on. They often end up with code like this. If you want to be a really good programmer, try and get in the habit of doing all these things, or at least always thinking about whether you need to or not.

There are so many potential bugs in this code. What happens if a line is more than 45 characters long? You don't strip newlines. You don't convert the strings to numbers (although number[1] appears to be a string data so why store it in an array called "numbers"?) or check that fgets actually returned any data or check how many pieces of data you get.

有深☉意 2024-10-13 08:05:20

让买家小心。

strtok 可能需要担心一些边缘情况。

“一、二、三” 将产生 3 个代币。

“一、三” 将产生 2 个代币。

Let the buyer beware.

strtok may have some edge cases to worry about.

"one,two,three" will yield 3 tokens.

"one,,three" will yield 2 tokens.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文