Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 编写getline()实现-Valgrind错误_C_Memory_Valgrind_Getline - Fatal编程技术网

C 编写getline()实现-Valgrind错误

C 编写getline()实现-Valgrind错误,c,memory,valgrind,getline,C,Memory,Valgrind,Getline,我必须重新编码getline()函数的实现,但要使用文件的文件描述符,而不是文件*。我只允许使用malloc()和free(),以及5个最多25行的函数。 我认为我已经正确地完成了这个项目,尽管我是C语言的初学者,我的代码可能不太好 当我运行它时,它工作得很好,但是valgrind显示我确实丢失了x字节,x取决于文件长度和读取大小(在头中定义的宏) 根据valgrind的--leak check=full,我在mallocdest时,在str\u realloc\u cat函数中有内存泄漏。我试

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

当我运行它时,它工作得很好,但是valgrind显示我确实丢失了x字节,x取决于文件长度和读取大小(在头中定义的宏)

根据valgrind的
--leak check=full
,我在malloc
dest
时,在
str\u realloc\u cat
函数中有内存泄漏。我试过了,但找不到我应该在哪里释放/做些别的事情

下面是我的代码:

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);
}

我关注这一行:

remaining = remaining + i + 1;

remaining
是指向已分配缓冲区的指针。在这一行中,你破坏了它,这意味着你不能再
释放它了。

我担心这一行:

remaining = remaining + i + 1;
remaining
是指向已分配缓冲区的指针。在这一行中,您销毁了它,这意味着您不能再
释放它了。

您的算法不好:

  • 将缓冲区保存在分配内存中
  • 您不需要使用结构来重新组合变量
  • 您使用的是幻数
    剩余[i]==10
  • 您可以使用递归堆栈溢出
    返回get\u next\u line(fd)
    。没关系,我读得不太好,你有一个尾部递归,只是要确保在编译过程中对它进行优化
  • 你有意大利面密码
  • 等等
  • 您应该使用更好的逻辑重写整个函数,首先使用以下结构:

    #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);
      }
    }
    
    #包括
    #包括
    #包括
    #包括
    #定义GNL_尺寸4096
    结构gnl_上下文{
    字符缓冲区[GNL_大小];
    尺寸i;
    尺寸不可读取;
    };
    char*get_next_line_r(int fd,struct gnl_context*gnl_context);
    字符*获取下一行(int fd);
    静态char*read\u缓冲区(struct gnl\u context*gnl\u context,char*str,
    尺寸(t*尺寸){
    size\u ti=gnl\u context->i;
    而(iread&&gnl\u context->buffer[i]!='\n'){
    i++;
    }
    size\u t j=i-gnl\u context->i;
    char*ret=realloc(str,*size+j+1);
    if(ret==NULL){
    返回NULL;
    }
    memcpy(ret+*size,gnl_上下文->缓冲区+gnl_上下文->i,j);
    *尺寸+=j;
    ret[*size]='\0';
    gnl_上下文->i=i;
    返回ret;
    }
    char*get_next_line_r(int fd,结构gnl_context*gnl_context){
    char*str=NULL;
    大小\u t大小=0;
    循环:
    如果(gnl_上下文->i==gnl_上下文->读取){
    ssize_t ret=read(fd,gnl_上下文->缓冲区,gnl_大小);
    if(ret read=(size_t)ret;
    gnl_上下文->i=0;
    }
    char*tmp=read\u缓冲区(gnl\u上下文、str和size);
    if(tmp==NULL){
    返回str;
    }
    如果(gnl_上下文->i!=gnl_上下文->读取){
    gnl_上下文->i++;
    返回tmp;
    }
    str=tmp;
    后藤环;
    }
    字符*获取下一行(int fd){
    静态结构gnl_上下文gnl_上下文;
    返回get_next_line_r(fd和gnl_上下文);
    }
    内部主(空){
    char*str;
    while((str=get_next_line(0))!=NULL){
    printf(“%s\n”,str);
    自由基(str);
    }
    }
    
    您的算法不好:

  • 将缓冲区保存在分配内存中
  • 您不需要使用结构来重新组合变量
  • 您使用的是幻数
    剩余[i]==10
  • 您可以使用递归堆栈溢出
    return get\u next\u line(fd)
    。没关系,我读得不太好,您有一个尾部递归,请确保在编译时对其进行优化
  • 你有意大利面密码
  • 等等
  • 您应该使用更好的逻辑重写整个函数,首先使用以下结构:

    #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);
      }
    }
    
    #包括
    #包括
    #包括
    #包括
    #定义GNL_尺寸4096
    结构gnl_上下文{
    字符缓冲区[GNL_大小];
    尺寸i;
    尺寸不可读取;
    };
    char*get_next_line_r(int fd,struct gnl_context*gnl_context);
    字符*获取下一行(int fd);
    静态char*read\u缓冲区(struct gnl\u context*gnl\u context,char*str,
    尺寸(t*尺寸){
    size\u ti=gnl\u context->i;
    而(iread&&gnl\u context->buffer[i]!='\n'){
    i++;
    }
    size\u t j=i-gnl\u context->i;
    char*ret=realloc(str,*size+j+1);
    if(ret==NULL){
    返回NULL;
    }
    memcpy(ret+*size,gnl_上下文->缓冲区+gnl_上下文->i,j);
    *尺寸+=j;
    ret[*size]='\0';
    gnl_上下文->i=i;
    返回ret;
    }
    char*get_next_line_r(int fd,结构gnl_context*gnl_context){
    char*str=NULL;
    大小\u t大小=0;
    循环:
    如果(gnl_上下文->i==gnl_上下文->读取){
    ssize_t ret=read(fd,gnl_上下文->缓冲区,gnl_大小);
    if(ret read=(size_t)ret;
    gnl_上下文->i=0;
    }
    char*tmp=read\u缓冲区(gnl\u上下文、str和size);
    if(tmp==NULL){
    返回str;
    }
    如果(gnl_上下文->i!=gnl_上下文->读取){
    gnl_上下文->i++;
    返回tmp;
    }
    str=tmp;
    后藤环;
    }
    字符*获取下一行(int fd){
    静态结构gnl_上下文gnl_上下文;
    返回get_next_line_r(fd和gnl_上下文);
    }
    内部主(空){
    char*str;
    while((str=get_next_line(0))!=NULL){
    printf(“%s\n”,str);
    自由基(str);
    }
    }
    
    sizeof(char)
    总是1,不要用它污染你的代码。使用
    #define SOF(x)sizeof(x)
    -不是显示而是推断出来的-似乎有点毫无意义。它可以在每次调用中节省3个字符,但会造成混乱。这不是一个很好的折衷办法。“在另一个系统上,一个char超过1个字节(尽管不太可能)。”唯一可能发生这种情况的方法是,如果C编译器不符合标准。
    sizeof(char)
    根据C标准为1,它永远不依赖于系统。
    if(!av[1])
    是检查是否没有参数的错误方法。虽然
    av
    数组以null结尾,但只能保证
    av[ac]
    将为空。在某些环境中,
    ac
    可能为0