C 释放getline()缓冲区后丢失的字节数

C 释放getline()缓冲区后丢失的字节数,c,malloc,free,getline,C,Malloc,Free,Getline,我已经查找了有关使用getline()时valgrind内存泄漏的帖子 基本上,我的代码是使用getline()在一行中读取的 } 如您所见,我为char*lineOrigin分配了一些内存,然后有第二个指针*line_ptr,指向*lineOrigin,稍后在代码中进行了修改 这段代码几乎从stdin中读入整数,并将它们按顺序存储到LinkedList中 每次sscanf将int读入&val时,我都会使用lookPastSpace()将*line_ptr移动到字符串中的非空格字符上,直到遇到另

我已经查找了有关使用getline()时valgrind内存泄漏的帖子

基本上,我的代码是使用getline()在一行中读取的

}

如您所见,我为char*lineOrigin分配了一些内存,然后有第二个指针*line_ptr,指向*lineOrigin,稍后在代码中进行了修改

这段代码几乎从stdin中读入整数,并将它们按顺序存储到LinkedList中

每次sscanf将int读入&val时,我都会使用lookPastSpace()将*line_ptr移动到字符串中的非空格字符上,直到遇到另一个空格,然后再将指针移动一个槽口,以便line_ptr现在指向字符串中可以读入新int的下一个位置

line_ptr = "123 456 789\n"
line_ptr = lookPastSpace(line_ptr)
line_ptr = "456 789\n"
...
line_ptr = "" -->sscanf stops.
接下来,我沿着链表走下去,释放每个分配的节点,因为节点没有分配内存的内容,所以我要释放LL的内存就到这里

然后,稍后,我将释放char*lineOrigin,这可能会起作用,因为它是最初分配的缓冲区,但它不是

    tylerjgabb@lectura:~/HW6/medianDir$ make mem
valgrind median
==11827== Memcheck, a memory error detector
==11827== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==11827== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==11827== Command: median
==11827==
123 456 789
1
1
1
[123, 456, 789]
==11827== Invalid free() / delete / delete[] / realloc()
==11827==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11827==    by 0x400B37: main (in /p3/ht/tylerjgabb/HW6/medianDir/median)
==11827==  Address 0x51ff040 is 0 bytes inside a block of size 5 free'd
==11827==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11827==    by 0x4EA5F9A: getdelim (iogetdelim.c:106)
==11827==    by 0x400A73: main (in /p3/ht/tylerjgabb/HW6/medianDir/median)
==11827==
==11827==
==11827== HEAP SUMMARY:
==11827==     in use at exit: 13 bytes in 1 blocks
==11827==   total heap usage: 5 allocs, 5 frees, 66 bytes allocated
==11827==
==11827== LEAK SUMMARY:
==11827==    definitely lost: 13 bytes in 1 blocks
==11827==    indirectly lost: 0 bytes in 0 blocks
==11827==      possibly lost: 0 bytes in 0 blocks
==11827==    still reachable: 0 bytes in 0 blocks
==11827==         suppressed: 0 bytes in 0 blocks
==11827== Rerun with --leak-check=full to see details of leaked memory
==11827==
==11827== For counts of detected and suppressed errors, rerun with: -v
==11827== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
tylerjgabb@lectura:~/HW6/medianDir$
我有点迷糊了。你知道怎么回事吗

--------------关于TYPEDEFS和LL函数的澄清----------------- LLfuncs.c

    #include "LinkedListHeader.h"
    #include <stdlib.h>

    void LLinit(LL *LL_ptr){
        LL_ptr->head_ptr = NULL;
        LL_ptr->tail_ptr = NULL;
        LL_ptr->length = 0;
    }


void freeLL(LL *LL_ptr){
    Node *curr_ptr = LL_ptr->head_ptr;
    while(curr_ptr != NULL){
        Node *next_ptr = curr_ptr->next_ptr;
        free(curr_ptr);
        curr_ptr = next_ptr;
    }
}
#包括“LinkedListHeader.h”
#包括
作废LLinit(LL*LL_ptr){
LL_ptr->head_ptr=NULL;
LL_ptr->tail_ptr=NULL;
LL_ptr->长度=0;
}
void freeLL(LL*LL_ptr){
节点*curr\u ptr=LL\u ptr->head\u ptr;
while(curr_ptr!=NULL){
节点*next\u ptr=curr\u ptr->next\u ptr;
免费(现金);
curr_ptr=下一个_ptr;
}
}
以上只是我的LLfuncs.c的一小部分

    #include "LinkedListHeader.h"
    #include <stdlib.h>

    void LLinit(LL *LL_ptr){
        LL_ptr->head_ptr = NULL;
        LL_ptr->tail_ptr = NULL;
        LL_ptr->length = 0;
    }


