image-20220122030027428

一、引出问题

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;

typedef struct LNode {
  ElemType data;
  struct LNode *next;
} LNode, *LinkList;

bool InitList(LinkList L) {
  L = (LNode *)malloc(sizeof(LNode));
  L->data = 1;
}

int main(void) {

  LinkList L;
  InitList(L);
  printf("%d", L->data);//false
  return 0;
}

好久没碰C,于是想拿基本的数据结构来熟悉下代码。
上述代码想要实现的功能是调用InitList()函数,实现对链表的初始化,但经过调用后的printf()测试之后发现报错,一直没有意识到问题所在。经过大半个小时的研究和DeBug、和一哲交流良久,意识到了问题同时也有了今天的这篇博客,接下来进入正文部分。

二、指针和指针变量

一定要区分指针和指针变量,我发现我的问题就是太久没有碰C,对相关概念出现了模糊化。

1. 指针变量

指针变量,本质上是一个变量,他存放的是一个地址

int a = 2;
int *p = &a;

示例代码中,创建了一个int 类型的指针变量

2. 指针

指针通常被理解为地址的意思,我们说的创建一个int类型的指针,其实是创建了一个指针类型的变量。在这个地方容易引起歧义:什么时候指针这个词表示的是一个地址、什么时候又是一个指针变量

int a = 2;
int *p = &a;//p 是一个指向int类型的指针(变量)

3. 写出错误代码的原因

回到开头的问题,为什么调用InitList()函数,实现对链表的初始化,但经过调用后的printf()测试之后发现报错。

我定义这个函数的时候想着说传一个指针,我这里想传递的是一个地址,但实际上传递的是一个指针变量赋给这个形参。换句话说这里的形参是一个指针变量,而不是一个地址,我当时一直陷入这里是一个”地址“的误区。

bool InitList(LinkList L) {//传递的值是一个指针变量
  L = (LNode *)malloc(sizeof(LNode));
  L->data = 1;
}

所以我后续的malloc操作是针对形参的L进行的,我修改了L中存放的地址值,而L在函数调用结束后就出栈了,所以并没有影响实际值。这个说法其实不太严谨,但姑且这么理解。核心原因是因为日常交流时,混淆了指针和指针变量的意思。

三、解决方案

1. 用指针

代码想要实现的效果是创建并初始化链表,那么修改后的代码应该是这样的。

LinkList InitList(LinkList L) {
  L = (LNode *)malloc(sizeof(LNode));
  L->data = 1;
  if (L == NULL) {
    return NULL;
  }
  return L;
}

将L作为返回值,直接返回到主调函数,从而实现既定效果。

2. 用引用

bool InitList(LinkList &L) {

  L = (LNode *)malloc(sizeof(LNode));
  L->data = 1;
  if (L == NULL) {
    return false;
  }

  return true;
}

引用就能很好的解决这一问题,引用相当于变量的别名,可以直接对该变量进行数据的修改操作。

总结一下就是一定要区分指针和指针变量的区别,写代码之前想清楚。


永远相信美好的事情即将发生!

Yancey
2021.11.01 01:11


文章作者: Yancey
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yancey !
评论
  目录