利用头插法实例理解指针原理

1.理解指针

1.1 指针含义

利用头插法实例理解指针原理_第1张图片
需要特别注意的是我们在定义一个指针后需要先将该指针变量指向NULL,即定义一个空指针,这样做是为了防止定义指针后该指针指向一陌生区域,导致使用指针时出现错误
指针类型需要与指向空间内值的类型相同

#include 

int main() {
	int a;
	a = 3; 
	int *p=NULL; //定义一个int型指针变量,变量名为p
	p = &a; //将a的地址赋值给p,&为取地址符 
	//划分一块内存存放a的值,用变量名为这块内存命名,即可以通过变量名直接访问这块内存 
	printf("a的值为:%d\n", a);
	//输出a的值为:3 
	printf("a的地址为:%p\n", &a); //输出地址需要用%p占位符 
	//输出a的地址为:000000000062FE1C 
	printf("p的值为:%p\n", p);
	//输出p的值为:000000000062FE1C 
	printf("p的地址为:%p\n", &p);
	//输出p的地址为:000000000062FE10 
	return 0;
}

当我们定义一个指针变量后,我们可以将该指针变量理解为地址箱,箱内可存放不同的地址,但是箱内只能存一个地址,可以这样理解指针即地址

1.2 指针访问空间

"* "星号符为访问符,访问指针变量所指空间内的值

#include 

int main() {
	int a=1;
	int *p1=NULL,*p2=NULL;
	p1 = &a;
	printf("p1的值: %p\n", p1);
	//输出p1的值: 000000000062FE0C 
	//不同指针变量之间可以相互赋值 
	p2 = p1; //现在p2内存放的也是a的地址,即p2也指向a
	printf("p2的值:%p\n", p2);
	//输出p2的值:000000000062FE0C 
	//* 符号为访问符,如*p即为访问p指向的空间,其值为p指向空间内的值
	printf("a的值:%d\n", a);
	//输出a的值:1 
	printf("访问p1指向空间,空间内的值为: %d\n", *p1);
	//输出访问p1指向空间,空间内的值为: 1 
	return 0;
}

1.3 指针使用

当指针指向一个变量,改变指针即改变变量的值
一块内存被划分后,我们用变量名为其命名,然后我们不仅可以通过变量名访问这块内存,还可以通过地址访问;通俗易懂,我们不仅可以通过xx省xx县xx镇xx路xx号去找一个地方,还可以通过经度xx纬度xx来找这个地方,在这里,前者就是变量名,后者就是指针。所以可以这样理解,当指针指向一个地方时,指针实际上就是代表了这个地方,对指针进行操作,实际上就是对这个地方操作。

#include 

int main() {
	int a = 3;
	int *p = NULL;
	p = &a;
	*p = (*p) + 1;
	printf("%d\n", *p); //输出4
	printf("%d\n", a); //输出4 
	return 0;
}

2.理解malloc

(void *)malloc(unsigned int size)
1.该函数作用为在内存的动态存储区中分配一个长度为size的连续空间,此函数的返回值是一个指针(该指针类型与指向空间内值的类型相同),该指针指向该分配区域的起始地址,所以我们也可以理解为该函数会返回分配区域的起始地址
2.如果分配成功会返回指向分配区域的指针,若失败则会返回一个空指针
3.新的ANSIC标准规定该函数返回为void型指针,所以必要时要进行指针类型转换,如若想分配的空间内的值为int型,那么就需要(int *)malloc

3.结合头插法实例理解

3.1 定义单链表中结点类型

利用头插法实例理解指针原理_第2张图片

typedef struct LNode {
	ElemType data;
	struct LNode *next; //定义struct LNode指针型变量,变量名为next,指针指向下一个结点即指针内的值为下一结点的地址
}LNode, *LinkList;

(typedef的作用为给定义的结构体类型起别名)


注意:
区分LNode *和LinkList用法,这两个都是指向结点的指针,但是一般强调这是单链表时使用LinkList,强调这是一个结点时使用LNode *,例如我们用LinkList L,强调定义了一个单链表,用(LNode *)malloc(sizeof(LNode))强调创建了新结点


3.2 了解头插法原理

利用头插法实例理解指针原理_第3张图片
头指针永远指向链表第一个结点,带头结点的链表中头结点是链表的第一个结点
利用头插法实例理解指针原理_第4张图片
1.指针s指向新结点
2.进行操作一,让新结点指向链表第二个结点
3.进行操作二,让头结点指向新结点
(注意操作顺序不能反)

3.3 实例讲解

创建头结点(创建链表第一个结点)
利用头插法实例理解指针原理_第5张图片
创建链表第二个结点
利用头插法实例理解指针原理_第6张图片
创建链表第三个结点
利用头插法实例理解指针原理_第7张图片
重复创建链表结点…
代码实现上述过程:
建议大家理解上面1.3指针使用,在下面代码中当指针指向一个结点时,对该指针进行的操作实际上就是对其所指向结点的操作,所以我们可以把指针就当成其指向结点

LinkList List_HeadInsert (LinkList &L) {
	LNode *s; //定义一个指针s 
	int x;
	scanf("%d", &x);
	L = (LinkList)malloc(sizeof(LNode)); //创建头结点,头指针L指向头结点
	L -> next = NULL; //初始化链表,此时链表为空
	//开始为链表创建结点
	while(x!=9999) { //设置循环条件,可不断插入新的结点 
		s = (LNode *)malloc(size(LNode)); //创建新结点,s指向新结点
		s -> data = x; //将x赋值给s内数据域
		s -> next = L -> next; //操作一,使新结点的下一结点为头结点的下一结点
		L -> next = s; //操作二,使新结点为头结点的下一结点
		scanf("%d", &x); //为新结点数据域传入值 
	}
	return L;
}

为了大家更好的了解1.3指针使用接下来再举一个例子

//删除p结点的后继节点
bool Delete_List(LinkList &L, i) {
	LNode *p; 
	//p结点是该链表的第i个结点
	p = getElem(LinkList L, i)
	// q指向p的后继结点,此时可将q看作是p的后继结点 
	LNode *q = p -> next;
	// 令p的数据域等于其后继结点的数据域 
	p -> data = p -> next -> data; 
	//p指向q的后继结点即p的下下个结点 
	p -> next = q -> next;
	free(q); //释放节点空间,将q指针删除实际上也是将q结点删去
	return true;
}

你可能感兴趣的:(C语言,c语言,c++,数据结构)