C语言零碎知识点之数据结构中的 *&
Posted 二木成林
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言零碎知识点之数据结构中的 *&相关的知识,希望对你有一定的参考价值。
在数据结构中我们经常能够看到 *&
在函数的形参中,但却有些难以明白它的含义。因为那些代码都是伪代码,不是某一类编程语言的代码,通常是 C 和 C++ 的混用。
而 *&
是 C++ 中才能使用的,被称之为”引用“。如果使用的是纯 C 编译器,那么很可能无法通过编译。
由于我并不会 C++ 语言,所以下面只是说一下对它使用的理解,并且在数据结构的解题中尽量避免去使用到它。
注:下面代码经过 Dev-C++ 5.11 版本验证。
举例说明,我最开始想创建一个链表,代码如下:
#include <stdio.h>
#include <malloc.h>
typedef struct LNode
int data;
struct LNode *next;
LNode;
/**
* 使用头插法创建单链表
* @param list 单链表
* @param nums 待插入的数据数组
* @param n 数组长度
*/
void createByHead(LNode *list, int nums[], int n)
// 创建链表的头节点
list = (LNode *) malloc(sizeof(LNode));
list->next = NULL;
// 循环数组 nums 中所有数据
for (int i = 0; i < n; i++)
// 创建新节点并指定数据域和指针域
LNode *newNode = (LNode *) malloc(sizeof(LNode));
newNode->data = nums[i];
newNode->next = NULL;
// 将新节点插入到链表的头部,但是在头结点的后面
LNode *temp = list->next;
newNode->next = temp;
list->next = newNode;
/**
* 打印单链表中的所有节点
* @param list 单链表
*/
void print(LNode list)
printf("[");
// 链表的第一个节点
LNode *node = list.next;
// 循环单链表所有节点,打印值
while (node != NULL)
printf("%d", node->data);
if (node->next != NULL)
printf(", ");
node = node->next;
printf("]\\n");
int main()
LNode *list;
int nums[] = 111, 222, 333, 444, 555;
int n = 5;
createByHead(list, nums, n);
print(*list);
但运行不会打印任何结果,尽管我传递了一个指针变量。事实上我对指针的理解还是不够深刻。
上面的代码可能有些多了,看看简化后的情况,即我想要在函数 fun
内修改传入的形参 a 的值,并且在函数外也能访问到:
#include <stdio.h>
#include <malloc.h>
void fun(int *a)
a = (int *) malloc(sizeof(int));
int b = 3;
a = &b;
printf("fun->a: %d\\n", *a);
int main()
int *a;
fun(a);
printf("main->a: %d\\n", *a);
代码指向结果如下:
fun->a: 3
--------------------------------
Process exited after 3.191 seconds with return value 3221225477
请按任意键继续. . .
即在函数 fun
外并不能访问到在函数 fun
内被修改的 a,即使它是一个指针变量。
事实上再次证明了我对 C 语言指针的认知浅薄。
如果我们把形参 int *a
变成 int *&a
呢?那么代码如下:
#include <stdio.h>
#include <malloc.h>
void fun(int *&a)
a = (int *) malloc(sizeof(int));
int b = 3;
a = &b;
printf("fun->a: %d\\n", *a);
int main()
int *a;
fun(a);
printf("main->a: %d\\n", *a);
代码执行结果如下:
fun->a: 3
main->a: 3
--------------------------------
Process exited after 1.911 seconds with return value 0
请按任意键继续. . .
我们仅仅在为形参的指针变量添加一个 &
符号就发生了改变。
其实在函数内形参int* a
和int a
区别不大,不过是整型指针类型的变量int*
和普通整型类型的变量int
的区别,都传递的是值。在函数内对它们的值做修改,都无法影响到函数外。
而 int *&a
传递的是整型指针类型变量 a 的地址值,在函数内直接对地址所表示的变量进行修改,那么无论是函数内还是函数外都会被影响到。
如果仅仅是使用 C 语言,那么也可以在形参和实参中传递指针变量的地址,但修改有点多:
#include <stdio.h>
#include <malloc.h>
void fun(int **a)
*a = (int *) malloc(sizeof(int));
int b = 3;
*a = &b;
printf("fun->a: %d\\n", **a);
int main()
int *a;
fun(&a);
printf("main->a: %d\\n", *a);
即在函数 fun
内 **a
接收的是就是 main
函数内实参指针变量 *a
的地址,通过 &
操作符取得指针变量的地址;而在函数 fun
内 *a
就表示一个指针变量,对这个指针变量的修改无论是函数内还是函数外都会被影响到。
将函数的实参改为普通变量,而形参继续是指针变量也可以实现同样的效果,但注意在函数内指针变量修改值的方式(这样 a = &b;
赋值是行不通的)。
#include <stdio.h>
void fun(int *a)
// 这里就不需要再为它动态分配内存空间了
// a = (int *) malloc(sizeof(int));
int b = 3;
*a = b;// 修改指针变量的值
printf("fun->a: %d\\n", *a);
int main()
// 声明一个普通变量,而非指针变量
int a;
fun(&a);// 因为函数的形参还是指针变量,所以这里要传递普通变量的地址,使用&取址符
printf("main->a: %d\\n", a);
那么同样的道理,要想在函数内修改单链表成功,并且在其他函数也可以访问,就可以使用 *&
。仅仅只需要改动形参,而不需要改动其他任何地方的代码。但注意这是 C++ 的语法,一般的 C 编译器是不支持的,但在解数据结构题目时为了省事可以考虑使用。
#include <stdio.h>
#include <malloc.h>
typedef struct LNode
int data;
struct LNode *next;
LNode;
/**
* 使用头插法创建单链表
* @param list 单链表
* @param nums 待插入的数据数组
* @param n 数组长度
*/
void createByHead(LNode *&list, int nums[], int n)
// 创建链表的头节点
list = (LNode *) malloc(sizeof(LNode));
list->next = NULL;
// 循环数组 nums 中所有数据
for (int i = 0; i < n; i++)
// 创建新节点并指定数据域和指针域
LNode *newNode = (LNode *) malloc(sizeof(LNode));
newNode->data = nums[i];
newNode->next = NULL;
// 将新节点插入到链表的头部,但是在头结点的后面
LNode *temp = list->next;
newNode->next = temp;
list->next = newNode;
/**
* 打印单链表中的所有节点
* @param list 单链表
*/
void print(LNode list)
printf("[");
// 链表的第一个节点
LNode *node = list.next;
// 循环单链表所有节点,打印值
while (node != NULL)
printf("%d", node->data);
if (node->next != NULL)
printf(", ");
node = node->next;
printf("]\\n");
int main()
LNode *list;
int nums[] = 111, 222, 333, 444, 555;
int n = 5;
createByHead(list, nums, n);
print(*list);
还能使用指向指针的指针,但修改涉及的代码就比较多了。实参、形参及在函数中使用了形参的代码都需要改变:
#include <stdio.h>
#include <malloc.h>
typedef struct LNode
int data;
struct LNode *next;
LNode;
/**
* 使用头插法创建单链表
* @param list 单链表
* @param nums 待插入的数据数组
* @param n 数组长度
*/
void createByHead(LNode **list, int nums[], int n)
// 创建链表的头节点
*list = (LNode *) malloc(sizeof(LNode));
(*list)->next = NULL;
// 循环数组 nums 中所有数据
for (int i = 0; i < n; i++)
// 创建新节点并指定数据域和指针域
LNode *newNode = (LNode *) malloc(sizeof(LNode));
newNode->data = nums[i];
newNode->next = NULL;
// 将新节点插入到链表的头部,但是在头结点的后面
LNode *temp = (*list)->next;
newNode->next = temp;
(*list)->next = newNode;
/**
* 打印单链表中的所有节点
* @param list 单链表
*/
void print(LNode list)
printf("[");
// 链表的第一个节点
LNode *node = list.next;
// 循环单链表所有节点,打印值
while (node != NULL)
printf("%d", node->data);
if (node->next != NULL)
printf(", ");
node = node->next;
printf("]\\n");
int main()
LNode *list;
int nums[] = 111, 222, 333, 444, 555;
int n = 5;
createByHead(&list, nums, n);
print(*list);
如果只是返回一个单链表,我们可以将创建成功的链表作为函数返回值返回,然后在主函数接收就可以,避免了它作为实参和形参的变化:
#include <stdio.h>
#include <malloc.h>
typedef struct LNode
int data;
struct LNode *next;
LNode;
/**
* 使用头插法创建单链表
* @param list 单链表
* @param nums 待插入的数据数组
* @param n 数组长度
*/
LNode *createByHead(int nums[], int n)
// 创建链表的头节点
LNode *list = (LNode *) malloc(sizeof(LNode));
list->next = NULL;
// 循环数组 nums 中所有数据
for (int i = 0; i < n; i++)
// 创建新节点并指定数据域和指针域
LNode *newNode = (LNode *) malloc(sizeof(LNode));
newNode->data = nums[i];
newNode->next = NULL;
// 将新节点插入到链表的头部,但是在头结点的后面
LNode *temp = list->next;
newNode->next = temp;
list->next = newNode;
// 将链表返回
return list;
/**
* 打印单链表中的所有节点
* @param list 单链表
*/
void print(LNode list)
printf("[");
// 链表的第一个节点
LNode *node = list.next;
// 循环单链表所有节点,打印值
while (node != NULL)
printf("%d", node->data);
if (node->next != NULL)
printf(", ");
node = node->next;
printf("]\\n");
int main()
LNode *list;
int nums[] = 111, 222, 333, 444, 555;
int n = 5;
list = createByHead(nums, n);
print(*list);
其实还可以考虑实参用普通变量,实参用指针变量,也能达到同样的效果:
#include <stdio.h>
#include <malloc.h>
typedef struct LNode
int data;
struct LNode *next;
LNode;
/**
* 使用头插法创建单链表
* @param list 单链表
* @param nums 待插入的数据数组
* @param n 数组长度
*/
void createByHead(LNode *list, int nums[], int n)
// list就是链表的头节点,不需要再分配内存空间了,但需要把next指针指向NULL
list->next = NULL;
// 循环数组 nums 中所有数据
for (int i = 0; i < n; i++)
// 创建新节点并指定数据域和指针域
LNode *newNode = (LNode *) malloc(sizeof(LNode));
newNode->data = nums[i];
newNode->next = NULL;
// 将新节点插入到链表的头部,但是在头结点的后面
LNode *temp = list->next;
newNode->next = temp;
list->next = newNode;
/**
* 打印单链表中的所有节点
* @param list 单链表
*/
void print(LNode list)
printf("[");
// 链表的第一个节点
LNode *node = list.next;
// 循环单链表所有节点,打印值
while (node != NULL)
printf("%d", node->data);
if (node->next != NULL)
printf(", ");
node = node->next;
printf("]\\n");
int main()
LNode list;
int nums[] = 111, 222, 333, 444, 555;
int n = 5;
createByHead(&list, nums, n);
print(list);
总结:
- 所谓
*&
就是传递一个引用进去,让你可以在函数内做的修改影响到函数外。 - 通常
*&
出现在一些关于数据结构中的书籍中,作为伪代码展示。 - 通常
*&
用来修改链表、栈、树等书籍结构。 - 除了
*&
之外,还可以考虑使用其他的方式也能实现同样的效果,不必过分纠结。 - 变量在使用之前,普通变量可以不初始化。但指针变量必须初始化并且普通类型的指针变量可以通过
&
取址符进行赋值,而结构体指针变量则需要通过malloc
函数动态分配空间然后再赋值。
以上是关于C语言零碎知识点之数据结构中的 *&的主要内容,如果未能解决你的问题,请参考以下文章