所以我在" main.c"
中有这样的东西#include "foo.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct myStruct
{
int dummyMember1;
float dummyMember2;
} myStruct_t;
int main()
{
myStruct_t* a = malloc(sizeof(myStruct_t));
a->dummyMember1 = 10;
a->dummyMember2 = 5.5;
push(a);
myStruct_t* b = pop();
if(b != NULL)
{
b->dummyMember1;
b->dummyMember2;
}
free(b);
return 0;
}
然后我在某个文件&#34; foo.h&#34;
中有类似的东西void push(void* item);
void* pop();
在&#34; foo.c&#34;我有类似的东西
#include "foo.h"
#include <stdlib.h>
#include <string.h>
#define ARR_SIZE 50
void* arr[ARR_SIZE];
int free_space = ARR_SIZE;
void push(void* item)
{
if(free_space > 0){
arr[ARR_SIZE - free_space] = item;
free_space--;
}
return;
}
void* pop()
{
void* p_ret = NULL;
if(free_space < ARR_SIZE)
{
void* p = arr[ARR_SIZE-(free_space+1)];
p_ret = malloc(sizeof(*p));
memcpy(p_ret, p, sizeof(*p));
free(p);
free_space++;
}
return p_ret;
}
此代码编译并在没有段错误的情况下运行,但问题是valgrind报告了无效的读取错误(即使它说&#34;所有堆块都被释放 - 没有泄漏可能&#34;)。
我的问题是,是什么导致valgrind报告无效的读错误(这都是指pop()函数)?
答案 0 :(得分:0)
只关心编译而不是结果。两个地方可能是错的。 第一个:
myStruct_t* structVar = pop();
//it can not realize structVar like this,you must use 'force converse'.
myStruct_t* structVar = (myStruct_t *)pop();
第二个:
p_ret = malloc(sizeof(*p));
//sizeof() parameters must be Object ,data type,and size.
p_ret = malloc(sizeof(p));
memcpy(p_ret, p, sizeof(p));
希望对你有所帮助。
答案 1 :(得分:0)
push()
和pop()
中的代码有点令人费解。在我的首选编译器选项下编译代码并进行最少的必要更改,然后在valgrind
下运行它,我收到警告:
==59504== Invalid read of size 4
==59504== at 0x100000EBF: main (main.c:21)
==59504== Address 0x100aa74e4 is 3 bytes after a block of size 1 alloc'd
==59504== at 0x100007E81: malloc (vg_replace_malloc.c:302)
==59504== by 0x100000E50: pop (foo.c:26)
==59504== by 0x100000EA4: main (main.c:18)
麻烦在于你的pop()
功能;您正尝试在sizeof(*p)
为p
的位置分配void *
字节,因此*p
为void
,其大小不足。 GCC(在我看来无用)将其视为对1
字节的请求,而不是给出应该给出的错误。您必须请求-pedantic
警告才能收到消息:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror -pedantic -c foo.c
foo.c: In function ‘pop’:
foo.c:26:30: error: invalid application of ‘sizeof’ to a void type [-Werror=pointer-arith]
p_ret = malloc(sizeof(*p));
^
In file included from /usr/include/string.h:186:0,
from foo.c:3:
foo.c:27:32: error: invalid application of ‘sizeof’ to a void type [-Werror=pointer-arith]
memcpy(p_ret, p, sizeof(*p));
cc1: all warnings being treated as errors
$
由于您将void *
值存储在固定数组中,因此堆栈中不需要任何动态内存分配。你可以使用:
#include "foo.h"
enum { ARR_SIZE = 50 };
static void *arr[ARR_SIZE];
static int free_space = ARR_SIZE;
void push(void *item)
{
if (free_space > 0)
{
arr[ARR_SIZE - free_space] = item;
free_space--;
}
}
void *pop(void)
{
void *p_ret = 0;
if (free_space < ARR_SIZE)
{
p_ret = arr[ARR_SIZE - (free_space + 1)];
free_space++;
}
return p_ret;
}
修改后的测试程序:
#include "foo.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct myStruct
{
int dummyMember1;
float dummyMember2;
} myStruct_t;
int main(void)
{
for (int i = 0; i < 3; i++)
{
myStruct_t *a = malloc(sizeof(myStruct_t));
a->dummyMember1 = 10 + i;
a->dummyMember2 = 5.5 * i;
push(a);
myStruct_t *b = pop();
if (b != NULL)
{
printf("Popped: %d and %f\n", b->dummyMember1, b->dummyMember2);
}
free(a);
}
return 0;
}
我得到valgrind
输出,例如:
==59611== Memcheck, a memory error detector
==59611== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==59611== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==59611== Command: foo
==59611==
--59611-- run: /usr/bin/dsymutil "./foo"
Popped: 10 and 0.000000
Popped: 11 and 5.500000
Popped: 12 and 11.000000
==59611==
==59611== HEAP SUMMARY:
==59611== in use at exit: 26,437 bytes in 189 blocks
==59611== total heap usage: 274 allocs, 85 frees, 32,661 bytes allocated
==59611==
==59611== LEAK SUMMARY:
==59611== definitely lost: 80 bytes in 1 blocks
==59611== indirectly lost: 68 bytes in 2 blocks
==59611== possibly lost: 0 bytes in 0 blocks
==59611== still reachable: 0 bytes in 0 blocks
==59611== suppressed: 26,289 bytes in 186 blocks
==59611== Rerun with --leak-check=full to see details of leaked memory
==59611==
==59611== For counts of detected and suppressed errors, rerun with: -v
==59611== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
那看起来很糟糕 - 失去了记忆。但是使用--leak-check=full
运行会产生:
==59641== 148 (80 direct, 68 indirect) bytes in 1 blocks are definitely lost in loss record 43 of 66
==59641== at 0x100007E81: malloc (vg_replace_malloc.c:302)
==59641== by 0x1001E58D6: __Balloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==59641== by 0x1001E2553: __rv_alloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==59641== by 0x1001E2574: __nrv_alloc_D2A (in /usr/lib/system/libsystem_c.dylib)
==59641== by 0x10020B3E6: __vfprintf (in /usr/lib/system/libsystem_c.dylib)
==59641== by 0x1002346C8: __v2printf (in /usr/lib/system/libsystem_c.dylib)
==59641== by 0x10020A389: vfprintf_l (in /usr/lib/system/libsystem_c.dylib)
==59641== by 0x100208223: printf (in /usr/lib/system/libsystem_c.dylib)
==59641== by 0x100000EA4: main (main.c:23)
我尝试添加fclose(stdout)
,但这并没有解决它。这个问题深埋在本地printf()
函数内部,完全在你的控制范围内和我的控制之外。我需要添加抑制。 Mac OS X往往会有很多这类泄漏 - 见证已经原位的抑制(180+分配中几乎27 KiB)。
如果你真的必须在你的堆栈中使用内存分配,你需要仔细考虑你正在推动堆栈的内容,以及你正在弹出它的内容。您可能需要知道要存储的对象的大小。然后,您将通过修改压入堆栈的值来证明堆栈不受影响,因为堆栈复制了该值。当你只是堆叠指针时,如果当前数组太小时堆栈增长,你只需要动态内存分配。