释放指针是否释放了它所引用的内存?

时间:2022-11-03 21:18:19

I'm currently working through Zed Shaw's Learn C the Hard Way tutorials and I'm trying to understand what is on the stack and what is on the heap in the following example, and how free() is working.

我目前正在研究Zed Shaw的Learn C the Hard Way教程,我正在尝试理解堆栈中的内容以及以下示例中的堆上的内容,以及free()的工作原理。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

/** our old friend die from ex17. */
void die(const char *message)
{
    if(errno) {
        perror(message);
    } else { 
        printf("ERROR: %s\n",message);
    }
    exit(1);
}

// a typedef creates a fake type, 
// in this case for a function pointer
typedef int (*compare_cb)(int a, int b);
// by declaring this pointer to a function
// we can use this like an int/char etc. in a function's arguments
/**
* A classic bubble sort function that uses the
* compare_cb to do the sorting.
*/
int *bubble_sort(int *numbers, int count, compare_cb cmp)
{
    int temp = 0;
    int i = 0;
    int j = 0;
    int *target = malloc(count * sizeof(int));

    if(!target) die("Memory error.");

    memcpy(target, numbers, count * sizeof(int));

    for(i = 0; i < count; i++) {
        for(j = 0; j < count - 1; j++){
            if(cmp(target[j], target[j+1]) > 0) {
                temp = target[j+1];
                target[j+1] = target[j];
                target[j] = temp;

            }
        }
    }
    return target;  // returns address of target(I think)
}                   // target will persist even after function 
                    // exit because we created on the heap (memcopy)
                    // so what happens if we run more than once?

int sorted_order(int a, int b)
{
    return a - b;
}

int reverse_order(int a, int b)
{
    return b - a;
}

int strange_order(int a, int b)
{
    if(a == 0 || b == 0) {
        return 0;
    } else {
        return a % b;
    }
}

/** 
 * used to test that we are sorting things correctly
 * by doing the sort and printing it out.
 */
void test_sorting(int *numbers, int count, compare_cb cmp)
{
    int i = 0;
    int *sorted = bubble_sort(numbers, count, cmp);

    if(!sorted) die("failed to sort as requested.");

    for(i = 0; i < count; i++){
        printf("%d ", sorted[i]);
    }
    printf("\n");

    free(sorted);
    sorted = NULL; 
}

int main(int argc, char *argv[])
{
    if(argc < 2) die("USAGE: ex18 4 3 1 5 6");

    int count = argc - 1;
    int i = 0;
    char **inputs = argv + 1;

    int *numbers = malloc(count * sizeof(int));
    if(!numbers) die("Memory error.");

    for(i = 0; i < count; i++) {
        numbers[i] = atoi(inputs[i]);
    }
    test_sorting(numbers, count, sorted_order);
    test_sorting(numbers, count, reverse_order);
    test_sorting(numbers, count, strange_order);

    free(numbers);
    numbers = NULL;

    return 0;
}

In the function bubble_sort, an array of ints target is created on the heap. My understanding is that since this is on the heap, it will persist after the function exits.

在函数bubble_sort中,在堆上创建一个int目标数组。我的理解是,由于这是在堆上,它将在函数退出后持续存在。

int *target = malloc(count * sizeof(int));

the function then returns target

然后该函数返回目标

return target;

I believe that means that the function returns the address of target

我相信这意味着该函数返回目标的地址

later, in test_sorting the result of the bubble_sort function is passed

之后,在test_sorting中传递bubble_sort函数的结果

int *sorted = bubble_sort(numbers, count, cmp);

so, if I'm right, the pointer sorted has been set to the same address as target

所以,如果我是对的,已经排序的指针已设置为与目标相同的地址

at the end of test_sorting *sorted is freed but the data pointed to by *target is never freed. But when I run the program in Valgrind I get no memory leaks, so this can't be true.

在test_sorting结束时*已释放,但* target指向的数据永远不会被释放。但是当我在Valgrind中运行程序时,我没有内存泄漏,所以这不可能是真的。

Am I right, then, in saying that when I free a pointer, the thing it points to is freed? I think probably not... I can't find any reference to this online so I'm assuming I'm mistaken at some point above, but I can't see where.

