我处于一种两难的境地,因此,首先我要道歉,如果下一个问题会更加荒谬,或者之前是否被问过(我找不到那些问题的答案) )。
无论如何,我会以一个任务为例来解释它(这不是作业,只是为了我的问题)。在这里:
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;
}
问题
答案 0 :(得分:1)
我在哪里必须释放我在str_index中动态分配的数组?
在函数return;
的{{1}}语句之前。
我们是否必须在函数str_index中释放它们?
没必要。取决于计划要求。
我所知道的是,当一个函数完成后,执行所有局部变量都会被销毁。
是的,对于在堆栈上分配的空间(如果变量不是str_index
),情况确实如此,但对于堆上分配的空间则不行。
为什么我们必须将它们释放出来?
static
中不必free
。取决于计划要求。
答案 1 :(得分:1)
我猜你在做大学课程。 (在我看来)大学课程的问题在于,他们从教授高级语言开始,一切都神奇地完成,然后教你低级语言。如果我统治世界,每个人都会从汇编程序开始,然后是C,然后被允许“进展”到Java等。
对于你的问题,你遇到的问题是假设“事情可能会神奇地完成”。 C根本没有神奇的做法。特别是,如果你malloc()
或calloc()
任何东西,或使用堆分配器(例如strdup()
)的东西分配任何东西,你有责任释放它。你需要明确地做到这一点。如果不这样做,您将有内存泄漏。因此,第一顺序问题是“如果我分配它,我必须确保它被释放”。第二个问题是'如果我使用了一个可能已经分配了东西的库,我需要弄清楚如何确保它知道我已经完成了,所以它可以释放东西'。如果你牢记这一点,你的C编程生活将会很开心,valgrind
将是你的朋友。
现在让我们考虑一下你的问题:
你问你应该在哪里释放动态分配的内存。从技术上讲,在这个例子中,您不需要,因为退出程序将释放堆上的所有内存。但是,假设您想要重复使用此功能。您希望在不再使用它时立即释放分配。在提供的示例中,这将紧接在return
之前。如果您有其他退出功能,请确保在每return
之前释放您的分配。一个有用的错误处理提示是通过相同的代码退出,每当你free()
分配时,也将指针设置为NULL
的分配。在输入时,也将指针初始化为NULL
。然后在退出时(有效使用goto
),您可以简单地检查针对NULL
的指针,如果它不为空,则free()
。 (事实上,一旦你变得很自大,你就会知道free()
NULL
在大多数平台上都是无操作的,所以你可以无条件地释放它。将指针设置为NULL
位是为了避免双重释放。
这是堆栈和堆之间的区别。局部变量在堆栈上分配。当函数返回时,C会自动销毁它们。这是魔术C的少数几点之一。请注意,我说它会破坏变量,而不是它们指向的东西。所以,如果你在一个局部变量的指针分配(堆)内存,函数返回时,它会“免费”的变量(在这个意义上,将不再是在栈上),但分配(堆)内存不会被释放。这就是为什么你必须释放只在函数中引用的堆分配内存,然后通过退出函数来销毁它的指针 - 参见上面1的答案。
您的示例中main()
不需要释放任何内容。如果您已将函数编码为返回指向堆内存的指针(例如,如果您编写了等效的strdup()
),那么您的main()
函数将需要free()
。这就提出了一个重要的观点,即调用者对free()
的需求取决于被调用函数的设计方式。因此,被调用的函数在文档中显而易见是非常重要的。