C语言中的文件IO问题

huangapple go评论65阅读模式
英文:

Issue with File IO in C

问题

我正在尝试每次用户输入1时都读取一个文件,但我遇到了意外的行为。

这是我的代码。

#include <stdio.h>
#include <string.h>

char* read_file(char* file_name){

	FILE *fp = fopen(file_name, "r");

    if (fp == NULL)
    {
        printf("Error: could not open file %s", file_name);
        return "";
    }

    // reading line by line, max 256 bytes
    const unsigned MAX_LENGTH = 30000;
    char buffer[30000];
	char data[MAX_LENGTH];
    memset(buffer, '
#include <stdio.h>
#include <string.h>

char* read_file(char* file_name){

	FILE *fp = fopen(file_name, "r");

    if (fp == NULL)
    {
        printf("Error: could not open file %s", file_name);
        return "";
    }

    // reading line by line, max 256 bytes
    const unsigned MAX_LENGTH = 30000;
    char buffer[30000];
	char data[MAX_LENGTH];
    memset(buffer, '\0', MAX_LENGTH);
    while (fgets(buffer, MAX_LENGTH, fp)){
        strcat(data, buffer);
		// strcat(data, "\n");
	}
    // close the file
    fclose(fp);
	char* return_data = &data[0];
	return return_data;

}

void send_data(char* file_name){
	printf("\n\n %s\n", read_file(file_name));
}

int main()
{
    int cont = 1;
    while(cont){
        send_data("try/try.txt");
        scanf("%d", &cont);
    }
}
'
, MAX_LENGTH);
while (fgets(buffer, MAX_LENGTH, fp)){ strcat(data, buffer); // strcat(data, "\n"); } // close the file fclose(fp); char* return_data = &data[0]; return return_data; } void send_data(char* file_name){ printf("\n\n %s\n", read_file(file_name)); } int main() { int cont = 1; while(cont){ send_data("try/try.txt"); scanf("%d", &cont); } }

发生的情况是,第一次输出时,它会给出正确的结果,但第二次会将先前的结果和新的结果添加在一起并打印出来。有没有办法可以纠正它。

这是输出日志。

tusharsing@techie-Latitude-3520:~/Desktop/Project/project/temp$ ./filetry 


 HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>

1


 HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>

^C

请注意,这段代码中存在一个问题,即 data 数组在每次函数调用之间没有被重置,因此会导致结果叠加。要解决这个问题,您可以在 send_data 函数内部的循环之前将 data 数组清空,如下所示:

void send_data(char* file_name){
    char data[MAX_LENGTH];
    memset(data, '
void send_data(char* file_name){
    char data[MAX_LENGTH];
    memset(data, '\0', MAX_LENGTH);
    printf("\n\n %s\n", read_file(file_name));
}
'
, MAX_LENGTH);
printf("\n\n %s\n", read_file(file_name)); }

这样,每次调用 send_data 函数时都会创建一个新的 data 数组,以防止结果叠加。

英文:

I am trying to read a file every time the user inputs 1 but i am facing an unexpected behaviour,

This is my code.

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

char* read_file(char* file_name){

	FILE *fp = fopen(file_name, &quot;r&quot;);

    if (fp == NULL)
    {
        printf(&quot;Error: could not open file %s&quot;, file_name);
        return &quot;&quot;;
    }

    // reading line by line, max 256 bytes
    const unsigned MAX_LENGTH = 30000;
    char buffer[30000];
	char data[MAX_LENGTH];
    memset(buffer, &#39;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
char* read_file(char* file_name){
FILE *fp = fopen(file_name, &quot;r&quot;);
if (fp == NULL)
{
printf(&quot;Error: could not open file %s&quot;, file_name);
return &quot;&quot;;
}
// reading line by line, max 256 bytes
const unsigned MAX_LENGTH = 30000;
char buffer[30000];
char data[MAX_LENGTH];
memset(buffer, &#39;\0&#39;, MAX_LENGTH);
while (fgets(buffer, MAX_LENGTH, fp)){
strcat(data, buffer);
// strcat(data, &quot;\n&quot;);
}
// close the file
fclose(fp);
char* return_data = &amp;data[0];
return return_data;
}
void send_data(char* file_name){
printf(&quot;\n\n %s\n&quot;, read_file(file_name));
}
int main()
{
int cont = 1;
while(cont){
send_data(&quot;try/try.txt&quot;);
scanf(&quot;%d&quot;, &amp;cont);
}
}
&#39;, MAX_LENGTH); while (fgets(buffer, MAX_LENGTH, fp)){ strcat(data, buffer); // strcat(data, &quot;\n&quot;); } // close the file fclose(fp); char* return_data = &amp;data[0]; return return_data; } void send_data(char* file_name){ printf(&quot;\n\n %s\n&quot;, read_file(file_name)); } int main() { int cont = 1; while(cont){ send_data(&quot;try/try.txt&quot;); scanf(&quot;%d&quot;, &amp;cont); } }

What is happening is when it is giving the output the first time it gives the correct result but on the second time it adds the prev result and new result and prints it.
Is there any way i can correct it.

Here is the output log

tusharsing@techie-Latitude-3520:~/Desktop/Project/project/temp$ ./filetry 


 HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Page Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h1&gt;My First Heading&lt;/h1&gt;
&lt;p&gt;My first paragraph.&lt;/p&gt;

&lt;/body&gt;
&lt;/html&gt;

1


 HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Page Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h1&gt;My First Heading&lt;/h1&gt;
&lt;p&gt;My first paragraph.&lt;/p&gt;

&lt;/body&gt;
&lt;/html&gt;
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Page Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h1&gt;My First Heading&lt;/h1&gt;
&lt;p&gt;My first paragraph.&lt;/p&gt;

&lt;/body&gt;
&lt;/html&gt;

^C

答案1

得分: 3

函数调用

```c
strcat(data, buffer);

要求data指向一个以null结尾的字符串。然而,在循环的第一次迭代中,这未必成立,因为您没有确保data包含一个null结尾字符。

如果您将以下行更改为

memset(buffer, '
memset(buffer, '\0', MAX_LENGTH);
'
, MAX_LENGTH);

然后您正在确保第一个字符是null字符(这将使字符串的长度为零)。

然而,为了将字符串的第一个字符设置为null字符,仅需编写以下内容即可:

data[0] = '
data[0] = '\0';
'
;

没有必要将整个字符串设置为零。

另一个问题是以下行

return return_data;

没有意义,因为return_data的值为&data[0],而data是一个局部数组。这意味着返回值是悬空指针。它指向一个一旦函数返回就不再存在的对象。因此,这样的指针是无用的。

如果解引用悬空指针恰好有效,那只是意味着您幸运地发现了已过期对象的内存位置尚未被覆写。您不能依赖这种行为。有关为什么会发生这种情况以及您不能依赖它的更多信息,请参见此答案另一个问题。

如果您想要在函数返回时仍然可以访问的数组,那么要么

  1. 调用者将不得不为数组分配内存并将指向该数组的指针传递给被调用的函数,或者
  2. 被调用的函数将不得不使用动态内存分配(例如malloc)。

<details>
<summary>英文:</summary>

The function call

strcat(data, buffer);


requires that `data` points to a null-terminated string. However, this is not necessarily the case in the first iteration of the loop, because you are not ensuring that `data` constains a null terminating character.

If you change the line

memset(buffer, '\0', MAX_LENGTH);


to

memset(data, '\0', MAX_LENGTH);


then you are ensuring that the first character is a null character (which makes the length of the string zero).

However, in order to set the first character of the string to a null character, it would be sufficient to write:

data[0] = '\0';


There is no need to set the entire string to zero.

Another issue is that the line

return return_data;


does not make sense, because `return_data` has the value `&amp;data[0]`, and `data` is a local array. This means that the return value is a [dangling pointer](https://en.wikipedia.org/wiki/Dangling_pointer). It points to an object that no longer exists as soon as the function returns. Therefore, such a pointer is useless.

If dereferencing the dangling pointer happens to work, then that just means that you are lucky that the memory location of the expired object has not yet been overwritten. You cannot rely on this behavior. See [this answer](https://stackoverflow.com/a/6445794/12149471) to another question for more information on why this happens and why you cannot rely on it.

If you want an array that is still accessible when the function returns, then either

1. the caller will have to allocate the memory for the array and pass a pointer to that array to the called function, or
2. the called function will have to use dynamic memory allocation (e.g. `malloc`)

</details>



huangapple
  • 本文由 发表于 2023年6月6日 05:35:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76410146.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定