我是对的,然后说,当我释放一个指针时,它指向的东西被释放了吗?我想可能不是......我在网上找不到任何参考,所以我假设我在某些方面错了,但是我看不到哪里。

4 个解决方案

#1


2  

Does Freeing a Pointer Free the Memory it References?

释放指针是否释放了它所引用的内存?

Yes. Quoting from: Usage of free:

是。引用*:免费使用:

When we want to free a memory chunk previously allocated by malloc(), we use the free function. This function accepts a char pointer to a previously allocated memory chunk, and frees it - that is, adds it to the list of free memory chunks, that may be re-allocated. Several notes about free():

当我们想要释放以前由malloc()分配的内存块时,我们使用free函数。此函数接受指向先前分配的内存块的char指针,并释放它 - 即,将其添加到可以重新分配的空闲内存块列表中。关于free()的几点注意事项:

  • The size of the chunk was stored by malloc() previously in its memory map, and that is how free() knows how many bytes to free.
  • 块的大小由malloc()先前存储在其内存映射中,这就是free()知道要释放多少字节的方式。

  • The freed memory is not being cleared or erased in any manner. This is why accessing memory that was just freed often does not cause a crash - any data in it is still the same as before calling free().

    释放的内存不会以任何方式清除或擦除。这就是为什么访问刚刚释放的内存不会导致崩溃的原因 - 其中的任何数据仍然与调用free()之前相同。

  • The free() function cannot nullify pointers to the given memory chunk that might still exist in our program. After we call free(), it is up to us (the programmers) not to try and dereference pointers that still point to that memory chunk. Such pointers are known as 'dangling pointers' - they point to memory that was already freed, and thus they should NOT be dereferenced again, unless they are assigned the address of a different (not-freed) memory chunk.

    free()函数不能使指向我们程序中可能仍然存在的给定内存块的指针无效。在我们调用free()之后,由我们(程序员)决定不尝试和取消引用仍然指向该内存块的指针。这样的指针被称为“悬空指针” - 它们指向已经释放的内存,因此它们不应再被取消引用,除非它们被分配了不同(未释放)内存块的地址。

As you can see, free() only marks the memory chunk as free - there is no enforcement of this freeing operation.

正如您所看到的,free()仅将内存块标记为空闲 - 没有强制执行此释放操作。

#2


2  

You're not running free to release the memory used to store the pointer value, but to free up the chunk of memory that pointer references, and the pointers sorted and target reference the same chunk of memory (within scope). When you free that memory, neither pointer can be legally dereferenced to that chunk.

你没有*释放用于存储指针值的内存,而是释放指针引用的内存块,并且指针排序和目标引用同一块内存(在范围内)。释放该内存时,两个指针都不能合法地取消引用该块。

#3


1  

The pointer itself is allocated on the stack and - as you already mentioned - holds an address. You also return the pointer by value and pass it by value unless you pass a pointer to the pointer. Malloc allocates memory somewhere and returns a pointer to this location(the address). If you don't want this memory to become unusable, you have to tell the system that you don't need it any longer later. Therefore you pass the address (i.e. the pointer) of the previously allocated chuck to free. This call actually frees the memory pointed to. The pointer itself will go out of scope when the function returns.

指针本身在堆栈上分配 - 正如您已经提到的 - 保存一个地址。您还可以按值返回指针并按值传递,除非您将指针传递给指针。 Malloc在某处分配内存并返回指向此位置的指针(地址)。如果您不希望此内存无法使用,则必须告诉系统您以后不再需要它。因此,您将先前分配的卡盘的地址(即指针)传递给空闲。这个调用实际上释放了指向的内存。函数返回时,指针本身将超出范围。

#4


0  

Yes, sorted and target will have the same address.
You can see this by printing both values.
In bubble_sort: printf("target address %X\n", target);
In test_sorting: printf("sorted address %X\n", sorted);

是的,已排序和目标将具有相同的地址。您可以通过打印两个值来查看。在bubble_sort:printf(“目标地址%X \ n”,目标);在test_sorting中:printf(“已排序的地址%X \ n”,已排序);

