user-0 提问: 自己实现的free()函数疑问

回复:
user: user-1
content: 代码： /*  * 链表综合应用  */ #include <stdio.h> #include <stdlib.h> #include <malloc.h>  struct node { 	int num; 	struct node *next; };  struct node *crfun(int n) { 	struct node *head,*p1,*p2; 	p1=p2=head=(struct node *)malloc(sizeof(struct node)); 	scanf("%d",&head->num); 	n--; 	while(n) 	{ 		p2=p1; 		p1=(struct node *)malloc(sizeof(struct node)); 		scanf("%d",&p1->num); 		p2->next=p1; 		n--; 	} 	p1->next=NULL; 	return head; }  struct node *hbfun(struct node *p1,struct node *p2) { 	 struct node *head,*p; 	 if(p1->num<p2->num)head=p1; 	 else head=p2; 	 p=NULL; 	 while(p1!=NULL&&p2!=NULL) 	 { 		 if(p1->num<p2->num) 		 { 			 p->next=p1; 			 p=p1; 			 p1=p1->next; 		 } 		 else 		 { 			 p->next=p2; 			 p=p2; 			 p2=p2->next; 		 } 	 } 	 //以下两句作用是把多余的部分连接起来 	 if(p1!=NULL)p->next=p1; 	 if(p2!=NULL)p->next=p2; 	 return head; }  struct node *delfun(struct node *head,int m) { 	struct node *p1,*p2; 	p1=p2=head; 	if(m==head->num) 	{ 		head=head->next; 		return head; 	} 	while(p2!=NULL&&p2->num!=m) 	{ 		p1=p2; 		p2=p2->next; 	} 	if(p2->num==m) 	{ 		p1->next=p2->next; 	} 	return head; }  struct node *insfun(struct node *head,int m) { 	struct node *p1,*p2,*p; 	p=p2=head; 	p1=(struct node *)malloc(sizeof(struct node)); 	p1->num=m; 	if(m<=head->num){p1->next=head;head=p1;return head;} 	while(m>=p2->num&&p2!=NULL) 	{ 		p=p2; 		p2=p2->next; 	} 		p->next=p1; 		p1->next=p2; 	return head; }  struct node *sortfun(struct node *head) { 	struct node *p; 	p=head->next; 	head->next=NULL; 	while(p!=NULL) 	{ 		head=insfun(head,p->num); 		p=p->next; 	} 	return head; }  void putfun(struct node *head) { 	while(head!=NULL) 	{ 		printf("%3d",head->num); 		head=head->next; 	} 	printf("\n"); }  void freefun(struct node* head) { 	struct node* temp; 	while(head!=NULL) 	{ 		temp=head->next; 		free(head); 		head=temp; 	} }  int main() { 	 struct node *head; 	 struct node *p1; 	 struct node *p2; 	 int m; 	 p1=crfun(5);			//创建链表 	 p2=crfun(5);			//创建链表 	 head=hbfun(p1,p2);	//合并链表(二路合并法) 	 scanf("%d",&m); 	 head=delfun(p1,m);	//删除节点 	 scanf("%d",&m); 	 head=insfun(p1,m);	//插入节点 	 head=sortfun(p1);		//排序链表 	 putfun(head);			//输出链表 	 freefun(head)//在实际应用中链表使用完后要记得释放 	 return 0; }

user: user-2
content: 引用 8 楼 zxh707wk 的回复:[quote=引用 1 楼 zhao4zhong1 的回复:] 试试在每次调用free后，输出整个占用内存块链和空闲内存块链的内容辅助调试。 参考这个代码的做法： //假设带表头结点的单向链表头指针为head，试编写一个算法将值为5的结点插入到连接表的第k个结点前，删除第k个节点，并对该链表进行排序。 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> struct NODE {     int          data;     struct NODE *next; } H,*head,*p,*q,*s1,*s2,*s3,*s4,*s; int i,j,k,n,t,m; int main() {     srand(time(NULL));      //填写头节点数据     H.data=-1;     H.next=NULL;     head=&H;      //创建10个节点的单链表     p=head;     for (i=0;i<10;i++) {         q=(struct NODE *)malloc(sizeof(struct NODE));         if (NULL==q) return 1;         q->data=rand()%100;//填写0..99的随机值         q->next=NULL;         p->next=q;         p=q;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将值为5的结点插入到单链表的第k个结点前     k=3;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=(struct NODE *)malloc(sizeof(struct NODE));             if (NULL==q) return 1;             q->data=5;             q->next=p->next;             p->next=q;             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //删除第k个节点     k=5;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=p->next;             if (q) {                 p->next=q->next;                 free(q);             }             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //从小到大排序     for (p=head;p!=NULL && p->next!=NULL;p=p->next) {         for (q=p->next;q!=NULL && q->next!=NULL;q=q->next) {             if (p->next->data > q->next->data) {                  //交换data //              printf("swap %02d %02d\n",p->next->data,q->next->data); //              t=p->next->data;p->next->data=q->next->data;q->next->data=t;                  //或者                  //交换next //              printf("swap %02d %02d\n",p->next->data,q->next->data);                 s1=p->next;                 s2=p->next->next;                 s3=q->next;                 s4=q->next->next;                  if (s2!=s3) {                      p->next=s3;                     s3->next=s2;                      q->next=s1;                     s1->next=s4;                 } else {                      p->next=s3;                     s3->next=s1;                            q=s3;                     s1->next=s4;                 }                  //输出整个单链表 //              s=head->next; //              while (1) { //                  if (NULL==s) { //                      printf("\n"); //                      break; //                  } //                  printf("%02d->",s->data); //                  s=s->next; //              } //              getchar();             }         }     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将单链表中前 m 个结点和后 n 个结点进行互换,m+n为链表总长10     m=4;     n=6;     k=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         k++;         if (m+1==k) {             q=p;         }         s=p;         p=p->next;     }     s1=head->next;     head->next=q->next;     s->next=s1;     q->next=NULL;      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //释放所有节点     p=head->next;     while (1) {         if (NULL==p) {             break;         }         q=p->next;         free(p);         p=q;     }      return 0; } //18->94->58->17->27->20->43->57->75->78-> //18->94->05->58->17->27->20->43->57->75->78-> //18->94->05->58->27->20->43->57->75->78-> //05->18->20->27->43->57->58->75->78->94-> //43->57->58->75->78->94->05->18->20->27-> //  能把 创建、插入、删除、排序、输出、释放链表都写成函数形式不？ 虽然这样写的运行效率比用函数写要快一些[/quote] 那就麻烦你在这段代码的基础上修改，编译、链接、调试无误后帖上来给大家共享了 。我还是比较懒的。

