【问题标题】:Am I freeing the dynamically allocated memories successfully?我是否成功释放了动态分配的内存?
【发布时间】:2023-04-07 12:05:02
【问题描述】:

我写了一个 C 程序来练习 DSA,特别是队列。

我编写了一个函数 free_q() 来释放动态分配的内存,但是当我打印指向这些结构的指针时,我得到的内存地址与打印 %p NULL 时不相等。我想知道为什么不仅释放动态时指针 Q 没有设置为 NULL。全部。结构体还有指向结构体内部数组的指针。

#include<stdio.h>
#include<math.h>
#include<stdlib.h>

struct queue_rec
{
    unsigned int front;
    unsigned int rear;
    unsigned int max_size;
    unsigned int size;
    int *arr_struct;
};

typedef struct queue_rec *QUEUE;


int 
isEmpty(QUEUE Q)
{
    return(Q->size==0);
}

int isFull(QUEUE Q)
{
    return(Q->size>=Q->max_size);
}

QUEUE
create_queue(unsigned int size)
{

    QUEUE Q = (QUEUE) malloc(sizeof(struct queue_rec));

    if(Q==NULL){printf("Out of space!");}
    else
    {
        Q->arr_struct = (int *) malloc(size * sizeof(int));

        if(Q->arr_struct == NULL){printf("Out of space!");}
        else
        {
            Q->size = 0;
            Q->front = 1;
            Q->rear = 0;
            Q->max_size = size;
        }
        
    }

    return Q;
    

}

unsigned int 
succ(unsigned int value, QUEUE Q)
{
    if(++value==Q->max_size){value=0;}
    return value;
}

void
enqueue(int data, QUEUE Q)
{
    if(isFull(Q)){printf("Queue is full!");}
    else
    {
        Q->size++;
        Q->rear = succ(Q->rear, Q);
        Q->arr_struct[Q->rear] = data;
    }
    
}

void 
dequeue(QUEUE Q)
{
    if(isEmpty(Q)){printf("Queue is empty!");}
    else
    {
        Q->size--;
        printf("%d", Q->arr_struct[Q->front]);
        Q->front = succ(Q->front,Q);
    }
    
}


void
free_q(QUEUE Q)
{
    free(Q->arr_struct);
    free(Q);
    Q = NULL;
}



int main()
{
    
    QUEUE Q = create_queue(4);
    free_q(Q);
    
    printf("%p\c", Q);
    printf("%p", NULL);

    


    return 0;
    
}

输出:

00031480
00000000

【问题讨论】:

  • Q = NULL;函数参数在C语言中是按值传递的。这意味着Q是函数中的一个局部变量,设置它不会改变调用者的变量。
  • @kaylum gotchu,我将 free_q() 函数设置为获取指向 Q 指针的指针,所以我将 &Q 作为参数传递,它现在可以工作了。另一个困惑是,即使在我没有更改调用者的变量之前,我释放了它所指向的内容,那么即使我释放了它,为什么它仍然指向某个地址?因为,当我将指针分配给动态分配的内存时,我的空间不足,指针指向 NULL,那么为什么在释放它时,它没有将指针设置为 NULL??
  • 使用valgrind

标签: c memory data-structures queue free


【解决方案1】:

free 将指针作为参数,这意味着它只能更改指针指向的内容。它不能将指针指向另一个对象。

void foo(int *p) {
    // Code
}

int main(void) {
    int x = 42;
    int *p = &x;
    int *q = &x;
    foo(p);
    if(p == q) 
        puts("Equal address"); // Guaranteed to be printed
    if(*p == *q)
        puts("Equal value");   // Depends on body of foo()
}

无论foo 中的正文如何,上面的代码都保证打印“Equal address”。但不能保证打印“等值”。如果签名是void foo(int **p),而您使用foo(&amp;p) 调用它,那就不同了。

如果你真的想要,你可以这样做:

void
free_q(QUEUE *Q)
{
    free((*Q)->arr_struct);
    free(*Q);
    *Q = NULL;
}

但我一般不会推荐这样的东西。对空指针的需求可能是您没有像您想象的那么多控制权的症状。你会在什么时候使用它?看看你是否正确地释放了它?不是一个好主意。看看这个:

QUEUE q = create_queue(42);
QUEUE p = q;
free_q(&q);
if(p == NULL) {
    // OOOPS

相反,我会这样做:

typedef struct queue_rec QUEUE; // No pointer

QUEUE
create_queue(unsigned int size)
{
    int *arr = malloc(size * sizeof *arr); 
    if(!arr){
        fprintf(stderr, "Out of space");
        exit(1);
    }
    return (QUEUE) { .max_size = size, .arr_struct = arr };
}

如果您出于某种原因想要动态分配整个队列,请手动执行:

QUEUE *q = malloc(sizeof *q);
*q = create_queue(42);

另外,我不鼓励类型定义指针。

【讨论】:

  • 所以如果在我的函数中我这样做: void free_q(QUEUE *Q) { free((*Q)->arr_struct);免费(* Q); *Q = 空;它应该可以工作,对吧?
  • @DaveHlave 是的,它会起作用,但我不鼓励它。查看更新的答案。
  • 非常感谢。在您的上一个代码中,您不是说 malloc(sizeof QUEUE) 而不是 malloc(sizeof *q) 吗?
  • @DaveHlave 不,我的意思是我写的。 :)
猜你喜欢
  • 1970-01-01
  • 2011-03-17
  • 2013-11-22
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-13
相关资源
最近更新 更多