C指针详解与链表实现

一直以来,对于c语言的指针就一知半解,数据结构课程多半是用c指针实现的,所以重新学习了一下

代码来源:《啊哈,算法》 人民邮电出版社、中国工信出版集团 啊哈磊著

(一)指针

使用指针的原因:方便版本迭代,假设你设计的程序已经发布或者交付使用,但是你发现要做出新的修改(增加存储空间等等),用指针可以更简单便捷的进行修改。

#include
#include
int main(){
	//1. 
	int a=10;
	int *p;		//定义一个指针p 
	p=&a;		//指针p获取变量a的地址 
	printf("%d\n",*p); 	//输出指针p所指向的内存中的值 
	 
	//2.
	p=(int*)malloc(sizeof(int));	//指针p获取动态分配的内存空间地址 
	*p=20;				//向指针p所指向的内存空间中存入10 
	printf("%d\n",*p);	//输出指针p所指向的内存中的值 
	
	return 0;
}
注:1.malloc——分配空间的函数被包含在"stdlib.h"头文件里

       2.malloc函数的返回类型是void*类型,表示未确定类型的指针,在C和C++中,void*类型的指针可以强制转换为任何其他类型的指针。我们将其强制转化为整型指针,以便告诉计算机这里的4个字节作为一个整体用来存放整数。

       3.指针变量存储的是一个内存空间的首地址(第一个字节的地址),但是这个空间占用了多少个字节,用来存储什么类型的数,则是由指针的类型来标明的。这样系统才知道应该取多少个连续内存作为一个数据

(二)链表

用结构体定义一个链表类型:

struct node{
	int data;			//数据域 
	struct node *next; //指针域 
}; 
第二个成员是一个指针, 用来存储下一个节点的地址。因为下一个节点的类型也是struct node,所以这个指针的类型也必须是struct node*类型的指针。

建立链表遵从以下步骤:
(1)用一个头指针head指向链表的最开始。当链表还没有建立时,头指针head为空(也可理解为指向空节点)

struct node *head;
head=NULL;	//头指针初始为空 

(2)接下来创建第一个节点,并用临时指针p指向这个节点

struct node *p;
//动态申请一个空间,用来存放一个节点,并用临时指针p指向这个节点 
p=(struct node*)malloc(sizeof(struct node));

(3)接下来分别设置新创建的这个节点的左半部分和右半部分

scanf("%d",&a);
p->data=a;		//将数据存入data域中 
p->next=NULL; 	//设置当前节点的后继指针指向空,也就是当前节点的下一个节点为空 
“->”叫做“ 结构体指针运算符”,用来访问结构体内部的成员。p是一个指针,因此不能用"."号访问内部成员。

(4)接着设置头指针,并设置新创建节点的*next指向空,头指针的作用是方便以后从头遍历整个链表

if(head==NULL)
	head=p;		//如果这是第一个创建的节点,则将头指针指向这个节点 
else 
	q->next=p;	//如果不是第一个创建的节点,则将上一个节点的后继指针指向当前的节点 

如果这是第一个创建的节点,则将头指针指向这个节点。

如果不是第一个创建的节点, 则将上一个节点的后继指针指向当前节点。

最后要将指针q也指向当前节点,因为待会儿临时指针p将会指向新创建的节点。

q=p;		//指针q也指向当前节点 

综合代码实现如下:

#include  
#include  
//创建结构体类型表示链表   
struct node{  
    int data;  
    struct node *next;  
};   
  
int main(){  
    struct node *head,*p,*q,*t;  
    int i,n,a;  
    scanf("%d",&n);  
    head=NULL;      //头指针初始为空   
    for(int i=1;i<=n;i++){       //循环读入n个数   
        scanf("%d",&a);  
        //动态申请一个空间,用来存放一个节点,并用临时指针p指向这个节点   
        p=(struct node*)malloc(sizeof(struct node));      
        p->data=a;       //将数据存储到当前节点的data域中   
        p->next=NULL;    //设置当前节点的后继指针指向空,也就是当前节点的下一个节点为空   
        if(head==NULL)  
            head=p;     //如果这是第一个创建的节点,则将头指针指向这个节点   
        else   
            q->next=p;   //如不是第一个创建的节点,则将上一个节点的后继指针指向当前节点   
        q=p;            //指针q也指向当前节点   
    }  
      
    //输出链表中所有的数   
    t=head;  
    while(t!=NULL){  
        printf("%d ",t->data);  
        t=t->next;       //继续下一个节点   
    }  
      
    free(p);  
    p=NULL;  
    return 0;  
} 


(5)插入操作:

如果想向链表中插入数据,首先用一个临时指针t从链表头部开始遍历:

t=head;		//从链表头部开始遍历 

等到指针t的下一个值比l6大的时候,将6插入到中间。即t->next->data大于6时进行插入:

scanf("%d",&a);		//读入待插入的数 
while(t!=NULL){		//当没有到达链表尾部的时候循环 
	if(t->next==NULL||t->next->data>a){
		//如果当前节点是最后一个节点或者下一个节点的值大于待插入数的时候插入 
		p=(struct node*)malloc(sizeof(struct node));
		//动态申请一个空间,用来存放新增节点 
		p->data=a;
		p->next=t->next;//新增节点的后继指针指向当前节点的后继指针所指向的节点 
		t->next=p;		//当前节点的后继指针指向新增节点 
		break;	//插入完毕即退出循环 
	}
	t=t->next;		//继续下一个节点 
} 

综合代码如下:

#include
#include
//创建结构体类型表示链表 
struct node{
	int data;
	struct node *next;
}; 

int main(){
	struct node *head,*p,*q,*t;
	int i,n,a;
	scanf("%d",&n);
	head=NULL;		//头指针初始为空 
	for(int i=1;i<=n;i++){		//循环读入n个数 
		scanf("%d",&a);
		//动态申请一个空间,用来存放一个节点,并用临时指针p指向这个节点 
		p=(struct node*)malloc(sizeof(struct node));	
		p->data=a;		//将数据存储到当前节点的data域中 
		p->next=NULL;	//设置当前节点的后继指针指向空,也就是当前节点的下一个节点为空 
		if(head==NULL)
			head=p;		//如果这是第一个创建的节点,则将头指针指向这个节点 
		else 
			q->next=p;	//如不是第一个创建的节点,则将上一个节点的后继指针指向当前节点 
		q=p;			//指针q也指向当前节点 
	}
	
	scanf("%d",&a);		//读入待插入的数 
	t=head;				//从链表的头部开始遍历 
	while(t!=NULL){		//当没有到达链表尾部的时候循环 
		if(t->next==NULL||t->next->data>a){
			//如果当前节点是最后一个节点或者下一个节点的值大于待插入数的时候插入 
			p=(struct node*)malloc(sizeof(struct node));
			//动态申请一个空间,用来存放新增节点 
			p->data=a;
			p->next=t->next;//新增节点的后继指针指向当前节点的后继指针所指向的节点 
			t->next=p;		//当前节点的后继指针指向新增节点 
			break;	//插入完毕即退出循环 
		}
		t=t->next;		//继续下一个节点 
	} 
	
	//输出链表中所有的数 
	t=head;
	while(t!=NULL){
		printf("%d ",t->data);
		t=t->next;		//继续下一个节点 
	}
	
	free(p);
	p=NULL;
	return 0;
}


你可能感兴趣的:(C指针)