These should be the same, so the address is returned, then freed.

这些应该是相同的,所以返回地址,然后释放。

#1


2  

Does Freeing a Pointer Free the Memory it References?

释放指针是否释放了它所引用的内存?

Yes. Quoting from: Usage of free:

是。引用*:免费使用:

When we want to free a memory chunk previously allocated by malloc(), we use the free function. This function accepts a char pointer to a previously allocated memory chunk, and frees it - that is, adds it to the list of free memory chunks, that may be re-allocated. Several notes about free():

当我们想要释放以前由malloc()分配的内存块时,我们使用free函数。此函数接受指向先前分配的内存块的char指针,并释放它 - 即,将其添加到可以重新分配的空闲内存块列表中。关于free()的几点注意事项:

  • The size of the chunk was stored by malloc() previously in its memory map, and that is how free() knows how many bytes to free.
  • 块的大小由malloc()先前存储在其内存映射中,这就是free()知道要释放多少字节的方式。

  • The freed memory is not being cleared or erased in any manner. This is why accessing memory that was just freed often does not cause a crash - any data in it is still the same as before calling free().

    释放的内存不会以任何方式清除或擦除。这就是为什么访问刚刚释放的内存不会导致崩溃的原因 - 其中的任何数据仍然与调用free()之前相同。

  • The free() function cannot nullify pointers to the given memory chunk that might still exist in our program. After we call free(), it is up to us (the programmers) not to try and dereference pointers that still point to that memory chunk. Such pointers are known as 'dangling pointers' - they point to memory that was already freed, and thus they should NOT be dereferenced again, unless they are assigned the address of a different (not-freed) memory chunk.

    free()函数不能使指向我们程序中可能仍然存在的给定内存块的指针无效。在我们调用free()之后,由我们(程序员)决定不尝试和取消引用仍然指向该内存块的指针。这样的指针被称为“悬空指针” - 它们指向已经释放的内存,因此它们不应再被取消引用,除非它们被分配了不同(未释放)内存块的地址。

As you can see, free() only marks the memory chunk as free - there is no enforcement of this freeing operation.

正如您所看到的,free()仅将内存块标记为空闲 - 没有强制执行此释放操作。

#2


2  

You're not running free to release the memory used to store the pointer value, but to free up the chunk of memory that pointer references, and the pointers sorted and target reference the same chunk of memory (within scope). When you free that memory, neither pointer can be legally dereferenced to that chunk.

你没有*释放用于存储指针值的内存,而是释放指针引用的内存块,并且指针排序和目标引用同一块内存(在范围内)。释放该内存时,两个指针都不能合法地取消引用该块。

#3


1  

The pointer itself is allocated on the stack and - as you already mentioned - holds an address. You also return the pointer by value and pass it by value unless you pass a pointer to the pointer. Malloc allocates memory somewhere and returns a pointer to this location(the address). If you don't want this memory to become unusable, you have to tell the system that you don't need it any longer later. Therefore you pass the address (i.e. the pointer) of the previously allocated chuck to free. This call actually frees the memory pointed to. The pointer itself will go out of scope when the function returns.

指针本身在堆栈上分配 - 正如您已经提到的 - 保存一个地址。您还可以按值返回指针并按值传递,除非您将指针传递给指针。 Malloc在某处分配内存并返回指向此位置的指针(地址)。如果您不希望此内存无法使用,则必须告诉系统您以后不再需要它。因此,您将先前分配的卡盘的地址(即指针)传递给空闲。这个调用实际上释放了指向的内存。函数返回时,指针本身将超出范围。

#4


0  

Yes, sorted and target will have the same address.
You can see this by printing both values.
In bubble_sort: printf("target address %X\n", target);
In test_sorting: printf("sorted address %X\n", sorted);

是的,已排序和目标将具有相同的地址。您可以通过打印两个值来查看。在bubble_sort:printf(“目标地址%X \ n”,目标);在test_sorting中:printf(“已排序的地址%X \ n”,已排序);

These should be the same, so the address is returned, then freed.

这些应该是相同的,所以返回地址,然后释放。