【原创】【基础】一文搞懂严蔚敏数据结构SqList &L和SqList L、ElemType &e和ElemType e
旁白
最近小渔夫在看严蔚敏、李冬梅《数据结构 c语言版》(第2版),学到第二章顺序表的实现时,看到函数参数一会是SqList &L、一会又是SqList L、一会ElemType &e、一会又ElemType e,当场大写的黑人问号加感叹号。这都什么玩意,一会有&一会又没有,都代表什么意思呢?
于是带着这些问号去找答案,上网上看了很多,看到的比较零散,于是我整理了一下,理清原因后,心想估计也有同学跟我一样的黑人问号,于是就有着这篇文章,希望能有点帮助吧。
先说答案
严书里的代码是伪代码,什么是伪代码?顾名思义不是真的代码,拿到电脑上去跑不起来的代码,伪代码重点是表达思路、表达想法的。
所以,书里函数参数中有&,想表达的意思是:希望通过函数改变该参数的值。可以看到书里在新建顺序表、插入一个数据、删除数据等改变顺序表的操作时用到了SqList &L,因为这些操作会改变表的内容;在查找操作时,没有改变表,顺序表前没有&,用到了SqList L;在取值时用到了ElemType &e,是想把取到的值通过参数返回。
在C语言里只能通过指针实现。书里写的是伪代码,而不是真正的C代码;在C++里可以通过指针和引用(C语言无引用)实现。
有些同学可能不太理解怎么通过函数改变传进来参数的值,下面详细介绍一个例子就明白了。
详细介绍
例子是用c语言的指针实现的,说起指针不得不提两个符号*与&,那先来看指针中的*与&。
C语言指针中的*与&
首先,一般看一个变量,看它的3点。变量名称、数据、地址。如定义一个变量int a = 5,变量名是a,值是5,在内存中的地址是0x00001111。

了解了变量,就可以了解指针了,指针可以理解成内存里的地址,指针变量就是存储地址的变量。
&是取地址运算符,用于取变量地址;例如:int a = 5, &a表示变量a的地址0x00001111。
*出现在不同的地方含义不同,但就我现在理解的,一般出现在两个地方:
- 函数参数中和变量定义中,表示定义一个指针变量。如
int *p ,int *p = &a. - 等号右边,
*(地址)表示取值运算。如int a = 5; int *p = &a; *p,中变量啊的值为5,指针变量p的值为0x00001111,*p的值为5。
例子:交换两变量的值
了解了指针后,来看下这个例子。例子中写了两个函数,来交换两变量的值,第一个函数swap1没用指针,第二个函数swap2用了指针。结果你猜,哪个函数能改变传进来参数的值?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int num1 = 1;
int num2 = 2;
swap1(num1, num2);
printf("num1 = %d, num2 = %d\n", num1, num2);
swap2(&num1, &num2);
printf("num1 = %d, num2 = %d\n", num1, num2);
// test();
return 0;
}
void swap1(int a, int b) {
int temp;
temp = a;
a = b;
b = temp;
}
void swap2(int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}
如图:运行一下,得到结果。第二个函数起作用了,也就是用了指针的函数能改变传进来参数的值,实现交换两变量的效果。这就是通过函数改变传进来参数的值。

到这里,已经得到答案了。
至于,为什么第一个函数没有实现交换,有兴趣的再往下看看。
单步调试一下,我发现了其中的奥妙。
调试开始,如下图,变量num1值为1,地址为0x62fe1c,变量num2值为2,地址为0x62fe18。

往下走,开始调用函数,进到函数swap1里。如图,变量num1和num2没什么变化。参数a和b已经接收到传进来的参数了。同时发现num1、num2的 地址和a、b不一样,原来函数会把形式参数当作局部变量,然后在栈中开辟内存空间,用于存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。

再往下走,走完发现了惊喜,与上图相比a和b互换了。而变量num1和num2和还是没什么变化。

最后,函数swap1执行结束,输出结果num1 = 1, num2 = 2。可以发现虽然变量交换了,但是只是交换了副本(替身)。至于为什么用了指针就可以交换真身呢?感兴趣,动动小手去探索探索吧,哈哈哈。

