二维指针操作链表
背景
Linus slashdot: https://meta.slashdot.org/story/12/10/11/0030249
Linus大婶在slashdot上回答一些编程爱好者的提问,其中一个人问他什么样的代码是他所喜好的,大婶表述了自己一些观点之后,举了一个指针的例子,解释了什么才是core low-level coding。
下面是Linus的教学原文及翻译——
“At the opposite end of the spectrum, I actually wish more people understood the really core low-level kind of coding. Not big, complex stuff like the lockless name lookup, but simply good use of pointers-to-pointers etc. For example, I’ve seen too many people who delete a singly-linked list entry by keeping track of the “prev” entry, and then to delete the entry, doing something like。(在这段话的最后,我实际上希望更多的人了解什么是真正的核心底层代码。这并不像无锁文件名查询(注:可能是git源码里的设计)那样庞大、复杂,只是仅仅像诸如使用二级指针那样简单的技术。例如,我见过很多人在删除一个单项链表的时候,维护了一个”prev”表项指针,然后删除当前表项,就像这样)”
if (prev)prev->next = entry->next;elselist_head = entry->next;
and whenever I see code like that, I just go “This person doesn’t understand pointers”. And it’s sadly quite common.(当我看到这样的代码时,我就会想“这个人不了解指针”。令人难过的是这太常见了。
我尝试用二维指针操作链表,写了如下code。
希望领悟到二维指针的精髓。
#include <stdio.h>
#include <stdlib.h>typedef struct Node {struct Node *next;int data;
} node;void initList(node **head, unsigned int size)
{node **cur = head;for (int i=0; i<size; i++){*cur = (node *)malloc(sizeof(node));(*cur)->data = i;(*cur)->next = NULL;cur = &(*cur)->next; }
}void deleteList(node **head, int data)
{for (node **cur=head; *cur;){node *entry = *cur;if (entry->data == data){*cur = entry->next;free(entry);entry = NULL;}elsecur = &entry->next;}
}void freeList(node **head)
{for (node **cur=head; *cur;){node *entry = *cur;*cur = entry->next;free(entry);entry = NULL;}
}int main()
{node *head = NULL;unsigned int size = 5;initList(&head, 5);if (NULL == head){printf("head is null, init list failed");return -1;}else{printf("init list suc, addr is: \n");node *cur = head;while(NULL != cur){printf("%X ", cur);cur = cur->next;} }printf("\n\n");node *cur = head;printf("list data: \n");while(NULL != cur){printf("%d ", cur->data);cur = cur->next;}printf("\n\n");printf("delete node 3 from list\n\n");deleteList(&head, 3);cur = head;printf("list data: \n");while(NULL != cur){printf("%d ", cur->data);cur = cur->next;}printf("\n\n");printf("free list\n\n");freeList(&head);cur = head;printf("list data: \n"); while(NULL != cur){printf("%d ", cur->data);cur = cur->next;}printf("\n");return 0;
}
运行结果如下:
init list suc, addr is:
4B8260 4B8280 4B82A0 4B82C0 4B82E0
list data:
0 1 2 3 4
delete node 3 from list
list data:
0 1 2 4
free list
list data:
Q1: 如果我们用下面的initList_1来代替原来的initList,重新build,运行,你想想会发生什么?
list 能初始化成功吗?
void initList_1(node **head, unsigned int size)
{node **cur = head;for (int i=0; i<size; i++){node *entry = *cur;entry = (node *)malloc(sizeof(node));entry->data = i;entry->next = NULL;cur = &entry->next; }
}
A:list不能初始化成功,*head 并没有指向分配的内存,依然为NULL, entry 指向的内存并不能返回到函数外部。
Q2: 上面的freeList 函数是否把list中分配的内存在free后设置成了NULL,杜绝野指针?
void freeList(node **head)
{for (node **cur=head; *cur;){node *entry = *cur;*cur = entry->next;free(entry);entry = NULL; /* is this lie useful? avoid wild pointer ?*/}
}
A: No, 内存free后并没有被置为NULL.
其实在循环过程中,*head(也就是*cur) 一直在链表中后移,最后指向了最后一个node的next 指针,也就是为NULL。
所以在这个函数执行完后,list的首节点指向了NULL(最后一个node的next 指针),而其它的node所分配的内存虽然被free了,但是并没有设置为NULL。这样做也没有问题,list暴露给用户的就是head 指针,非head节点并没有提供给用户,没有置为NULL,也就没有什么问题了。
相关文章:

