调用函数并将另一个结构作为参数传递后,结构的元素将失去其值
An element of a struct loses its value after a function is called passing another struct as argument
我有一个问题想不通。我有以下文件:file_reader.c, file_reader.h, file_writer.c, file_writer.h, test_file_reader.c
我正在使用 'struct' 读写文件。为了更好地理解我写了下面的代码 test_file_reader.c
:
#include <stdio.h>
#include "file_reader.h"
#include "file_writer.h"
int main ()
{
char *file_path = "/home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml";
struct FileReader *fr = malloc(sizeof(struct FileReader));
file_reader_new (file_path, fr);
show_file_reader_values(fr);
struct FileWriter *fw = malloc(sizeof(struct FileWriter));
fw->file_path = "/tmp/text1.txt";
fw->content = "aaa";
write (fw);
show_file_reader_values(fr);
return 0;
}
void show_file_reader_values(const struct FileReader *fr)
{
printf("==========FILE READER==========\n");
printf("file path: %s\n", fr->file_path);
printf("----------file content---------\n");
printf("content:\n%s\n", fr->content);
printf("----------file content---------\n");
printf("n lines: %d\n", fr->n_lines);
printf("n characters: %d\n", fr->n_characters);
printf("==========FILE READER==========\n\n");
}
函数'file_reader_new'读取文件,然后将内容、文件路径、行数和字符数签名到'struct' 'FileReader'.
当我第一次调用函数'show_file_reader_values'时,内容没有问题,但是当我调用函数'write'然后再次调用函数'show_file_reader_values'时,内容不一样了。问题是文件 'file_writer.c' 及其结构的函数 'write' 与文件 'file_reader' 及其结构没有任何关系。那么,使用另一个结构的函数如何更改另一个文件的另一个结构的值?
输出:
[freitas@localhost test]$ ./test_file_reader
==========FILE READER==========
file path: /home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml
----------file content---------
content:
<cleaner> <id>k3b</id> <label>k3b</label> <description>Disc writing software</description> <option> <id>log</id> <label>Log</label> <description>Delete the log file which contains information about the last writing session(s).</description> <command>delete</command> <search>glob</search> <path>~/.kde/share/apps/k3b/*.log</path> </option> <option> <id>log2</id> <label>Log</label> <description>Delete the log file which contains information about the last writing session(s).</description> <command>delete</command> <search>glob</search> <path>~/.kde/share/apps/k3b/*.log</path> </option> </cleaner>
----------file content---------
n lines: 1
n characters: 621
==========FILE READER==========
==========FILE READER==========
file path: /home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml
----------file content---------
content:
<cleaner> <id>k��U�N
----------file content---------
n lines: 1
n characters: 621
==========FILE READER==========
你看到了吗?在第一次通话中,我得到了完整的输出:
<cleaner> <id>k3b</id> <label>k3b</label> <description>Disc wri...
但在第二次通话中我接到了:
<cleaner> <id>k��U�N
file_reader.c
#include <stdio.h>
#include <stdlib.h>
#include "file_reader.h"
int file_reader_new(const char *file_path, struct FileReader *fr)
{
char *content; // holds the file content.
int counter; // holds the file number of lines.
size_t i; // indexing into content.
size_t buffer_size; // size of the content.
char *temp; // for realloc().
char c; // for reading from the input.
FILE *input; // our input stream.
if ((input = fopen(file_path, "r")) == NULL) {
fprintf(stderr, "Error opening input file %s\n", file_path);
exit(EXIT_FAILURE);
}
/* Initial allocation of content */
counter = 0;
i = 0;
buffer_size = BUFSIZ;
if ((content = malloc(buffer_size)) == NULL) {
fprintf(stderr, "Error allocating memory (before reading file).\n");
fclose(input);
}
while ((c = fgetc(input)) != EOF) {
/* Enlarge content if necessary. */
if (i == buffer_size) {
buffer_size += BUFSIZ;
if ((temp = realloc(content, buffer_size)) == NULL) {
fprintf(stderr, "Ran out of core while reading file.\n");
fclose(input);
free(content);
exit(EXIT_FAILURE);
}
content = temp;
}
/* Add input char to the content. */
content[i++] = c;
/* If the character is a break of line
* then the counter will be incremented.
*/
if (c == '\n')
counter++;
}
/* Test if loop terminated from error. */
if (ferror(input)) {
fprintf(stderr, "There was a file input error.\n");
free(content);
fclose(input);
exit(EXIT_FAILURE);
}
/* Make the content a bona-fide string. */
if (i == buffer_size) {
buffer_size += 1;
if ((temp = realloc(content, buffer_size)) == NULL) {
fprintf(stderr, "Ran out of core (and only needed one more byte too ;_;).\n");
fclose(input);
free(content);
exit(EXIT_FAILURE);
}
content = temp;
}
content[i] = '[=14=]';
/* Assigns the variables to the corresponding
* element of the struct.
*/
fr->file_path = file_path;
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content);
fclose(input);
return 0;
}
file_reader.h
#ifndef FILE_READER_H_
#define FILE_READER_H_
typedef struct FileReader
{
char *content; // holds the file content.
char *file_path; // holds the file path.
int *n_lines; // holds the number of lines.
int *n_characters; // holds the number of characters.
} FileReader;
// file_reader_new - reads the file
int file_reader_new(const char *file_path, struct FileReader *fr);
#endif
file_writer.c
#include <stdio.h>
#include "file_writer.h"
void write (struct FileWriter *fw)
{
FILE *f = fopen(fw->file_path, "w");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "%s", fw->content);
fclose(f);
}
file_writer.h
#ifndef FILE_WRITER_H_
#define FILE_WRITER_H_
typedef struct FileWriter
{
char *file_path;
char *content;
int *error;
} FileWriter;
#endif
你能帮帮我吗?谢谢!
struct FileReader *fr = malloc(sizeof(struct FileReader));
没有必要这样做。你只需要这个:
struct FileReader fr;
这里也一样:
struct FileWriter fw;
然后只需将这些变量的地址传递给必要的函数即可。
请注意,这不是作为答案提供给您的,只是作为注释来稍微清理您的代码以删除对堆的无关调用。碰巧真正的问题存在于其他地方,而您在这里看到的是 undefined behavior
的辉煌。
我不确定您是如何逐个字符或逐块读取文件的,但是无论如何,
因为你更新了content
缓冲区中的读取数据,并将content
缓冲区中的地址存储在file_reader_new()
中到变量fr->content
中并立即释放内存将结束失去你阅读的数据。并导致称为 悬挂指针
的情况
悬挂指针
(一个指针变量,指向释放的内存)
这就是为什么总是建议在释放后将指针变量设置为NULL
。在某些情况下,取消引用悬空指针将导致 Segmentation fault
或 undefined behavior
。
此外,由于 struct
的所有成员变量都是指针,因此最好将它们初始化为 NULL
。
您可以使用 calloc
来初始化 struct
中的所有变量,而不是 malloc
来将所有成员初始化为 NULL
,如果您要使用动态分配。这也适用于 string
。
这是我看到的一个问题:
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content); /* <-- Danger */
您在 file_reader_new
函数中执行此操作。然后调用 show_file_reader_values
并在该函数中访问 content
:
printf("content:\n%s\n", fr->content);
由于您对内容调用了 free()
,该指针不再指向有效内存,因此发生了未定义的行为。
解决方法是在fr
上为内容分配space并将content
的字符复制到这个space,或者干脆不调用free
在 content
.
所以要么这样做:
fr->content = malloc(i + 1);
strcpy(fr->content, content);
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content);
或者这个:
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* No call to free(content) done */
我有一个问题想不通。我有以下文件:file_reader.c, file_reader.h, file_writer.c, file_writer.h, test_file_reader.c
我正在使用 'struct' 读写文件。为了更好地理解我写了下面的代码 test_file_reader.c
:
#include <stdio.h>
#include "file_reader.h"
#include "file_writer.h"
int main ()
{
char *file_path = "/home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml";
struct FileReader *fr = malloc(sizeof(struct FileReader));
file_reader_new (file_path, fr);
show_file_reader_values(fr);
struct FileWriter *fw = malloc(sizeof(struct FileWriter));
fw->file_path = "/tmp/text1.txt";
fw->content = "aaa";
write (fw);
show_file_reader_values(fr);
return 0;
}
void show_file_reader_values(const struct FileReader *fr)
{
printf("==========FILE READER==========\n");
printf("file path: %s\n", fr->file_path);
printf("----------file content---------\n");
printf("content:\n%s\n", fr->content);
printf("----------file content---------\n");
printf("n lines: %d\n", fr->n_lines);
printf("n characters: %d\n", fr->n_characters);
printf("==========FILE READER==========\n\n");
}
函数'file_reader_new'读取文件,然后将内容、文件路径、行数和字符数签名到'struct' 'FileReader'.
当我第一次调用函数'show_file_reader_values'时,内容没有问题,但是当我调用函数'write'然后再次调用函数'show_file_reader_values'时,内容不一样了。问题是文件 'file_writer.c' 及其结构的函数 'write' 与文件 'file_reader' 及其结构没有任何关系。那么,使用另一个结构的函数如何更改另一个文件的另一个结构的值?
输出:
[freitas@localhost test]$ ./test_file_reader
==========FILE READER==========
file path: /home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml
----------file content---------
content:
<cleaner> <id>k3b</id> <label>k3b</label> <description>Disc writing software</description> <option> <id>log</id> <label>Log</label> <description>Delete the log file which contains information about the last writing session(s).</description> <command>delete</command> <search>glob</search> <path>~/.kde/share/apps/k3b/*.log</path> </option> <option> <id>log2</id> <label>Log</label> <description>Delete the log file which contains information about the last writing session(s).</description> <command>delete</command> <search>glob</search> <path>~/.kde/share/apps/k3b/*.log</path> </option> </cleaner>
----------file content---------
n lines: 1
n characters: 621
==========FILE READER==========
==========FILE READER==========
file path: /home/freitas/Dropbox/projects/gcleaner/cleaners/custom.xml
----------file content---------
content:
<cleaner> <id>k��U�N
----------file content---------
n lines: 1
n characters: 621
==========FILE READER==========
你看到了吗?在第一次通话中,我得到了完整的输出:
<cleaner> <id>k3b</id> <label>k3b</label> <description>Disc wri...
但在第二次通话中我接到了:
<cleaner> <id>k��U�N
file_reader.c
#include <stdio.h>
#include <stdlib.h>
#include "file_reader.h"
int file_reader_new(const char *file_path, struct FileReader *fr)
{
char *content; // holds the file content.
int counter; // holds the file number of lines.
size_t i; // indexing into content.
size_t buffer_size; // size of the content.
char *temp; // for realloc().
char c; // for reading from the input.
FILE *input; // our input stream.
if ((input = fopen(file_path, "r")) == NULL) {
fprintf(stderr, "Error opening input file %s\n", file_path);
exit(EXIT_FAILURE);
}
/* Initial allocation of content */
counter = 0;
i = 0;
buffer_size = BUFSIZ;
if ((content = malloc(buffer_size)) == NULL) {
fprintf(stderr, "Error allocating memory (before reading file).\n");
fclose(input);
}
while ((c = fgetc(input)) != EOF) {
/* Enlarge content if necessary. */
if (i == buffer_size) {
buffer_size += BUFSIZ;
if ((temp = realloc(content, buffer_size)) == NULL) {
fprintf(stderr, "Ran out of core while reading file.\n");
fclose(input);
free(content);
exit(EXIT_FAILURE);
}
content = temp;
}
/* Add input char to the content. */
content[i++] = c;
/* If the character is a break of line
* then the counter will be incremented.
*/
if (c == '\n')
counter++;
}
/* Test if loop terminated from error. */
if (ferror(input)) {
fprintf(stderr, "There was a file input error.\n");
free(content);
fclose(input);
exit(EXIT_FAILURE);
}
/* Make the content a bona-fide string. */
if (i == buffer_size) {
buffer_size += 1;
if ((temp = realloc(content, buffer_size)) == NULL) {
fprintf(stderr, "Ran out of core (and only needed one more byte too ;_;).\n");
fclose(input);
free(content);
exit(EXIT_FAILURE);
}
content = temp;
}
content[i] = '[=14=]';
/* Assigns the variables to the corresponding
* element of the struct.
*/
fr->file_path = file_path;
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content);
fclose(input);
return 0;
}
file_reader.h
#ifndef FILE_READER_H_
#define FILE_READER_H_
typedef struct FileReader
{
char *content; // holds the file content.
char *file_path; // holds the file path.
int *n_lines; // holds the number of lines.
int *n_characters; // holds the number of characters.
} FileReader;
// file_reader_new - reads the file
int file_reader_new(const char *file_path, struct FileReader *fr);
#endif
file_writer.c
#include <stdio.h>
#include "file_writer.h"
void write (struct FileWriter *fw)
{
FILE *f = fopen(fw->file_path, "w");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "%s", fw->content);
fclose(f);
}
file_writer.h
#ifndef FILE_WRITER_H_
#define FILE_WRITER_H_
typedef struct FileWriter
{
char *file_path;
char *content;
int *error;
} FileWriter;
#endif
你能帮帮我吗?谢谢!
struct FileReader *fr = malloc(sizeof(struct FileReader));
没有必要这样做。你只需要这个:
struct FileReader fr;
这里也一样:
struct FileWriter fw;
然后只需将这些变量的地址传递给必要的函数即可。
请注意,这不是作为答案提供给您的,只是作为注释来稍微清理您的代码以删除对堆的无关调用。碰巧真正的问题存在于其他地方,而您在这里看到的是 undefined behavior
的辉煌。
我不确定您是如何逐个字符或逐块读取文件的,但是无论如何,
因为你更新了content
缓冲区中的读取数据,并将content
缓冲区中的地址存储在file_reader_new()
中到变量fr->content
中并立即释放内存将结束失去你阅读的数据。并导致称为 悬挂指针
悬挂指针
(一个指针变量,指向释放的内存)
这就是为什么总是建议在释放后将指针变量设置为NULL
。在某些情况下,取消引用悬空指针将导致 Segmentation fault
或 undefined behavior
。
此外,由于 struct
的所有成员变量都是指针,因此最好将它们初始化为 NULL
。
您可以使用 calloc
来初始化 struct
中的所有变量,而不是 malloc
来将所有成员初始化为 NULL
,如果您要使用动态分配。这也适用于 string
。
这是我看到的一个问题:
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content); /* <-- Danger */
您在 file_reader_new
函数中执行此操作。然后调用 show_file_reader_values
并在该函数中访问 content
:
printf("content:\n%s\n", fr->content);
由于您对内容调用了 free()
,该指针不再指向有效内存,因此发生了未定义的行为。
解决方法是在fr
上为内容分配space并将content
的字符复制到这个space,或者干脆不调用free
在 content
.
所以要么这样做:
fr->content = malloc(i + 1);
strcpy(fr->content, content);
fr->n_lines = counter;
fr->n_characters = i;
/* Clean up. */
free(content);
或者这个:
fr->content = content;
fr->n_lines = counter;
fr->n_characters = i;
/* No call to free(content) done */