void freeLL(LL *LL_ptr){
    Node *curr_ptr = LL_ptr->head_ptr;
    while(curr_ptr != NULL){
        Node *next_ptr = curr_ptr->next_ptr;
        free(curr_ptr);
        curr_ptr = next_ptr;
    }
}
LinkedListHeader.h

/* This is a header file containing typedefs and macros for linked lists *Tyler J Gabb
 *For assignment 6a. Shuffle.
 */
#include <stdio.h>
#define showLocs(LL) printf("head_ptr = %p, tail_ptr = %p length = %d\n",LL.head_ptr,LL.tail_ptr,LL.length)


typedef struct LinkedListNode {
  int val;
  struct LinkedListNode *next_ptr;
} Node;

typedef struct LinkedList {
    Node *head_ptr;
    Node *tail_ptr;
    int length;
} LL;
/*这是一个包含链接列表的typedef和宏的头文件*Tyler J Gabb
*作业6a。洗牌
*/
#包括
#定义showLocs(LL)printf(“head\u ptr=%p,tail\u ptr=%p length=%d\n”,LL.head\u ptr,LL.tail\u ptr,LL.length)
typedef结构LinkedListNode{
int-val;
结构LinkedListNode*下一步\u ptr;
}节点;
类型定义结构链接列表{
节点*头部ptr;
节点*tail_ptr;
整数长度;
}LL;
LLinit()初始化任何最近声明的LL类型,使其头部和尾部为0x0,长度为0。这有助于使LL发生变异的其他功能

-------------------------------一些其他有趣的信息-----------------


如果输入字符串的大小小于len的原始值,则不会出现内存泄漏(有时)

您基本上有以下模式:

char *lineOrigin, *line_ptr;
size_t len = 5;

lineOrigin = malloc(len);
line_ptr = lineOrigin;
getline(&line_ptr, &len, stdin);
由于将在必要时重新分配缓冲区,因此在调用
getline()
之后,
lineOrigin
可能不再有效

实际上,您在
lineOrigin
中保留了一个旧指针的副本,该指针可能由
getline()
调用释放。您没有释放可能由
getline()
line\u ptr
重新分配的当前缓冲区,而是错误地(使用)和
free()
一些旧值不再有效:
lineOrigin


编写模式的正确方法很简单。首先,将行指针定义为
NULL
,并将其分配的大小定义为零。我将分配的大小称为
line\u max
,其中
line\u len
反映了当前行的长度,但是您显然可以使用您认为最容易维护的变量命名

char   *line_ptr = NULL;
size_t  line_max = 0;
ssize_t line_len;
您可以使用

line_len = getline(&line_ptr, &line_max, stdin);
if (line_len > 0) {
    /* You have a line in line_ptr */
} else
if (ferror(stdin)) {
    /* Error reading from standard input (rare!) */

} else
if (feof(stdin)) {
    /* No more data to read from standard input. */
}
您可以根据需要多次重复上述操作,但您需要意识到,
line_ptr
line_max
的值在不同的调用中可能会有所不同

完成后,释放行缓冲区。因为
free(空)始终是安全的,即使未读取实际行,也可以安全执行此操作:

free(line_ptr);
line_ptr = NULL;
line_max = 0;
现在,清除变量并不是绝对必要的,但我发现这是一个很好的实践,有时甚至可以帮助调试


还要注意的是,即使在调用
getline()
之前,也完全可以像上面那样释放缓冲区并清除变量,因为
getline()
不关心它是获得大小为零的空指针,还是之前分配的大小为非零的缓冲区。

FYI,您不必
malloc
ing缓冲区,因为
getline
将为您执行此操作,*如果在调用之前lineptr设置为NULL且*n设置为0,则getline()将分配一个缓冲区来存储该行“根据,但您必须释放缓冲区。尝试一下,看看这是否有区别,如果没有区别,那么错误就在某个地方,我的赌注是
line\u ptr=lookPastSpace(line\u ptr)是它撞击指针的地方。添加了澄清和其他源文件和标题文件。感谢大家到目前为止的评论。我正在努力寻找solution@t0mm13b . 我只是按照你的指示更改了代码。它现在没有错误,但仍然丢失字节。如果(status==0){
是真的,你在返回之前没有释放你分配的内存。我喜欢你的答案的彻底性。这是一个很大的帮助。我准备进入空闲()在valgrind中运行时,我很快发现自己陷入了恐惧之中可能改变了,也可能没有改变它的起源。我要做的是在通过
getline()
加载一个字符串后,用
char*line\u save=line\u ptr
将行\u ptr的位置保存为
free(line\u save)
。谢谢