user-0 提问: 通讯录是不是每一个malloc都有对应的free，如果是的话，那下面的代码是不是有错 head=shifang(head);是什么意思，把所有有错的地方找出来

回复:
user: user-1
content: /*****************************************************************  *  EXAMPLE  1                                                   *  *  This simple program illustrates the basic debugging features *  *  of the C runtime libraries, and the kind of debug output     *  *  that these features generate.                                *  *****************************************************************/  #include <stdio.h> #include <string.h> #include <malloc.h> #include <crtdbg.h>  // This routine place comments at the head of a section of debug output void OutputHeading( const char * explanation ) {    _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\ ************************************\n", explanation ); }  // The following macros set and clear, respectively, given bits // of the C runtime library debug flag, as specified by a bitmask. #ifdef   _DEBUG #define  SET_CRT_DEBUG_FIELD(a) \             _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) #define  CLEAR_CRT_DEBUG_FIELD(a) \             _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) #else #define  SET_CRT_DEBUG_FIELD(a)   ((void) 0) #define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0) #endif   void main( ) {    char *p1, *p2;    _CrtMemState s1, s2, s3;     // Send all reports to STDOUT    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );     // Allocate 2 memory blocks and store a string in each    p1 = malloc( 34 );    strcpy( p1, "This is the p1 string (34 bytes)." );     p2 = malloc( 34 );    strcpy( p2, "This is the p2 string (34 bytes)." );      OutputHeading(        "Use _ASSERTE to check that the two strings are identical" );    _ASSERTE( strcmp( p1, p2 ) == 0 );     OutputHeading(        "Use a _RPT macro to report the string contents as a warning" );    _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );     OutputHeading(        "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );    _CrtMemDumpAllObjectsSince( NULL );     free( p2 );     OutputHeading(        "Having freed p2, dump allocation information about p1 only" );    _CrtMemDumpAllObjectsSince( NULL );     // Store a memory checkpoint in the s1 memory-state structure    _CrtMemCheckpoint( &s1 );     // Allocate another block, pointed to by p2    p2 = malloc( 38 );    strcpy( p2, "This new p2 string occupies 38 bytes.");     // Store a 2nd memory checkpoint in s2    _CrtMemCheckpoint( &s2 );     OutputHeading(        "Dump the changes that occurred between two memory checkpoints" );    if ( _CrtMemDifference( &s3, &s1, &s2 ) )       _CrtMemDumpStatistics( &s3 );     // Free p2 again and store a new memory checkpoint in s2    free( p2 );    _CrtMemCheckpoint( &s2 );     OutputHeading(        "Now the memory state at the two checkpoints is the same" );    if ( _CrtMemDifference( &s3, &s1, &s2 ) )       _CrtMemDumpStatistics( &s3 );     strcpy( p1, "This new p1 string is over 34 bytes" );    OutputHeading( "Free p1 after overwriting the end of the allocation" );    free( p1 );     // Set the debug-heap flag so that freed blocks are kept on the    // linked list, to catch any inadvertent use of freed memory    SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );     p1 = malloc( 10 );    free( p1 );    strcpy( p1, "Oops" );     OutputHeading( "Perform a memory check after corrupting freed memory" );    _CrtCheckMemory( );     // Use explicit calls to _malloc_dbg to save file name and line number    // information, and also to allocate Client type blocks for tracking    p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );    p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );    strcpy( p1, "p1 points to a Normal allocation block" );    strcpy( p2, "p2 points to a Client allocation block" );     // You must use _free_dbg to free a Client block    OutputHeading(        "Using free( ) to free a Client block causes an assertion failure" );    free( p1 );    free( p2 );     p1 = malloc( 10 );    OutputHeading( "Examine outstanding allocations (dump memory leaks)" );    _CrtDumpMemoryLeaks( );     // Set the debug-heap flag so that memory leaks are reported when    // the process terminates. Then, exit.    OutputHeading( "Program exits without freeing a memory block" );    SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF ); }  Output  Use _ASSERTE to check that the two strings are identical: ************************************************************************** C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0   Use a _RPT macro to report the string contents as a warning: ************************************************************************** p1 points to 'This is the p1 string (34 bytes).' and  p2 points to 'This is the p2 string (34 bytes).'   Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations: ************************************************************************** Dumping objects -> {13} normal block at 0x00660B5C, 34 bytes long  Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73  {12} normal block at 0x00660B10, 34 bytes long  Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73  Object dump complete.   Having freed p2, dump allocation information about p1 only: ************************************************************************** Dumping objects -> {12} normal block at 0x00660B10, 34 bytes long  Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73  Object dump complete.   Dump the changes that occurred between two memory checkpoints: ************************************************************************** 0 bytes in 0 Free Blocks. 38 bytes in 1 Normal Blocks. 0 bytes in 0 CRT Blocks. 0 bytes in 0 IgnoreClient Blocks. 0 bytes in 0 (null) Blocks. Largest number used: 4 bytes. Total allocations: 38 bytes.   Now the memory state at the two checkpoints is the same: **************************************************************************   Free p1 after overwriting the end of the allocation: ************************************************************************** memory check error at 0x00660B32 = 0x73, should be 0xFD. memory check error at 0x00660B33 = 0x00, should be 0xFD. DAMAGE: after Normal block (#12) at 0x00660B10.   Perform a memory check after corrupting freed memory: ************************************************************************** memory check error at 0x00660B10 = 0x4F, should be 0xDD. memory check error at 0x00660B11 = 0x6F, should be 0xDD. memory check error at 0x00660B12 = 0x70, should be 0xDD. memory check error at 0x00660B13 = 0x73, should be 0xDD. memory check error at 0x00660B14 = 0x00, should be 0xDD. DAMAGE: on top of Free block at 0x00660B10. DAMAGED located at 0x00660B10 is 10 bytes long.   Using free( ) to free a Client block causes an assertion failure: ************************************************************************** dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse   Examine outstanding allocations (dump memory leaks): ************************************************************************** Detected memory leaks! Dumping objects -> {18} normal block at 0x00660BE4, 10 bytes long  Data: <          > CD CD CD CD CD CD CD CD CD CD  Object dump complete.   Program exits without freeing a memory block: ************************************************************************** Detected memory leaks! Dumping objects -> {18} normal block at 0x00660BE4, 10 bytes long  Data: <          > CD CD CD CD CD CD CD CD CD CD  Object dump complete.

