在方法/函数内部分配局部变量

时间:2019-04-20 01:07:14

标签: c

我正在用C创建一个动态链接列表,这与Java中的类似。

我将元素/值包装在一个结构中,该结构具有下一个节点的值和地址。我不希望传递该结构本身的实例,因此我制作了一个方法,该方法接受该值并将该值添加到该结构中((您可以说此结构是抽象的,使用该方法的人不会知道方法中使用了一个结构),然后将该结构添加到列表中。

为了测试代码,我添加了5个不同的整数,并且在所有5个添加过程中,我在方法内部创建的结构都获得了相同的内存地址。

此代码使用gcc编译,并在ubuntu中进行了编写和测试。

struct node {

  void* value; // literal values can't be passed in here, only address can be passed
  struct node* next; // poninter to the next node

};

typedef struct {

  size_t size; // size of the linked list
  struct node* head; // head node of the list, always points to the first element in the list

} link_list; 


void link_list_add(link_list * list, struct node * ele) {

  // if size is zero, simply add the node to the list
  if(list->size==0) {
    list->head = ele;
    ele->next = NULL;
  }
  else {
  // add the new node to the front of the list and make in point towards what is being pointed by the list head
    ele->next = list->head;
    list->head = ele;
  }

  list->size++;

}

// does the same thing as the previous method, the only difference being that it takes the address of the element that needs to add and makes the wrapper node struct for it.
void link_list_add_ele(link_list * list, void * ele){

  struct node eleNode = {ele, NULL}; // this gives the same address every single time.
  link_list_add(list, eleNode);

}

3 个答案:

答案 0 :(得分:2)

函数返回后,像struct node eleNode = {ele, NULL};这样的堆栈内存将不再有效。函数返回后,内存将被重用。

要返回的比基本类型更简单的东西(例如浮点数,整数或指针),都需要使用malloc来分配堆内存。该内存将一直分配,直到被free d或程序退出为止。

将结构分配和释放放入DRY purposes的函数中并将其与其余代码隔离是一个好主意。虽然现在很简单,但是结构分配通常很复杂。

struct node *node_new {
    return malloc(sizeof(struct node));
}

void link_list_add_ele(link_list * list, void * ele){
    struct node *eleNode = node_new();
    eleNode->value = ele;
    eleNode->next = NULL;
    link_list_add(list, eleNode);
}

当您删除节点时,必须释放内存。

void node_free(struct node *node) {
    free(node);
}

答案 1 :(得分:1)

您一直在观察的是正确的。如果要使用超出此功能范围的链接列表,则应动态分配Linked List节点(即,使用malloccallocrealloc之类的函数)您创建了它。一旦不需要动态分配的内存,就需要释放它们。如果您不这样做,那么您将拥有memory leaks

  

为了测试代码,我添加了5个不同的整数,并且在所有5个添加过程中,我在方法内部创建的结构都获得了相同的内存地址。

这是因为您一直在Stack memory上分配节点,因此它具有automatic storage class(了解有关Storage Classes的更多信息)。当您退出函数link_list_add_ele时,分配给该节点的内存位置将被破坏。一旦包装函数返回,它就不再有效。

要点:

您将错误的参数传递给link_list_add。第二个参数是一个指针,但是您一直在向它传递一个值。

重要提示:

尝试了解编译器抛出的各种WarningsErrors。 在我的Linux中,我尝试使用各种详细的警告标志来编译我的代码。

gcc example.c -o example -Wall -Wextra -Wshadow

如果您使用的是IDE,那么会有一些设置选项可以启用警告。

我用gcc filename.c -Wall编译了您的代码,它给了我这个错误:

error: incompatible type for argument 2 of ‘link_list_add’
link_list_add(list, eleNode);
                   ^~~~~~~
note: expected ‘struct node *’ but argument is of type ‘struct node’
void link_list_add(link_list * list, struct node * ele) {

我已经编辑了删除Warnings的函数,并在heap上分配了内存:

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

void link_list_add_ele(link_list *list, void *ele)
{
    struct node *eleNode = malloc(sizeof(struct node)); // this gives the same address every single time.
    eleNode->value = ele;
    eleNode->next = NULL;
    link_list_add(list, eleNode);
}

您还需要包括头文件#include <stdlib.h>,并且不要忘记释放不需要的内存,因为C没有自动垃圾收集,因此,您可能会观察到内存如果您没有正确释放它们,则会泄漏。

答案 2 :(得分:1)

这定义了一个局部变量:

struct node eleNode = {ele, NULL}; // this gives the same address every single time.

在调用link_list_add_ele函数时进行分配,并在函数返回时释放。下次调用该函数时,它的内存可能会被重用。

您正在寻找的是动态内存分配(例如Java中的new

void link_list_add_ele(link_list * list, void * ele){

  struct node *eleNode = malloc(sizeof(struct node));
  eleNode->value = ele;
  eleNode->next = 0;
  link_list_add(list, eleNode);

}

但是请记住,由于C没有垃圾收集器,因此还需要通过调用free()显式释放这种内存。