这是我的代码,该代码使用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)
有人知道出什么事了吗? 谢谢。
答案 0 :(得分:2)
是的,我在评论中提到的是问题。您没有在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;
}
}
您的代码正确扩展了容量-最大数量的项目-但是在realloc()
期间,它没有将项目转换为字节强>。您可以在这里这样做:
gMyQueue.data = (int*)realloc(gMyQueue.data, gMyQueue.queueCapacity * sizeof(int));
^^^^^^^^^^^^^^
现在,Valgrind似乎对此很满意。
我建议您实际上从变量而不是类型的名称中得出大小。使用sizeof(* gMyQueue.data)
而不是sizeof(int)
可以从变量指向的对象中提取类型,如果更新代码,则只需更改即可。
例如,如果您希望data
是long
而不是int
的数组,那么您当然必须更新结构以反映正确的类型,但是您不会必须更新sizeof
。建议同样在原始malloc()
中进行相同的操作。
这不是必需的,但是这是一个很好的习惯,可以避免以后遇到的问题。
答案 1 :(得分:2)
至少函数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;
}
}
}
}