在调用函数后,结构的元素会丢失其值,并将另一个结构作为参数传递

时间:2015-02-17 16:35:27

标签: c pointers struct

我有一个我无法弄清楚的问题。我有以下文件: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");
}

函数&#39; file_reader_new&#39;读取文件,然后将内容,文件路径,行数和字符数签名到&#39; struct&#39; &#39;的FileReader&#39;

当我调用函数&#39; show_file_reader_values&#39;在第一次我没有内容问题,但当我打电话给函数&#39;写&#39;然后调用函数&#39; show_file_reader_values&#39;再一次,内容不再相同了。问题是功能“写”&#39;文件&#39; file_writer.c&#39;并且它的结构与文件&#39; file_reader&#39;没有任何关系。和它的结构。那么,使用另一个struct的函数如何改变另一个文件的另一个结构的值?

输出:

[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] = '\0';

  /* 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
你能帮帮我吗?谢谢!

3 个答案:

答案 0 :(得分:1)

struct FileReader *fr = malloc(sizeof(struct FileReader)); 

没有必要这样做。所有你需要的是:

struct FileReader fr; 

同样在这里:

struct FileWriter fw; 

然后只需将这些变量的地址传递给必需的函数。


请注意,这不作为答案提供给您,仅作为注释来清除您的代码以删除对堆的无关调用。碰巧真正的问题存在于其他地方,你在这里看到的是undefined behavior充满荣耀。

答案 1 :(得分:1)

我不确定你是如何从文件,字符或块中读取的,但无论如何,

因为您更新content缓冲区中的读取数据,并将content缓冲区内file_reader_new()的地址存储到变量fr->content中并立即释放内存将最终失去你读过的数据。并导致称为悬空指针

的条件

悬空指针

(指针变量,指向已释放的内存)

这就是为什么总是建议在释放到NULL之后设置指针变量。在某些情况下,取消引用悬空指针会导致Segmentation faultundefined behavior

此外,由于struct的所有成员变量都是指针,因此最好将它们初始化为NULL

如果您要进行动态分配,可以使用calloc初始化struct中的所有变量,而不是malloc将所有成员初始化为NULL 。也适用于string

答案 2 :(得分:0)

我看到这是一个问题:

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上为内容分配空间,并将content的字符复制到此空间,或者只是不在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 */