2014-01-14 107 views
0

我处于一种两难的境地,因此,首先我想道歉,如果下一个问题会更不雅观,或者之前曾询问过(我无法找到那些答案虽然)。免费动态分配阵列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. 为什么我们必须将它们释放出来?并不是主要功能,因此在完成执行后,该功能中定义的所有变量都将被销毁。

回答

1

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

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

现在考虑您的问题:

  1. 你问,你应该释放你动态分配的内存。从技术上讲,在这个例子中,你不需要,因为退出你的程序将释放堆中的所有内存。不过,我们假设您要重复使用此功能。只要您不再使用它,您就想立即释放该分配。在提供的示例中,这将紧接在return之前。如果您有其他功能退出,请确保您在每个return之前免除您的分配。一个有用的错误处理提示是通过相同的代码退出,并且无论您何时分配,还将指针分配给NULL。在输入时,还要初始化指向NULL的指针。然后在退出时(有效使用goto),你可以简单地检查指针对NULL,如果它不为空,则为free()。 (实际上,一旦你变得非常自大,你就会知道free()在大多数平台上是NULL是无操作的,所以你可以无条件释放它)。将指针设置为NULL位是为了避免双倍空闲。

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

  3. 在你的例子中,你不需要释放任何东西在main()。如果你已经编写了函数来返回一个指向堆上的内存的指针(例如,如果你编码的代码等于strdup()),那么你的main()函数将需要free()那个。这引出了重要的一点,即调用者需要的内容取决于被调用函数的设计方式。被调用的函数在文档中很明显是非常重要的。

1

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

就在您的功能str_indexreturn;声明之前。

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

没有必要。取决于计划要求。

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

是的,对于在堆栈上分配的空间(如果变量不是static),但对堆中分配的空间不是这样。

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

没有必要它必须freemain。取决于计划要求。

+0

你是什么意思,按程序要求? –

+0

如果您从函数返回指针,则不应该在该函数中释放此指针。你应该在'main'中释放这个指针。如果函数没有返回指针,那么它应该在该函数中被释放。 – haccks