需要特别注意的是我们在定义一个指针后需要先将该指针变量指向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;
}
当我们定义一个指针变量后,我们可以将该指针变量理解为地址箱,箱内可存放不同的地址,但是箱内只能存一个地址,可以这样理解指针即地址
"* "星号符为访问符,访问指针变量所指空间内的值
#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;
}
当指针指向一个变量,改变指针即改变变量的值
一块内存被划分后,我们用变量名为其命名,然后我们不仅可以通过变量名访问这块内存,还可以通过地址访问;通俗易懂,我们不仅可以通过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;
}
(void *)malloc(unsigned int size)
1.该函数作用为在内存的动态存储区中分配一个长度为size的连续空间,此函数的返回值是一个指针(该指针类型与指向空间内值的类型相同),该指针指向该分配区域的起始地址,所以我们也可以理解为该函数会返回分配区域的起始地址
2.如果分配成功会返回指向分配区域的指针,若失败则会返回一个空指针
3.新的ANSIC标准规定该函数返回为void型指针,所以必要时要进行指针类型转换,如若想分配的空间内的值为int型,那么就需要(int *)malloc
typedef struct LNode {
ElemType data;
struct LNode *next; //定义struct LNode指针型变量,变量名为next,指针指向下一个结点即指针内的值为下一结点的地址
}LNode, *LinkList;
(typedef的作用为给定义的结构体类型起别名)
注意:
区分LNode *和LinkList用法,这两个都是指向结点的指针,但是一般强调这是单链表时使用LinkList,强调这是一个结点时使用LNode *,例如我们用LinkList L,强调定义了一个单链表,用(LNode *)malloc(sizeof(LNode))强调创建了新结点
头指针永远指向链表第一个结点,带头结点的链表中头结点是链表的第一个结点
1.指针s指向新结点
2.进行操作一,让新结点指向链表第二个结点
3.进行操作二,让头结点指向新结点
(注意操作顺序不能反)
创建头结点(创建链表第一个结点)
创建链表第二个结点
创建链表第三个结点
重复创建链表结点…
代码实现上述过程:
建议大家理解上面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;
}