附录
1. *p和**p的区别
int *p 是一级指针,存放的是一个变量的地址。
int **p是二级指针,存放的是指针变量的地址。
例子:
//定义整形变量
int a = 6;
//定义一个指针指向这个变量
int *p = &a;
//定义一个二级指针指向p指针
int **pp = &p;
// 那么取出6的方式都有哪些呢?
printf("a=%d", a);
printf("a=%d", *p);
printf("a=%d", **pp);
以上3行输出的值都是6 。
2. *&p和&*p的区别
根据单目运算符运算的优先级,*&p 等价于*(&p)。&*p 等价于&(*p)。
如果
p是指针变量,那么*&p = p,&*p = p,都等于p,但还没定义p指向哪,存的是谁的地址。如果
p是一个int变量,那么*&p = p;而&*p是非法的,因为*p非法。
比如int p =10;那么*&p = *(&p) = p = 10(即从p的地址取值),而&*p = &(*p) 则非法,因为p=10,*10是取内存地址为10的值,这在c语言中是不合法的。
后续
我在学习中发现,c只能通过指针实现这种方式,而C++不仅能通过指针实现,还能通过引用实现。并且C++还提倡使用引用。本来想继续写写,什么是C++引用,为什么C++引进这个概念,这个概念有什么好处、C++指针参数和引用参数有什么区别的。但发现跟主题好像离得有点远,扯到C++去了,作罢。看看后面有机会用C++实现算法的时候再行补上。
才疏学浅,如有不当,请批评指正。
你的支持也是我的动力,最后笔记对你有用,别忘了点赞支持下哦。
【原创】【基础】一文搞懂严蔚敏数据结构SqList &L和SqList L、ElemType &e和ElemType e的更多相关文章
- Java基础-一文搞懂位运算
在日常的Java开发中,位运算使用的不多,使用的更多的是算数运算(+.-.*./.%).关系运算(<.>.<=.>=.==.!=)和逻辑运算(&&.||.!), ...
- Java 基础 一文搞懂泛型
本文将从以下四个方面来系统的讲解一下泛型,基本上涵盖了泛型的主体内容. 什么是泛型? 为什么要使用泛型? 如何使用泛型? 泛型的特性 1. 什么是泛型? 泛型的英文是Generics,是指在定义方法. ...
- 基础篇|一文搞懂RNN(循环神经网络)
基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...
- Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!
本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...
- 三文搞懂学会Docker容器技术(下)
接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...
- 一文搞懂所有Java集合面试题
Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...
- 一文搞懂如何使用Node.js进行TCP网络通信
摘要: 网络是通信互联的基础,Node.js提供了net.http.dgram等模块,分别用来实现TCP.HTTP.UDP的通信,本文主要对使用Node.js的TCP通信部份进行实践记录. 本文分享自 ...
- 一文搞懂指标采集利器 Telegraf
作者| 姜闻名 来源|尔达 Erda 公众号 导读:为了让大家更好的了解 MSP 中 APM 系统的设计实现,我们决定编写一个<详聊微服务观测>系列文章,深入 APM 系统的产品.架构 ...
- 一文搞懂Google Navigation Component
一文搞懂Google Navigation Component 应用中的页面跳转是一个常规任务, Google官方提供的解决方案是Android Jetpack的Navigation componen ...
随机推荐
- vue中v-model的学习
v-model在表单元素input.radio.checkBox.textarea创建双向数据绑定,他会根据类型选取正确的方法来更新元素,本质不过是语法糖,负责监听用户的输入操作以更新数据并对一些极端 ...
- ElementUI使用总结
首先声明,我这总结的官网都有,只是将自己使用时遇到的问题,重新记录一下,官网地址:https://element.eleme.cn/ 1.表格内指定行数给定不同样式(类似于隔行变色,也能叫指定行数不同 ...
- Hive实现自增序列及常见的Hive元数据问题处理
Hive实现自增序列 在利用数据仓库进行数据处理时,通常有这样一个业务场景,为一个Hive表新增一列自增字段(比如事实表和维度表之间的"代理主键").虽然Hive不像RDBMS如m ...
- 后端程序员之路 40、Pthreads
POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准.线程这个东西在操作系统原理里讲得比较清楚了,再加上对windows那一套进程线程的东西比较清楚,所以这里还是 ...
- 使用Prometheus搞定微服务监控
最近对服务进行监控,而当前监控最流行的数据库就是 Prometheus,同时 go-zero 默认接入也是这款数据库.今天就对 go-zero 是如何接入 Prometheus ,以及开发者如何自己定 ...
- 解决tui-editor布局错误失效问题(Vue-Element-Admin)
更新:突然想起来会不会是兼容或者版本问题? 使用tui-editor遇到markdown预览样式错误,也不清楚是不是版本的问题,改了下源码之后效果正常了 打开控制台看到几个类名不对劲,te-edito ...
- let、const、var区别?
let.const.var区别? let和const不存在变量提升(没有预解析,var有预解析). let和const在同一作用域范围内不能重复定义变量.(var可以). let和const有严格的作 ...
- 在ASP.NET Core中用HttpClient(二)——发送POST, PUT和DELETE请求
在上一篇文章中,我们已经学习了如何在ASP.NET Core中使用HttpClient从Web API获取数据.此外,我们还学习了如何使用GetAsync方法和HttpRequestMessage类发 ...
- 基于ABP框架的SignalR,使用Winform程序进行功能测试
在ABP框架里面,默认会带入SignalR消息处理技术,它同时也是ABP框架里面实时消息处理.事件/通知处理的一个实现方式,SignalR消息处理本身就是一个实时很好的处理方案,我在之前在我的Winf ...
- (数据科学学习手札111)geopandas 0.9.0重要新特性一览
本文示例文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 就在几天前,geopandas释放了其最新正式版 ...