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