编写getline()实现 - Valgrind错误

时间:2017-01-14 22:26:36

标签: c memory valgrind getline

我必须重新编码getline()函数的实现,但是使用文件的文件描述符而不是FILE *。我只允许使用malloc()free(),以及最多25行的5个函数。 我认为我已经正确完成了项目,虽然我是C语言的初学者,但我的代码可能不错。

当我运行它时,它工作正常,但valgrind显示我definetely lost x bytes,x取决于文件长度和READ_SIZE(标头中定义的宏)。

根据valgrind的--leak-check=full,当我在malloc str_realloc_cat时,我在dest函数中有内存泄漏。我试过但无法找到自由/做其他事情的地方?

以下是我的代码:

char *get_next_line(const int fd)
{
  static char   *remaining = "";
  char          *buffer;
  ssize_t       cread;
  size_t       i;

  i = 0;
  if (remaining == NULL)
    return (NULL);
  if ((buffer = malloc(SOF(char) * READ_SIZE + 1)) == NULL ||
      (cread = read(fd, buffer, READ_SIZE)) < 0)
        return (NULL);
  buffer[cread] = 0;
  remaining = str_realloc_cat(remaining, buffer);
  while (remaining[i])
    {
      if (remaining[i] == 10)
        {
          remaining[i] = 0;
          buffer = str_create_cpy(remaining);
          remaining = remaining + i + 1;
          return (buffer);
        }
      i++;
    }
  return (check_eof(fd, buffer, remaining, cread));
}

char *str_realloc_cat(char *rem, char *buf)
{
  size_t i;
  size_t dest_i;
  char   *dest;

  i = (dest_i = 0);
  if ((dest = malloc(SOF(char) * (str_len(rem) + str_len(buf) + 1))) == NULL)
    return (NULL);
  while (rem[i])
    {
      dest[dest_i] = rem[i];
      dest_i++;
      i++;
    }
  i = 0;
  while (buf[i])
    {
      dest[dest_i] = buf[i];
      dest_i++;
      i++;
    }
  dest[dest_i] = 0;
  free(buf);
  return (dest);
}

char    *check_eof(const int fd, char *buffer, char *remaining, ssize_t cread)
{
  if (cread == 0)
    return (NULL);
  if (cread < READ_SIZE)
    {
      buffer = remaining;
      remaining = NULL;
      return (buffer);
    }
  return (get_next_line(fd));
}

char *str_create_cpy(const char *src)
{
  char *dest;
  size_t i;

  i = 0;
  if ((dest = malloc(sizeof(char) * str_len(src) + 1)) == NULL)
    return (NULL);
  while (src[i])
    {
      dest[i] = src[i];
      i++;
    }
  dest[i] = 0;
  return (dest);
}

int str_len(const char *str)
{
  size_t i;

  i = 0;
  while (str[i])
    i++;
  return (i);
}

如果你想测试一个主要的功能:

#define SOF(x) sizeof(x) // Why in the comments

int main(int ac, char **av)
{
  int  fd;
  char *s;

  UNUSED(ac);
  if (!av[1])
    return 1;
  fd = open(av[1], O_RDONLY);
  while ((s = get_next_line(fd)))
    {
      printf("%s\n", s);
      free(s);
    }
  close(fd);
}

2 个答案:

答案 0 :(得分:2)

你的算法不好:

  1. 将缓冲区保留在分配内存中
  2. 您不使用结构重新组合变量
  3. 您使用幻数remaining[i] == 10
  4. 您使用递归可以堆叠溢出return get_next_line(fd)。没关系,我没有读好你有一个尾递归,只要确保你的编译优化。
  5. 你有意大利面条代码。
  6. 你应该用更好的逻辑重写你的整个函数首先使用这个结构:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #define GNL_SIZE 4096
    
    struct gnl_context {
      char buffer[GNL_SIZE];
      size_t i;
      size_t read;
    };
    
    char *get_next_line_r(int fd, struct gnl_context *gnl_context);
    char *get_next_line(int fd);
    
    static char *read_buffer(struct gnl_context *gnl_context, char *str,
                             size_t *size) {
      size_t i = gnl_context->i;
      while (i < gnl_context->read && gnl_context->buffer[i] != '\n') {
        i++;
      }
      size_t j = i - gnl_context->i;
    
      char *ret = realloc(str, *size + j + 1);
      if (ret == NULL) {
        return NULL;
      }
      memcpy(ret + *size, gnl_context->buffer + gnl_context->i, j);
      *size += j;
      ret[*size] = '\0';
      gnl_context->i = i;
    
      return ret;
    }
    
    char *get_next_line_r(int fd, struct gnl_context *gnl_context) {
      char *str = NULL;
      size_t size = 0;
    loop:
      if (gnl_context->i == gnl_context->read) {
        ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE);
        if (ret <= 0) {
          return str;
        }
        gnl_context->read = (size_t)ret;
        gnl_context->i = 0;
      }
    
      char *tmp = read_buffer(gnl_context, str, &size);
      if (tmp == NULL) {
        return str;
      }
      if (gnl_context->i != gnl_context->read) {
        gnl_context->i++;
        return tmp;
      }
      str = tmp;
      goto loop;
    }
    
    char *get_next_line(int fd) {
      static struct gnl_context gnl_context;
      return get_next_line_r(fd, &gnl_context);
    }
    
    int main(void) {
      char *str;
      while ((str = get_next_line(0)) != NULL) {
        printf("%s\n", str);
        free(str);
      }
    }
    

答案 1 :(得分:1)

我担心这一行:

remaining = remaining + i + 1;

remaining是指向已分配缓冲区的指针。在这一行,你将其销毁,这意味着你不能再free()了。