user: user-0
content: 可以留下qq号私聊

user: user-0
content: //文件写入函数   void save(struct address_list *head)   {       FILE *fp;       struct address_list *p1;       char tong[30];       if(head==NULL)       {           printf("通讯录为空,无法存储!\n");           return;       }       printf("请输入保存后的文件名:");       gets(tong);       fp=fopen("tong.txt","w");       if(fp==NULL)       {           printf("cannot open file\n");           return;       }       p1=head;       fprintf(fp,"姓名    职业      手机     Email     通讯地址\n");       for(;p1!=NULL;)        {           fprintf(fp,"%s       %s       %s        %s       %s\n",p1->name,p1->work,p1->handset,p1->email,p1->address);           p1=p1->next;       }       printf("保存完毕!\n");       fclose(fp);   }      //文件读出函数   struct address_list *load(struct address_list *head)   {       FILE *fp;       char tong[30];       struct address_list *p1,*p2;       printf("请输入要输出的文件名:");       gets(tong);       fp=fopen("tong.txt","r");       if(fp==NULL)       {           printf("此通讯录名不存在,无法输出!\n");           return(head);       }       else       {           head=shifang(head);       }       p1=(struct address_list *)malloc(LEN);       fscanf(fp,"%s%s%s%s%s",&p1->name,&p1->work,&p1->handset,&p1->email,&p1->address);       if(feof(fp)!=0)       {           printf("文件为空,无法打开!\n");           return(head);       }       else       {           rewind(fp);           p2=p1;           head=p1;         //  n=0;           while(feof(fp)==0)           {               fscanf(fp,"%s%s%s%s%s",&p1->name,&p1->work,&p1->handset,&p1->email,&p1->address);               if(feof(fp)!=0)                   break;               p2->next=p1;               p2=p1;               p1=(struct address_list *)malloc(LEN);            //   n=n+1;           }           p2->next=NULL;           p1=head;           head=head->next;          // n=n-1;           free(p1);           print(head);           printf("打开完毕!\n");           return(head);       }       fclose(fp);   }      //综合操作函数   struct address_list *menu(struct address_list *head)   {       char num[10];       while(1)       {           printf("*********************\n");           printf("*** 1 姓名查找      ****\n");           printf("*** 2 增加          ****\n");           printf("*** 3 退出          ****\n");           printf("*********************\n");           printf("请输入您选择的操作:");           gets(num);           switch(*num)           {           case '1':               {                   head=search(head);                          //姓名查找                   print(head);               }               break;                 case '2':               {                   head=insert(head);                           //增加                   print(head);               }               break;           case '3':               return head;                  default:               printf("操作错误，此项不存在!\n");               break;           }                 // if(strcmp(num,"6")==0)             //  break;       }       return head;   }   //主函数   void main()   {       struct address_list *head=NULL;       char num[10];       printf("*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n");       printf("*=*               程序说明                *=*\n");       printf("*=*    请及时保存创建完毕的通讯录内容!    *=*\n");       printf("*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n");       while(1)       {           printf("************************\n");           printf("***     1 创建通讯录      ****\n");           printf("***     2 按名字排序      ****\n");           printf("***     3 综合操作        ****\n");           printf("***     4 保存            ****\n");           printf("***     5 打开            ****\n");            printf("***     6 删除            ****\n");           printf("***     7 退出            ****\n");           printf("************************\n");           printf("请输入您选择的操作:");           gets(num);           switch(*num)           {           case '1':               {                   if(head==NULL)                   {                       head=creat();                                //创建                       print(head);                   }                   else                   {                       head=shifang(head);                       head=creat();                                //重新创建                       print(head);                                        }               }               break;           case '2':               {                   head=paixu(head);                               //排序               }               break;           case '3':               {                   head=menu(head);                              //综合操作               }               break;           case '4':               {                   save(head);                                   //文件保存                   print(head);               }               break;           case '5':               {                   head=load(head);                              //文件输出               }               break;           case '6':               {                   head=delete_txl(head);                           //删除                   print(head);               }               break;           case '7':               head=shifang(head);               break;           default:               printf("操作错误，此项不存在!\n");               break;           }           if(strcmp(num,"7")==0)               break;       }   }

