关于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");
}