user: user-3
content: malloc出来的内存并不仅仅是你设定的sizeof的大小，malloc里面还包含了各种信息结构，所以free这个也要涉及到malloc的实现，实际上malloc就是一个双向链表

user: user-1
content: 引用 1 楼 zhao4zhong1 的回复:试试在每次调用free后，输出整个占用内存块链和空闲内存块链的内容辅助调试。 参考这个代码的做法： //假设带表头结点的单向链表头指针为head，试编写一个算法将值为5的结点插入到连接表的第k个结点前，删除第k个节点，并对该链表进行排序。 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> struct NODE {     int          data;     struct NODE *next; } H,*head,*p,*q,*s1,*s2,*s3,*s4,*s; int i,j,k,n,t,m; int main() {     srand(time(NULL));      //填写头节点数据     H.data=-1;     H.next=NULL;     head=&H;      //创建10个节点的单链表     p=head;     for (i=0;i<10;i++) {         q=(struct NODE *)malloc(sizeof(struct NODE));         if (NULL==q) return 1;         q->data=rand()%100;//填写0..99的随机值         q->next=NULL;         p->next=q;         p=q;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将值为5的结点插入到单链表的第k个结点前     k=3;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=(struct NODE *)malloc(sizeof(struct NODE));             if (NULL==q) return 1;             q->data=5;             q->next=p->next;             p->next=q;             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //删除第k个节点     k=5;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=p->next;             if (q) {                 p->next=q->next;                 free(q);             }             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //从小到大排序     for (p=head;p!=NULL && p->next!=NULL;p=p->next) {         for (q=p->next;q!=NULL && q->next!=NULL;q=q->next) {             if (p->next->data > q->next->data) {                  //交换data //              printf("swap %02d %02d\n",p->next->data,q->next->data); //              t=p->next->data;p->next->data=q->next->data;q->next->data=t;                  //或者                  //交换next //              printf("swap %02d %02d\n",p->next->data,q->next->data);                 s1=p->next;                 s2=p->next->next;                 s3=q->next;                 s4=q->next->next;                  if (s2!=s3) {                      p->next=s3;                     s3->next=s2;                      q->next=s1;                     s1->next=s4;                 } else {                      p->next=s3;                     s3->next=s1;                            q=s3;                     s1->next=s4;                 }                  //输出整个单链表 //              s=head->next; //              while (1) { //                  if (NULL==s) { //                      printf("\n"); //                      break; //                  } //                  printf("%02d->",s->data); //                  s=s->next; //              } //              getchar();             }         }     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将单链表中前 m 个结点和后 n 个结点进行互换,m+n为链表总长10     m=4;     n=6;     k=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         k++;         if (m+1==k) {             q=p;         }         s=p;         p=p->next;     }     s1=head->next;     head->next=q->next;     s->next=s1;     q->next=NULL;      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //释放所有节点     p=head->next;     while (1) {         if (NULL==p) {             break;         }         q=p->next;         free(p);         p=q;     }      return 0; } //18->94->58->17->27->20->43->57->75->78-> //18->94->05->58->17->27->20->43->57->75->78-> //18->94->05->58->27->20->43->57->75->78-> //05->18->20->27->43->57->58->75->78->94-> //43->57->58->75->78->94->05->18->20->27-> //  能把 创建、插入、删除、排序、输出、释放链表都写成函数形式不？ 虽然这样写的运行效率比用函数写要快一些