php多选框怎么传值,tp3.2如何处理多选框传参和判断状态
创建多选框:(1)普通的多选:123(2)在数据库中遍历出来的多选框,value和data-id都要赋值(大家都懂,我就不说啦):{$vo.title} 2.我是用jq做的异步,我是使用英文“,”分割字段存储的。我们的前端是自己封装过的,大家根据自…

UIWebView和UIActivityIndicatorView的结合使用
环境:Xcode6.1 UIWebView是iOS开发中常用的一个控件,是内置的浏览器控件,我们可以用它来浏览网页,加载文档等。这篇文件将结合UIActivityIndicatorView控件制作一个小实例(加载apple的官网)。效果如下: 一.建立一个Sin…

Python对象类型——字符串、列表、元组
字符串Python连接多个字符串可用“”号,但这个操作不如把所有子字符串放到一个列表或可迭代对象中,然后调用一个join方法来把所有内容连接在一起节约内存。原始字符串操作符(R/r):相当于取消“\”转义,在使…

leetcode--1:(python)Two Sum
2019.5.25: #1 Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice. Example: 我的解法࿱…

memset初始化内存
在suse 9,运行man memset 查看memset的解释如下: “NAME memset - fill memory with a constant byte SYNOPSIS #include <string.h> void *memset(void *s, int c, size_t n); DESCRIPTION The memset() function fills the fir…

php 数字变量,php入门变量之数字_PHP教程
在介绍变量时,我明确指出PHP具有整型和浮点型(小数)数字类型。但是,依据我的经验,这两种类型都可以归类到一般的数字之下(在极大程度上是这样的)。下面列举下PHP中有效的数字类型的变量:83.1410980843985-4.23985084.4e2注意&…

BZOJ 1597: [Usaco2008 Mar]土地购买( dp + 斜率优化 )
既然每块都要买, 那么一块土地被另一块包含就可以不考虑. 先按长排序, 去掉不考虑的土地, 剩下的土地长x递增, 宽y递减dp(v) min{ dp(p)xv*yp1 }假设dp(v)由i转移比由j转移优(i>j), 那么dp(i)xv*yi1 < dp(j)xv*yj1化简得 (dp(i) - dp(j))/(yi1-yj1) > -xv然后就斜率优…

雨季来临 对车辆涉水说“NO”
七月的上海开始进入暴雨频发的季节。在城市排水系统受到考验的同时,车主们的车辆也同样经受着雨水的考验。而每年都会有相当一部分车辆因为“水害”,使车辆自身的价值受到很大的影响。为此开新通过以下案例为大家做个分析。并推荐几个实用的技巧以备不时…

C#编写dll进行sql server数据库扩展储存过程
一、编写C#函数文件 1、新建一个类库文件 备注:sqlserver 2008只能用.net3.5版本。 2、如有想加入强命名的话可如下步骤: 参考博文:https://blog.csdn.net/donnie88888888/article/details/52743064 1、运行在“开始菜单”-“程序”-“Micros…

malloc(0)-malloc 0 字节
C17中有如下描述: 7.22.3 Memory management functions 1 The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds …

php常见排序算去,PHP兑现常见排序算法
PHP实现常见排序算法//插入排序(一维数组)function insert_sort($arr){$count count($arr);for($i1; $i$tmp $arr[$i];$j $i - 1;while($arr[$j] > $tmp){$arr[$j1] $arr[$j];$arr[$j] $tmp;$j--;}}return $arr;}//选择排序(一维数组)function select_sort($arr){$coun…

C#中 int.TryParse 的用法
int i -1;bool b int.TryParse(null, out i);执行完毕后,b等于false,i等于0,而不是等于-1,切记。 int i -1;bool b int.TryParse("123", out i); 执行完毕后,b等于true,i等于123;…

2022-2028年中国综艺节目市场深度调研及投资前景预测报告
【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新(交付时间约3个工作日) 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国综艺节目行业市场行业相关概述、中国综艺节目行业市场行业运行环境、分析了中国综艺节目行…