user: user-0
content: //输出函数   void print(struct address_list *head)      {       struct address_list *p;       if(head!=NULL)       {           p=head;           printf("本通讯录现在共有%d人:\n",n);           printf("---姓名-------职业--------手机-------Email-------通讯地址\n");           printf("==================================\n");           do           {               printf("== %s",p->name); printf("       ");               printf("%s",p->work); printf("       ");               printf("%s",p->handset); printf("       ");               printf("%s",p->email); printf("       ");               printf("%s",p->address); printf("       \n");               p=p->next;           }while(p!=NULL);           printf("==================================\n");       }       else           printf("通讯录为空,无法输出!\n");   }   //增加函数   struct address_list *insert(struct address_list *head)    {       struct address_list *p0,*p1,*p2;       char name[20];       p1=head;       printf("请输入增加的内容:\n");       printf("请输入姓名:");      gets(name);       if(strcmp(name,"0")==0)       {           printf("姓名不能为0,增加失败!\n");           return(head);       }       else       {           p0=(struct address_list *)malloc(LEN);           strcpy(p0->name,name);           printf("请输入职业:"); gets(p0->work);           printf("请输入手机:"); gets(p0->handset);           printf("请输入电子邮件:"); gets(p0->email);           printf("请输入通讯地址:");  gets(p0->address);           n=n+1;           if(head==NULL)           {               head=p0;               p0->next=NULL;               return head;           }           else           {               while(strcmp(p0->name,p1->name)>0&&(p1->next!=NULL))               {                   p2=p1;                   p1=p1->next;               }               if(strcmp(p0->name,p1->name)<0 || strcmp(p0->name,p1->name)==0)               {                   if(head==p1)                   {                       head=p0;  //第一次输入po                 }                   else                   {                       p2->next=p0; //不是第一次输入po                  }                   p0->next=p1;  //p1zhixiang head ,jiushi p2-p0-p1             }               else               {                   p1->next=p0;                   p0->next=NULL;               }               return head;           }       }   }   struct address_list *delete_txl(struct address_list *head)   {       struct address_list *p,*q;       char name[30];          if(head==NULL)       {           printf("通讯录为空,无法显示!\n");           return head;       }       p=head;       printf("请输入需要删除的人的姓名:");       gets(name);       if(strcmp(head->name,name)==0)       {           head=head->next;           free(p);           printf("删除操作成功！\n");          n--;          return head;       }       else       {           q=head,p=head->next;           while(p!=NULL)           {               if(strcmp(p->name,name)==0)               {                   q->next=p->next;                   free(p);                   printf("删除操作成功！\n");                   n--;                  return head;                                }               p=p->next;               q=q->next;           }             return head;       }   } //排序函数   struct address_list *paixu(struct address_list *head)   {       struct address_list *p1,*p2;       int i,j;       struct address_list1       {           char name[30];           char work[30];           char handset[30];           char email[30];           char address[30];       };       struct address_list1 px[200];       struct address_list1 temp;       if(head==NULL)       {           printf("通讯录为空,无法排序!\n");           return(head);       }       p1=head;       for(i=0;i<n,p1!=NULL;i++)       {           strcpy(px[i].name,p1->name);           strcpy(px[i].work,p1->work);           strcpy(px[i].handset,p1->handset);           strcpy(px[i].email,p1->email);           strcpy(px[i].address,p1->address);           p2=p1;           p1=p1->next;       }       head=shifang(head);       for(j=0;j<n-1;j++)       {           for(i=j+1;i<n;i++)           {               if(strcmp(px[i].name,px[j].name)<0)               {                   temp=px[i];                   px[i]=px[j];                   px[j]=temp;  //j=0，循环第一次后，，pj变成最小的             }           }       }       p1=(struct address_list *)malloc(LEN);       p2=p1;       strcpy(p1->name,px[0].name);      strcpy(p1->work,px[0].work);       strcpy(p1->handset,px[0].handset);       strcpy(p1->email,px[0].email);       strcpy(p1->address,px[0].address);          head=p1;       for(i=1;i<n;i++)       {           p1=(struct address_list *)malloc(LEN);           strcpy(p1->name,px[i].name);           strcpy(p1->work,px[i].work);           strcpy(p1->handset,px[i].handset);           strcpy(p1->email,px[i].email);           strcpy(p1->address,px[i].address);           p2->next=p1;           p2=p1;       }       p2->next=NULL;       printf("按姓名排序后为:\n");       print(head);       return(head);   }   //姓名查找函数   struct address_list *search(struct address_list *head)   {       struct address_list *p1,*p2;       int m;       char name[30];       if(head==NULL)       {           printf("通讯录为空,无法分类查找!\n");           return(head);       }       p1=head;       printf("********************\n");       printf("**  请输入需要查找的姓名  **\n");       printf("********************\n");       m=0;       gets(name);       while(p1!=NULL)       {           while(strcmp(p1->name,name)!=0&&p1->next!=NULL)           {               p2=p1;               p1=p1->next;           }           if(strcmp(p1->name,name)==0)           {               m++;               printf("你查找的内容是:\n");               printf("+++++++++++++++++++++++++++++++++++\n");               printf("++ %s        %s       %s       %s        %s\n",p1->name,p1->work,p1->handset,p1->email,p1->address);               printf("+++++++++++++++++++++++++++++++++++\n");           }           p1=p1->next;              if(m==0)           {               printf("此人未在本通讯录中!\n");           }           break;       }          return(head);   }      //释放内存函数   struct address_list *shifang(struct address_list *head)   {       struct address_list *p1;       while(head!=NULL)       {           p1=head;           head=head->next;           free(p1);       }       return(head);   }

user: user-0
content: 引用 4 楼 zhao4zhong1 的回复:代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。 I 内存是否释放怎么判断。它又没有报错

user: user-1
content: 代码功能归根结底不是别人帮自己看或讲解或注释出来的；而是被自己静下心来花足够长的时间和精力亲自动手单步或设断点或对执行到某步获得的中间结果显示或写到日志文件中一步一步分析出来的。 提醒：再牛×的老师也无法代替学生自己领悟和上厕所！ 单步调试和设断点调试（VS IDE中编译连接通过以后，按F10或F11键单步执行，按Shift+F11退出当前函数；在某行按F9设断点后按F5执行停在该断点处。）是程序员必须掌握的技能之一。