user: user-0
content: 引用 6 楼 u012061345 的回复:你说的有道理。我要看看全文再考虑一下。 《程序员的自我修养》13.1.2堆的实现，第418页，清单13-2 malloc.c 看出了结果请回复我

user: user-4
content: 引用 5 楼 haoren026 的回复:假设用free释放的内存块首地址是10，前一块内存首地址是0，后一块内存是20，后一块的后一块内存是30。以下用首地址代表内存块 第二种情况下：内存块10的长度+=内存块20的长度，10的next指向30，但30的prev还指向20，这就是我说的问题。如果以后访问30的prev，那么跳转到20，而20已经不是一个header了，而是普通内存数据。所以应该把30的prev指向10  你说的有道理。我要看看全文再考虑一下。

user: user-0
content: 引用 4 楼 u012061345 的回复:完全没有必要。因为第一种情况下逻辑上删除了原header指向的块。而第二种情况下逻辑上删除了header->next的块，既然该块已经删除了，当然不再需要设置header->next->prev。 画个指针的指向图，仔细看看。这个逻辑上就是一个双向链表。  假设用free释放的内存块首地址是10，前一块内存首地址是0，后一块内存是20，后一块的后一块内存是30。以下用首地址代表内存块 第二种情况下：内存块10的长度+=内存块20的长度，10的next指向30，但30的prev还指向20，这就是我说的问题。如果以后访问30的prev，那么跳转到20，而20已经不是一个header了，而是普通内存数据。所以应该把30的prev指向10

user: user-2
content: 试试在每次调用free后，输出整个占用内存块链和空闲内存块链的内容辅助调试。 参考这个代码的做法： //假设带表头结点的单向链表头指针为head，试编写一个算法将值为5的结点插入到连接表的第k个结点前，删除第k个节点，并对该链表进行排序。 #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <time.h> struct NODE {     int          data;     struct NODE *next; } H,*head,*p,*q,*s1,*s2,*s3,*s4,*s; int i,j,k,n,t,m; int main() {     srand(time(NULL));      //填写头节点数据     H.data=-1;     H.next=NULL;     head=&H;      //创建10个节点的单链表     p=head;     for (i=0;i<10;i++) {         q=(struct NODE *)malloc(sizeof(struct NODE));         if (NULL==q) return 1;         q->data=rand()%100;//填写0..99的随机值         q->next=NULL;         p->next=q;         p=q;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将值为5的结点插入到单链表的第k个结点前     k=3;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=(struct NODE *)malloc(sizeof(struct NODE));             if (NULL==q) return 1;             q->data=5;             q->next=p->next;             p->next=q;             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //删除第k个节点     k=5;     n=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         n++;         if (k==n) {             q=p->next;             if (q) {                 p->next=q->next;                 free(q);             }             break;         }         p=p->next;     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //从小到大排序     for (p=head;p!=NULL && p->next!=NULL;p=p->next) {         for (q=p->next;q!=NULL && q->next!=NULL;q=q->next) {             if (p->next->data > q->next->data) {                  //交换data //              printf("swap %02d %02d\n",p->next->data,q->next->data); //              t=p->next->data;p->next->data=q->next->data;q->next->data=t;                  //或者                  //交换next //              printf("swap %02d %02d\n",p->next->data,q->next->data);                 s1=p->next;                 s2=p->next->next;                 s3=q->next;                 s4=q->next->next;                  if (s2!=s3) {                      p->next=s3;                     s3->next=s2;                      q->next=s1;                     s1->next=s4;                 } else {                      p->next=s3;                     s3->next=s1;                            q=s3;                     s1->next=s4;                 }                  //输出整个单链表 //              s=head->next; //              while (1) { //                  if (NULL==s) { //                      printf("\n"); //                      break; //                  } //                  printf("%02d->",s->data); //                  s=s->next; //              } //              getchar();             }         }     }      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //将单链表中前 m 个结点和后 n 个结点进行互换,m+n为链表总长10     m=4;     n=6;     k=0;     p=head;     while (1) {         if (NULL==p) {             break;         }         k++;         if (m+1==k) {             q=p;         }         s=p;         p=p->next;     }     s1=head->next;     head->next=q->next;     s->next=s1;     q->next=NULL;      //输出整个单链表     s=head->next;     while (1) {         if (NULL==s) {             printf("\n");             break;         }         printf("%02d->",s->data);         s=s->next;     }      //释放所有节点     p=head->next;     while (1) {         if (NULL==p) {             break;         }         q=p->next;         free(p);         p=q;     }      return 0; } //18->94->58->17->27->20->43->57->75->78-> //18->94->05->58->17->27->20->43->57->75->78-> //18->94->05->58->27->20->43->57->75->78-> //05->18->20->27->43->57->58->75->78->94-> //43->57->58->75->78->94->05->18->20->27-> //

user: user-4
content: 完全没有必要。因为第一种情况下逻辑上删除了原header指向的块。而第二种情况下逻辑上删除了header->next的块，既然该块已经删除了，当然不再需要设置header->next->prev。 画个指针的指向图，仔细看看。这个逻辑上就是一个双向链表。

user: user-5
content: 你再看看源代码,这个好像不是简单的双链表结构