cocos2d-js 自定义事件监听派发
熟悉js的dom事件或者flash事件的,基本都能立马明白cc.eventManager的用法。 cc.eventManager有两种注册监听器的方式,一种是原生事件,例如 cc.eventManager.addListener({ event: cc.EventListener.KEYBOARD, onKeyReleased: function(keyCod…

URL编码转义,冒号和/不转,否则导致http链接失效
URL含有中文需要转义 参考 https://blog.csdn.net/benbenxiongyuan/article/details/10608095 自己写一个 1 public boolean checkURLFileIsExist(String stringURL){2 boolean isExist false;3 String sEncodeURL;4 5 try{6 // URL内中文…

C面向对象之透明指针的运用
不透明指针(opaque pointer)可以用来在C中实现封装。 什么是不透明指针(opaque pointer) 从字面意思来看,“不透明”意味着看不到内部,因此“不透明指针”即看不到内部定义的指针。这样说有些抽象,我们来看个例子: #include &l…

支付宝 php rsa算法,:PHP支付宝接口RSA验证
这两天一直困扰的PHP RSA签名验证问题终于解决了,由于之前RSA接触的不多,再加上官方至今还未有PHP的SDK可供参考,因此走了一些弯路,写在这里和大家分享。虽然支付宝官方还未提供相关SDK,PHP确实可以实现RSA方式的签名&…

int与string转换
参考: http://greatverve.cnblogs.com/archive/2012/10/24/cpp-int-string.html 转载于:https://www.cnblogs.com/predator-wang/p/4789775.html

更改Jenkins升级站点
更新地址:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json 【图示】:

Android 模仿微信启动动画(转)
本文内容 环境项目结构演示微信启动动画本文演示微信启动动画。请点击此处下载,自行调试。 顺便抱怨一下,实践性(与研究性质的相对)技术博的“七宗罪”: 第一宗罪,错字连篇,逻辑不清;…

navicat for mysql收藏夹
navicat for mysql如果库表非常多的化,每次输入表名比较繁琐。 可以进入收藏夹便于快速打开经常使用的库表。 打开要入收藏夹的表,文件-添加收藏夹。 也可以快捷键shiftctrl1 如果已经有3个占用了,则自动跳到第4个栏位 也可以快捷键shiftctrl…

C 变量的作用域
下面的程序输出什么?思考一下 #include <stdio.h>// Driver Code int main() {{int x 10, y 20;{// The outer block contains// declaration of x and// y, so following statement// is valid and prints// 10 and 20printf("x %d, y %d\n",…

oracle字段重复新增错误,oracle在已有重复数据的列上创建唯一约束
在有重复数据的列上添加unique constraints,大家正常的解决办法就修改重复数据,但也可以 保留重复数据,使约束对以后的数据有限制,不过我们还可以用以下的方法来添加唯一约束. SQL create table aa(num number(6),email varchar2(32)); 表已创建。 SQL insert在有重复数据的列上…

poj_3067 树状数组
题目大意 左右两个竖排,左边竖排有N个点,从上到下依次标记为1,2,...N; 右边竖排有M个点,从上到下依次标记为1,2....M。现在从K条直线分别连接左边一个点和右边一个点,求这K条直线的交点个数(左右竖排上的点不算做交点&…

2022-2028年中国自主可控行业深度调研及投资前景预测报告(全卷)
【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新(交付时间约3个工作日) 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国自主可控行业市场行业相关概述、中国自主可控行业市场行业运行环境、分析了中国自主可控行…

linux /etc/fstab文件参数求解释
2019独角兽企业重金招聘Python工程师标准>>> # cat /etc/fstab# # /etc/fstab # Created by anaconda on Mon Dec 17 09:06:53 2012 # # Accessible filesystems, by reference, are maintained under /dev/disk # See man pages fstab(5), findfs(8), mount(8) and…

C运算符优先级笔记
1. 指针数组 int *p[5]; [] 大于 * 2. 强制类型() 与 成员选择(./->) #include <stdlib.h>typedef struct {int data;int time; } data_t;int main() {data_t *p (data_t *)malloc(sizeof(data_t));int t (data_t *)p->time; /*focus: -> 大于 (data_t)*/f…

移动应用开发—— 如何搭建开发大型的应用架构?
什么是一个好的应用架构?怎么才能搭建大型的应用架构?其实每个人在工作几年之后都会有这个疑问,都在寻求好点的框架,那么小编我总结一下我的经验给大家。 其实对于客户端,一个好的应用架构,复杂度不亚于服务…

4104 oracle 数据文件名,Oracle 11g 常遇到ora-01034错误,这是为什么?
Errors in file d:\app\gerry\diag\rdbms\orcl\orcl\trace\orcl_psp0_5252.trc:ORA-27300: OS system dependent operation:CreateThread failed with status: 8ORA-27301: OS failure message: 存储空间不足,无法处理此命令。ORA-27302: failure occurred at: ssth…

Linux(CentOS6.5)中安装maven
Linux(CentOS6.5)中安装maven 1.上传相关包(*.tar.gz等) 使用相关软件上传或用Xshell连接后下载命令:yum install lrzsz 2.安装maven 1> 官网下载apache-maven-3.6.0-bin.tar.gz压缩包,上传到CentOS上(目录自选)。官网地址…