c语言之链表的实现

关于malloc和free的使用:

Malloc         格式void malloc(int size)      作用:给指针型变量分配一个size的内存空间。 

                     比如 int *a;   a=(int*)malloc(int)   指针a指向一个4字节的内存空间,a存放该内存空间的地址。

Free             格式void free(void*ptr)       作用:使指针型变量指向的内存空间释放,但是该指针变量还是会指向该内存空间。

                     如果在释放指针所指向的内存空间之后,仍然访问该内存空间 ,这样就会产生不可预知的错误(出现内中断,权限不够)。

                    注意:在释放指针之后,该指针要指向NULL,不然会成为野指针。

 

关于野指针,空指针

 

野指针        定义:指向一个已删除的内存空间或指向超过访问权限的内存空间

                     成因:①:定义时未初始化。②:指针已被删除或释放后没有指向NULL③:指针访问超过变量的作用域。

                由于他的指向是未知的,访问会带来不可预知的错误。

空指针        定义:指针型变量指向值为NULL(即整数0)

                例如:int *p=NULL;    尽量在初始化时赋值为NULL,其一,会避免指向野指针再调用出现未知的错误;其二,在链表或其他案例容易作为判断条件.。

 

#include
   
   
    
    	
#include
    
    
     
     	
#define SIZE_stu sizeof(struct stu)
	struct stu
	{
		int num;
		int score;
		struct stu *next;
    };
	int n;    //记录链表的个数
//笔者认为链表中插入节点在属于链表函数中最难的一种。其中的难点在插入点的寻
//找和区分插入位置上

            //插入节点元素
	 struct stu *linkedlist_Insert(struct stu *head, struct stu *unit)
	{
		struct stu *p1, *p2;
		p1 = head;
		if (head != NULL)
		{
     //插入点的寻找:
     //在首节点不为NULL的情况下,有两种情况作为跳出循环的条件  
     其一,寻找到指向的节点序号大于插入节点的序号;
     其二,寻找到末尾节点。                                                                                                                      
			while (p1->num
     
     
      
      num&&p1->next!=NULL)
			{
				p2 = p1;
				p1 = p1->next;
			}
			//插入点位置的判断:①链表首部节点之前②链表节点之中③链表节点末尾。
			if (p1->next==NULL&&unit->num>p1->num)                   
			//链表节点末尾        两判断条件的位置不能够交换
			{
				p1->next = unit; 
		//链表末尾p的下一节点为NULL,p的序号大于插入元素的序号作为区分条件
				unit->next == NULL;
			}
			else
			{
				if (head==p1)  //链表首部节点之前
				{
					head = unit;   
//在排除链表节点末尾后情况不予考虑,所以p等于head可以作为区分链表首部节点之
//前和链表节点之中的区分条件。
					unit->next = p1;                                              
				}
				else					             //链表节点之中
				{
					unit->next = p1;                                             
					p2->next = unit;
				}
			}
		}
		else             //首部为空时
		{
			head = unit;
		}
		n += 1;   //链表项加1
		return head;
	}
	
	
	
	 //之前遇到一种错误的想法,whlie插入指定位置作为判断条件时,认为当p->next
	 //为空时,再用p=p->next会出现未知错误(事后证明没有出现错误)
	
	//输出链表元素
	 void linkedlist_Input(struct stu *head)                             
	 {
		 struct stu *p;
		 if (head == NULL)
		 {
			 printf("链表尾空!\n");
		 }
		 else
		 {
			 p = head;
			 while (p != NULL)
			 {
	      printf("学号为:%d  成绩为:%d 该地址为:%p\n", p->num, p->score, p);
		  p = p->next;
			 }
		 }
	 }
	
	//查找节点元素
	struct stu *linkedlist_Search(struct stu *head)                    
	{
		struct stu *p=NULL;
		int sid= 0;
		p = head;
		printf("请输入要查看学生的学号:");
		scanf("%d", &sid);
		while (p->next!= NULL&&p->num != sid)
		{
			p = p->next;
		}
		if (p->num != sid)
		{
			printf("你输入的学号有误\n");
			return NULL;
		}
		printf("学生的成绩为:%d\n", p->score);
		
	}
	//删除节点元素
	struct stu *linkedlist_Delete(struct stu *head)
	{
		struct stu *p1=NULL,*p2=NULL;
		int sid= 0;
		p1 = head;
		printf("请输入要删除学生的学号:");
		scanf("%d", &sid);
		while (p1->next!= NULL&&p1->num != sid)
		{
			p2 = p1;
			p1 = p1->next;
		}
		if (p1->num != sid)
		{
			printf("你输入的学号有误\n");
			return NULL;
		}
		if (p1 == head)	//当删除为链表节点首部时的
					                       
		{
			head = p1->next;
		}
		else
		{
			p2->next = p1->next;
		}
		free(p1); //在释放某指针变量之后,一定要将指针变量指向NULL                                                                   
		printf("\n你已成功删除\n");
		n--;
		return head;
	}
	//释放链表
	void linkedlist_Return(struct stu *head)
	{
		struct stu *p1=NULL,*p2=NULL;
		p1 = head;
		p2 = head;
		while (p2 != NULL)
		{
			free(p1);
			p1 = p2;
			p2 = p2->next;
		}
	}
	
	
int main(int argc,char *argv)
{
	struct stu *head = NULL;
	struct stu *unit = NULL;
	char c='0';
	printf("--------------------请输入1;插入节点------------------------\n");
	printf("--------------------请输入2;输出链表------------------------\n");
	printf("--------------------请输入3;查找节点------------------------\n");
	printf(---------------------请输入4;删除节点------------------------\n");
	printf("--------------------请输入5;释放链表并安全退出程序----------\n");
	while (1)
	{
		printf("请输入你要进行的操作:");
		scanf("%c", &c);
		switch c//使用getchar()作为缓冲区接受换行(回车)                                                                   
		{
		case '1':
		{
			unit = (struct stu*)malloc(SIZE_stu);
			unit->next = NULL;
			if (unit == NULL)
			{
				printf("插入节点失败\n");
				exit(0);
			}
			printf("请输入学生的学号和成绩:");
			scanf("%d", &unit->num);
			scanf("%d", &unit->score);
			head=linkedlist_Insert(head,unit);
			printf("\n你已插入成功!\n");
			getchar();
			break;
		}
		case '2':
		{
			linkedlist_Input(head);
			getchar();
			break;
		}
		case '3':
		{
			linkedlist_Search(head);
			getchar();
			break;
		}
		case '4':
		{
			head=linkedlist_Delete(head);
			getchar();
			break;
		}
		case '5':
		{
			linkedlist_Return(head);
			printf("你已成功退出程序!");
			exit(0);
			break;
		}

		default:
			printf("输入错误:请重新输入\n");
			getchar();
		}
	}
	system("pause");
}
     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值