是的,我在评论中提到的是问题;您没有在realloc() call
中分配足够的内存:
这是我的代码,该代码使用c中的数组实现Queue数据结构。请注意,gMyQueue是我之前定义的Queue类型的全局变量。在此程序上运行Valgrind时-会大声喊出大小为4的无效读写错误。似乎没有什么错。
typedef struct Queue
{
size_t numOfElems;
size_t queueCapacity;
int *data;
} Queue;
Queue gMyQueue;
void printQueue()
{
for(size_t i = 0; i < gMyQueue.numOfElems; ++i)
{
printf("%d, ", gMyQueue.data[i]);
}
printf("\n");
printf("numOfElems: %lu, queueCapacity: %lu\n",
gMyQueue.numOfElems, gMyQueue.queueCapacity);
}
void cleanQueue()
{
if (gMyQueue.data != NULL)
{
free(gMyQueue.data);
}
}
void init()
{
gMyQueue.data = (int *) malloc(sizeof(int));
gMyQueue.queueCapacity = 1;
gMyQueue.numOfElems = 0;
}
void enqueue(int n) {
if (gMyQueue.numOfElems == 0 && gMyQueue.data == NULL) {
init();
gMyQueue.data[gMyQueue.numOfElems] = n;
gMyQueue.numOfElems++;
}
else {
gMyQueue.numOfElems++;
if (gMyQueue.numOfElems == gMyQueue.queueCapacity) {
gMyQueue.queueCapacity *= 2;
gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity);
}
gMyQueue.data[gMyQueue.numOfElems - 1] = n;
}
}
int dequeue(void) {
int dequeue = 0;
if (gMyQueue.numOfElems == 0) {
return dequeue;;
}
else {
dequeue = *(gMyQueue.data);
for (int i = 0; i < gMyQueue.numOfElems - 1; i++)
{
gMyQueue.data[i] = gMyQueue.data[i + 1];
}
gMyQueue.numOfElems--;
}
return dequeue;
}
int main()
{
init();
enqueue(1);
enqueue(2);
dequeue();
printQueue();
cleanQueue();
return 0;
}
我已经调试了一段时间,似乎一切正常,也可以使用指针和索引...但是运行valgrind会产生以下结果:
==12905== Invalid write of size 4
==12905== at 0x108CC9: enqueue (main.c:200)
==12905== by 0x109071: main (main.c:309)
==12905== Address 0x522d090 is 0 bytes inside a block of size 2 alloc'd
==12905== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12905== by 0x108CA5: enqueue (main.c:197)
==12905== by 0x109071: main (main.c:309)
==12905==
==12905== Invalid write of size 4
==12905== at 0x108CC9: enqueue (main.c:200)
==12905== by 0x10907B: main (main.c:310)
==12905== Address 0x522d0e4 is 0 bytes after a block of size 4 alloc'd
==12905== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12905== by 0x108CA5: enqueue (main.c:197)
==12905== by 0x10907B: main (main.c:310)
==12905==
==12905== Invalid read of size 4
==12905== at 0x108D2B: dequeue (main.c:213)
==12905== by 0x109080: main (main.c:311)
==12905== Address 0x522d0e4 is 0 bytes after a block of size 4 alloc'd
==12905== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12905== by 0x108CA5: enqueue (main.c:197)
==12905== by 0x10907B: main (main.c:310)
有人知道出什么事了吗?谢谢。
至少功能enqueue
错误。
else语句不得以numOfElems
的增量开头>
//... else { gMyQueue.numOfElems++; //…
因为此数据成员在if语句中的函数的第一次调用中已经递增]
if (gMyQueue.numOfElems == 0 && gMyQueue.data == NULL) { init(); gMyQueue.data[gMyQueue.numOfElems] = n; gMyQueue.numOfElems++; }
此函数
realloc
的调用gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity);
不正确。第二个参数应指定新分配的内存的大小。因此,通话至少应该看起来像
gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity * sizeof( int ) );
并且您应该使用中间指针,因为该函数可以返回NULL。在这种情况下,先前分配的内存的地址将丢失。
功能看起来像
void enqueue( int n )
{
if ( gMyQueue.data == NULL )
{
init();
gMyQueue.data[gMyQueue.numOfElems++] = n;
}
else
{
if ( gMyQueue.numOfElems == gMyQueue.queueCapacity )
{
gMyQueue.queueCapacity *= 2;
int *tmp = realloc( gMyQueue.data, gMyQueue.queueCapacity ( sizeof( int ) );
if ( tmp != NULL )
{
gMyQueue.data = tmp;
gMyQueue.data[gMyQueue.numOfElems++] = n;
}
}
}
}
是的,我在评论中提到的是问题;您没有在realloc() call
中分配足够的内存:
void enqueue(int n) {
if (gMyQueue.numOfElems == 0 && gMyQueue.data == NULL) {
init();
gMyQueue.data[gMyQueue.numOfElems] = n;
gMyQueue.numOfElems++;
}
else {
gMyQueue.numOfElems++;
if (gMyQueue.numOfElems == gMyQueue.queueCapacity) {
gMyQueue.queueCapacity *= 2;
gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity); // HERE
}
gMyQueue.data[gMyQueue.numOfElems - 1] = n;
}
}
您的代码正确扩展了容量-items
的最大数量-但在realloc()
期间它不会将items转换为bytes”。您可以在这里这样做::我建议您实际上从变量而不是类型的名称中得出大小。使用gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity * sizeof(int)); ^^^^^^^^^^^^^^
现在,Valgrind似乎对此很满意。
EDIT
sizeof(* gMyQueue.data)
而不是sizeof(int)
可以从变量所指向的对象中提取类型,如果更新代码,则只需更改一个即可。例如,如果您希望data
是long
而不是int
的数组,那么您当然必须更新结构以反映正确的类型,但是不必更新sizeof
。建议在原始文件malloc()
中也这样做。
这不是必需的,但这是一个很好的习惯,可以避免并避免日后出现问题。
是的,我在评论中提到的是问题;您没有在realloc() call
中分配足够的内存: