繁体   English   中英

自由动态分配的阵列C.

[英]Free Dynamically Allocated Array C

我处于一种两难的境地,因此,首先,我想道歉,如果下一个问题会更加荒谬,或者之前是否曾被问过(我找不到那些答案)。

无论如何,我会以一个任务为例来解释它(这不是作业,只是为了我的问题)。 在这里:

Given a string from stdin index each word, then print each word on one line.
Example:
str[] = "Stack is awesome"
str_index {
    [0] => "Stack"
    [1] => "is"
    [2] => "awesome"
}

我知道有很多方法可以解决这个问题,但是,再次,为了我的问题

裸露这个解决方案:

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

/* fgets adds an unwanted '\n' at the end, so I made
 * a special function to read from stdin that removes
 * that '\n'.
 */
int read(char *str, int size) {
    // fgets adds an unwanted '\n' at the end, so we remove it
    fgets(str, size, stdin);

    int length = strlen(str);
    str[length - 1] = '\0';

    return length;
}

/* A function that breaks a string into words, indexes them
 * and prints them out, all done dynamically with malloc.
 */
void str_index(char *str) {
    char **index, *ptr;
    int i = 0, number_of_words;

    index = malloc(sizeof(char *));

    ptr = strtok(str, " ");
    for(i = 0; ptr != NULL; i++) {
        index = realloc(index, (i + 1) * sizeof(char *));
        index[i] = malloc(50 * sizeof(char));
        strcpy(index[i], ptr);
        ptr = strtok(NULL, " ");
    }
    number_of_words = i;

    for(i = 0; i < number_of_words; i++) {
        printf("%s\n", index[i]);
    }

    return;
}

int main() {
    char str[250];
    read(str, 250);
    str_index(str);

return 0;

}

质询

  1. 我在哪里必须释放我在str_index中动态分配的数组?
  2. 我们是否必须在函数str_index中释放它们? 如果是这样,为什么? 我所知道的是,当一个函数完成后,执行所有局部变量都会被销毁。
  3. 为什么我们必须将它们释放出来? 主要不是函数,因此在完成执行后,该函数中定义的所有变量都将被销毁。

我在哪里必须释放我在str_index中动态分配的数组?

就在return;之前return; 函数str_index语句。

我们是否必须在函数str_index中释放它们?

不必要。 取决于计划要求。

我所知道的是,当一个函数完成后,执行所有局部变量都会被销毁。

是的,对于在堆栈上分配的空间(如果变量不是static ),它是真的,但对于堆上分配的空间则不行。

为什么我们必须将它们释放出来?

没必要,它必须在main free 取决于计划要求。

我猜你在做大学课程。 (在我看来)大学课程的问题是,他们从教授高级语言开始,一切都是神奇地完成,然后教你低级语言。 如果我统治世界,每个人都会从汇编程序开始,然后是C,然后被允许“进步”到Java等。

对于你的问题,你遇到的问题是“事情可能会神奇地完成”。 C根本没有神奇的做法。 特别是,如果你使用malloc()calloc()任何东西,或者使用使用堆分配器的东西(例如strdup() )分配任何东西,你有责任释放它。 你需要明确地做到这一点。 如果不这样做,您将有内存泄漏。 因此,第一顺序问题是“如果我分配它,我必须确保它被释放”。 第二个问题是'如果我使用了一个可能已经分配了东西的库,我需要弄清楚如何确保它知道我已经完成了,所以它可以释放东西'。 如果你牢记这一点,你的C编程生活将会很快乐,而valgrind将成为你的朋友。

我们现在考虑你的问题:

  1. 你问你应该在哪里释放动态分配的内存。 从技术上讲,在这个例子中,您不需要,因为退出程序将释放堆上的所有内存。 但是,假设您想要重复使用此功能。 您希望在不再使用它时立即释放分配。 在提供的示例中,这将在return之前立即生效。 如果你有其他退出功能,那么请确保在每次return之前释放你的分配。 一个有用的错误处理提示是通过相同的代码退出,每当free()分配时,也将指向分配的指针设置为NULL 在进入时,也将指针初始化为NULL 然后在退出时( goto的有效使用),你可以简单地检查指针是否为NULL ,如果它不是null,则free()它。 (事实上​​,一旦你变得很自大,你就会知道大多数平台上的NULL上的free()是无操作的,所以你可以无条件地释放它)。 将指针设置为NULL位是为了避免双重释放。

  2. 这是堆栈和堆之间的区别。 局部变量在堆栈上分配。 当函数返回时,C会自动销毁它们。 这是魔术C的少数几点之一。 请注意,我说它会破坏变量,而不是它们指向的东西。 因此,如果你有一个指向本地变量中已分配(堆)内存的指针,并且函数返回,它将“释放”变量(在某种意义上它将不再在堆栈中),但是分配的(堆)内存不会被释放。 这就是为什么你必须释放只在函数中引用的堆分配内存,然后通过退出函数来销毁它的指针 - 参见上面的答案1。

  3. 在示例中,您不需要在main()中释放任何内容。 如果您已经编写了函数来返回指向堆上内存的指针(例如,如果您编写了等效的strdup() ),那么main()函数将需要free() 这就提出了一个重要的观点,即调用者对free()需求取决于被调用函数的设计方式。 因此,被调用的函数在文档中显而易见是非常重要的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM