动态列表中的Malloc函数

动态列表中的Malloc函数,c,list,dynamic,C,List,Dynamic,我刚开始学习动态列表,我不明白为什么在main()程序中声明第一个节点时也需要使用malloc函数,下面的代码应该只打印第一个节点中包含的数据,但是如果我不使用malloc函数初始化节点,它就无法工作: struct node{ int data; struct node* next; }; void insert(int val, struct node*); int main() { struct node* head ; head->data =

我刚开始学习动态列表,我不明白为什么在main()程序中声明第一个节点时也需要使用malloc函数,下面的代码应该只打印第一个节点中包含的数据,但是如果我不使用malloc函数初始化节点,它就无法工作:

 struct node{
    int data;
    struct node* next;
};

void insert(int val, struct node*);

int main() {
    struct node* head ;
    head->data = 2;
    printf("%d \n", head->data);

}

从技术上讲,您不需要这样做,但是使用相同的内存模式维护所有节点对您来说只是一个优势,没有实际的缺点

假设所有节点都存储在动态内存中

您的“insert”过程最好命名为“add”或(对于完整的功能上下文)“cons”,它应该返回新节点:

struct node* cons(int val, struct node* next)
{
  struct node* this = (struct node*)malloc( sizeof struct node );
  if (!this) return next;  // or some other error condition!
  this->data = val;
  this->next = next;
  return this;
}
创建列表现在非常简单:

int main()
{
  struct node* xs = cons( 2, cons( 3, cons( 5, cons( 7, NULL ) ) ) );
  // You now have a list of the first four prime numbers.
而且很容易处理它们

  // Let’s print them!
  {
    struct node* p = xs;
    while (p)
    {
      printf( "%d ", p->data );
      p = p->next;
    }
    printf( "\n" );
  }

  // Let’s get the length!
  int length = 0;
  {
    struct node* p = xs;
    while (p)
    {
      length += 1;
      p = p->next;
    }
  }
  printf( "xs is %d elements long.\n", length );
顺便说一下,在命名事物时,你应该尽量保持一致。您已将节点数据命名为“data”,但构造函数的参数将其称为“val”。你应该选一个并坚持下去

此外,常见的情况是:

typedef struct node node;
现在,除了在
struct node
的定义中,您可以在每个地方使用
node
这个词

哦,我差点忘了:别忘了用合适的析构函数来清理

node* destroy( node* root )
{
  if (!root) return NULL;
  destroy( root->next );
  free( root );
  return NULL;
}
以及
main()
的附录:


从技术上讲,您不需要这样做,但是使用相同的内存模式维护所有节点对您来说只是一个优势,没有实际的缺点

假设所有节点都存储在动态内存中

您的“insert”过程最好命名为“add”或(对于完整的功能上下文)“cons”,它应该返回新节点:

struct node* cons(int val, struct node* next)
{
  struct node* this = (struct node*)malloc( sizeof struct node );
  if (!this) return next;  // or some other error condition!
  this->data = val;
  this->next = next;
  return this;
}
创建列表现在非常简单:

int main()
{
  struct node* xs = cons( 2, cons( 3, cons( 5, cons( 7, NULL ) ) ) );
  // You now have a list of the first four prime numbers.
而且很容易处理它们

  // Let’s print them!
  {
    struct node* p = xs;
    while (p)
    {
      printf( "%d ", p->data );
      p = p->next;
    }
    printf( "\n" );
  }

  // Let’s get the length!
  int length = 0;
  {
    struct node* p = xs;
    while (p)
    {
      length += 1;
      p = p->next;
    }
  }
  printf( "xs is %d elements long.\n", length );
顺便说一下,在命名事物时,你应该尽量保持一致。您已将节点数据命名为“data”,但构造函数的参数将其称为“val”。你应该选一个并坚持下去

此外,常见的情况是:

typedef struct node node;
现在,除了在
struct node
的定义中,您可以在每个地方使用
node
这个词

哦,我差点忘了:别忘了用合适的析构函数来清理

node* destroy( node* root )
{
  if (!root) return NULL;
  destroy( root->next );
  free( root );
  return NULL;
}
以及
main()
的附录:


声明变量时,定义变量的类型,然后 名称,并可以选择声明其初始值

每种类型都需要特定数量的内存。例如,
int
将是 32位操作系统为32位,64位操作系统为8位

函数中声明的变量通常存储在相关的堆栈中 具有该功能。当函数返回时,该函数的堆栈为 不再可用,且变量不再存在

当您需要变量的值/对象即使在函数之后也存在时 返回,然后需要在程序的不同部分分配内存, 通常是堆。这正是
malloc
realloc
calloc
所做的

这完全是错误的。您已经声明了一个名为
head
的指针,其类型为
struct node
, 但你没有给它分配任何东西。因此,它指向一个未指明的目标 内存中的位置
head->data=2
尝试在未指定的位置存储值 位置和程序很可能会因segfault而崩溃

大体上,您可以这样做:

int main(void)
{
    struct node head;
    head.data = 2;
    printf("%d \n", head.data);
    return 0;
}
head
将保存在堆栈中,只要
main
没有保存,它就会一直存在 回来但这只是一个很小的例子。在一个复杂的程序中 拥有更多的变量、对象等。简单地声明所有 在
main
中需要的变量。因此,最好在创建对象时创建它们 这是需要的

例如,您可以有一个创建对象和另一个对象的函数 调用
create\u node
并使用该对象

struct node *create_node(int data)
{
    struct node *head = malloc(sizeof *head);
    if(head == NULL)
        return NULL; // no more memory left

    head->data = data;
    head->next = NULL;

    return head;
}

struct node *foo(void)
{
    struct node *head = create_node(112);

    // do somethig with head

    return head;
}
这里
create\u节点
使用malloc为一个
struct节点分配内存
对象,使用一些值初始化该对象,并返回指向该内存位置的指针。
foo
调用
create\u节点
并对其执行操作,然后返回 对象如果另一个函数调用
foo
,此函数将获取对象

malloc
还有其他原因。考虑这个代码:

void foo(void)
{
    int numbers[4] = { 1, 3, 5, 7 };

    ...
}
在这种情况下,您知道需要4个整数。但有时你需要一个 例如,仅在运行时知道元素数的数组 因为它依赖于一些用户输入。为此,您还可以使用
malloc

void foo(int size)
{
    int *numbers = malloc(size * sizeof *numbers);

    // now you have "size" elements
    ...
    free(numbers);   // freeing memory
}
使用
malloc
realloc
calloc
时,需要释放内存。如果 您的程序不再需要内存,您必须使用
free
(如 最后一个例子。请注意,为了简单起见,我省略了
带有
struct head的示例

声明变量时,定义变量的类型,然后 名称,并可以选择声明其初始值

每种类型都需要特定的内存量。例如
int
32位操作系统为32位,64位操作系统为8位

函数中声明的变量通常存储在相关的堆栈中 当函数返回时,该函数的堆栈 不再可用,且变量不再存在

当您需要变量的值/对象即使在函数之后也存在时 返回,然后需要在程序的不同部分分配内存, 通常是堆。这正是
malloc
realloc
calloc
所做的

是错误的。您声明了一个名为
head
的指针,其类型为
struct node
, 但是你没有给它赋值,所以它指向一个未指定的 内存中的位置。
head->data=2
尝试存储
int main() {
        int myInt;  // creates space for an actual int in automatic storage (most likely the stack)
        int* head = &myInt;  // now head points to a valid memory location, namely myInt
        *head = 2;  // now myInt == 2
        printf("%d\n", *head);  // prints 2

        return 0;
    }
int main() {
        int* head = malloc(sizeof int);  // silly to malloc a single int, but this is for illustration purposes
        if (head != NULL)
        {
            // space for an int was returned to us from the heap
            *head = 2; // now the unnamed int that head points to is 2
            printf("%d\n", *head);  // prints out 2
            // don't forget to clean up
            free(head);
        }
        else
        {
            // handle error, print error message, etc
        }

        return 0;
    }
int main() {
    struct node* head = calloc(1, sizeof(struct node));
    if (head) {
      head->data = 2;
      printf("%d \n", head->data);
      free(head);
    }
}
int main() {
    struct node head;
    head.data = 2;
    printf("%d \n", head.data);
}