鱼C论坛

 找回密码
 立即注册
查看: 1832|回复: 20

[已解决]重金求解释,请狠狠地用解释抽我

[复制链接]
发表于 2020-8-12 11:51:39 | 显示全部楼层 |阅读模式
10鱼币
本帖最后由 科科都不挂 于 2020-8-12 12:55 编辑

这是C语言S1E46单链表2课上的例题:

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. void addBook(struct Book **library);
  4. void printLibrary (struct Book *library);
  5. void releaseLibrary(struct Book **library);

  6. struct Book
  7. {
  8.         char title[128];
  9.         char author[40];
  10.         struct Book *next;
  11. };

  12. void getinput(struct Book *book);

  13. void getinput(struct Book *book)
  14. {
  15.         printf ("请输入书名:");
  16.         scanf ("%s", book->title);
  17.        
  18.         printf ("请输入作者:");
  19.         scanf ("%s", book->author);
  20. }

  21. void addBook(struct Book **library) //在这里为什么两个*,即指向指针的指针。因为你要修改的是指针的值,所以你要找到它的地址。
  22. {
  23.         struct Book *book, *temp;
  24.        
  25.         book = (struct Book *)malloc(sizeof(struct Book *));  //待插入的项
  26.         if (book == NULL)
  27.         {
  28.                 printf ("很遗憾,内存失败了!\n");
  29.                 exit(1);
  30.         }
  31.        
  32.         getinput(book);
  33.        
  34.         if (*library == NULL) //如果原来的头没有数据
  35.         {
  36.                 *library = book;
  37.                 book->next = NULL;
  38.         }
  39.         else
  40.         {
  41.                 temp = *library; //将temp指向头指针
  42.                 while (temp->next != NULL)
  43.                 {
  44.                         temp = temp->next;  
  45.                 }
  46.                 temp->next = book;
  47.                 book->next = NULL; //book后面的地址指向NULL
  48.         }
  49. }

  50. void printLibrary (struct Book *library)
  51. {
  52.         struct Book *book;
  53.         int count = 1;
  54.        
  55.         book = library;
  56.         while (book != NULL)
  57.         {
  58.                 printf ("Book%d: ", count);
  59.                 printf ("书名:%s ", book->title);
  60.                 printf ("作者:%s\n", book->author);
  61.                 book = book->next;  //类似于 *i++ ,指向下一个结构体
  62.                 count++;
  63.         }
  64. }

  65. void releaseLibrary(struct Book **library)
  66. {
  67.         struct Book *temp;
  68.        
  69.         while (*library != NULL)
  70.         {
  71.                 temp = *library;
  72.                 *library = (*library)->next;  //因为这里我们需要修改指针所指向的地址,所以要从指针的地址下手
  73.                 free(temp);
  74.         }
  75. }

  76. int main(void)
  77. {
  78.         struct Book *library = NULL; //*library就是头号元素
  79.         char ch;
  80.        
  81.         while (1)
  82.         {
  83.                 printf ("请问是否需要录入图书信息:");
  84.                 do
  85.                 {
  86.                         ch = getchar();
  87.                 }while (ch != 'Y' && ch != 'N');
  88.                
  89.                 if (ch == 'N')
  90.                 {
  91.                         break;
  92.                 }
  93.                 if (ch == 'Y')
  94.                 {
  95.                         addBook (&library);
  96.                 }
  97.         }
  98.         printf ("请问是否需要打印图书信息:");
  99.        
  100.         do
  101.         {
  102.                 ch = getchar();
  103.         }while (ch != 'Y' && ch != 'N');
  104.        
  105.         if (ch == 'Y')
  106.         {
  107.                 printLibrary(library);
  108.         }
  109.        
  110.         releaseLibrary(&library); // 清除内存
  111.                
  112.         return 0;
  113. }
复制代码


在这个代码中,我不解的是,我将addBook函数中的部分代码修改了一下,但是结果却截然不同。检查了好几遍,我感觉逻辑上也过得去,语法也没错。希望各位帮帮忙!!!

  1.                 temp = *library; //将temp指向头指针
  2.                 while (temp != NULL) //验证temp的第一个值是不是NULL
  3.                 {
  4.                         temp = temp->next; //如果不是NULL,则给他指向下一个值的地址
  5.                 }
  6.                 temp = book; //将NULL的地址指向新书
  7.                 book->next = NULL; //book后面的地址指向NULL
复制代码

其它代码与原代码完全一致,唯独改了三处。将temp->next 改为了temp.
最佳答案
2020-8-12 11:51:40
科科都不挂 发表于 2020-8-12 18:42
例子能理解,但是涉及到指针,我就有点搞不懂了。
那能帮我解释一下为什么像这样写就能实现呢?而我只是 ...

temp->next=NULL时循环退出,此时是最后一个元素,然后把最后一个元素的指针域指向book这一个节点,这个节点不为NULL,然后再把book->next的指针域初始化为NULL,
你自己写的是当temp->next=NULL时你没有把这个指针去指向新添加的书籍,反而让temp = NULL,也就是一个一个未初始化新的节点,上一本书的指针域并没有指向新添加的书籍,这就导致你的链表永远只有一本书,

最佳答案

查看完整内容

temp->next=NULL时循环退出,此时是最后一个元素,然后把最后一个元素的指针域指向book这一个节点,这个节点不为NULL,然后再把book->next的指针域初始化为NULL, 你自己写的是当temp->next=NULL时你没有把这个指针去指向新添加的书籍,反而让temp = NULL,也就是一个一个未初始化新的节点,上一本书的指针域并没有指向新添加的书籍,这就导致你的链表永远只有一本书,
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 11:51:40 | 显示全部楼层    本楼为最佳答案   
科科都不挂 发表于 2020-8-12 18:42
例子能理解,但是涉及到指针,我就有点搞不懂了。
那能帮我解释一下为什么像这样写就能实现呢?而我只是 ...

temp->next=NULL时循环退出,此时是最后一个元素,然后把最后一个元素的指针域指向book这一个节点,这个节点不为NULL,然后再把book->next的指针域初始化为NULL,
你自己写的是当temp->next=NULL时你没有把这个指针去指向新添加的书籍,反而让temp = NULL,也就是一个一个未初始化新的节点,上一本书的指针域并没有指向新添加的书籍,这就导致你的链表永远只有一本书,
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-8-12 11:53:17 | 显示全部楼层
说错了,只改了两处。将temp->next 改为了temp.
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-8-12 11:56:32 | 显示全部楼层
结果不同在于,原代码可以将所有的书的信息都打印出来,但是我稍微修改后的代码只能打印第一位本书。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 12:13:43 | 显示全部楼层
最后一个元素的指针域还是NULL,没有指向新添加的元素
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 12:26:17 | 显示全部楼层
temp->next == NULL 就是最后一个元素, 它的指针域为NULL 即temp -> next = NULL; 然后继续temp = temp->next, 此时temp = NULL
这样样写直接到最后一个元素之后, 相当于新建一个节点, 最后一个元素的指针域还是NULL, 没有指向新添加的元素
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-8-12 12:46:18 | 显示全部楼层
baige 发表于 2020-8-12 12:26
temp->next == NULL 就是最后一个元素, 它的指针域为NULL 即temp -> next = NULL; 然后继续temp = temp->n ...

谢谢回复!但是我感觉还没答到点上。我可能是哪个理论知识理解错了。可以帮我结合我的代码解释吗?

在我修改后的代码中,我是先让temp的最后一位指向NULL,再将最后一位指向NULL的temp指向新的地址。从逻辑上来看,与老师的例题完全一样。所以我猜是语法错误。望指正!

  1.                 temp = *library; //将temp指向头指针
  2.                 while (temp != NULL) //验证temp的第一个值是不是NULL
  3.                 {
  4.                         temp = temp->next; //如果不是NULL,则给他指向下一个值的地址
  5.                 }
  6.                 temp = book; //将NULL的地址指向新书
  7.                 book->next = NULL; //book后面的地址指向NULL
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 12:55:11 | 显示全部楼层
本帖最后由 baige 于 2020-8-12 13:00 编辑
  1.         struct Book *prew;
  2.     temp = *library; //将temp指向头指针
  3.     while (temp != NULL) //验证temp的第一个值是不是NULL
  4.     {
  5.         prew = temp;
  6.         temp = temp->next; //如果不是NULL,则给他指向下一个值的地址
  7.         }
  8.     temp = book; //将NULL的地址指向新书
  9.     prew->next = temp;// prew->next = book
  10.     book->next = NULL; //book后面的地址指向NULL
复制代码

要这样写就得先记录最后一个元素,在用最后一个元素指针域指向新添加的元素
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 12:56:09 | 显示全部楼层
本帖最后由 baige 于 2020-8-12 13:01 编辑
科科都不挂 发表于 2020-8-12 12:46
谢谢回复!但是我感觉还没答到点上。我可能是哪个理论知识理解错了。可以帮我结合我的代码解释吗?

在 ...


你录入第一本书后,第一本书的指针域永远都是NULL,你并没有去修改它的指针域,去指向新添加的元素,你只是把temp变为NULL,当temp的上一个元素也就是第一本书的指针域还是NULL,也就是最后面的temp跟book没有区别,都是一个节点,没有把第一本书的指针域去指向它
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 13:05:57 | 显示全部楼层
temp->next=NULL时,temp!=NULL,然后就相当于temp = NULL->next,此时temp = NULL, 也就是一个新的节点,第一本书并没有去指向这一个新生成的节点,
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 14:06:53 | 显示全部楼层
我明白了,问题在这里,temp是子函数定义的指针变量,其作用域只在这个函数中使用,而你这里的语句
temp=temp->next,这是单纯的将temp->next赋值给了temp,也就是说temp现在只是存储了temp->next存储的地址,而之后你将book的值赋给temp,并没有对结构体里的next的值进行更改,结构就没有连上,只能显示第一个
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-8-12 15:42:33 | 显示全部楼层
baige 发表于 2020-8-12 12:56
你录入第一本书后,第一本书的指针域永远都是NULL,你并没有去修改它的指针域,去指向新添加的元素,你 ...


那我第七行的temp = book;的作用不是将NULL替换成新书的地址吗?


  1.                 temp = *library; //将temp指向头指针
  2.                 while (temp != NULL) //验证temp的第一个值是不是NULL
  3.                 {
  4.                         temp = temp->next; //如果不是NULL,则给他指向下一个值的地址
  5.                 }
  6.                 temp = book; //将NULL的地址指向新书
  7.                 book->next = NULL; //book后面的地址指向NULL
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 15:45:20 | 显示全部楼层
科科都不挂 发表于 2020-8-12 15:42
那我第七行的temp = book;的作用不是将NULL替换成新书的地址吗?

是,但你第一本书的指针域并没有去指向temp
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-8-12 16:59:54 | 显示全部楼层
baige 发表于 2020-8-12 15:45
是,但你第一本书的指针域并没有去指向temp

这里我把我自己的代码完整放出来吧,第41行和46行是不是将第一本书的指针域给temp呢?
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. void addBook(struct Book **library);
  4. void printLibrary (struct Book *library);
  5. void releaseLibrary(struct Book **library);

  6. struct Book
  7. {
  8.         char title[128];
  9.         char author[40];
  10.         struct Book *next;
  11. };

  12. void getinput(struct Book *book);

  13. void getinput(struct Book *book)
  14. {
  15.         printf ("请输入书名:");
  16.         scanf ("%s", book->title);
  17.        
  18.         printf ("请输入作者:");
  19.         scanf ("%s", book->author);
  20. }

  21. void addBook(struct Book **library) //在这里为什么两个*,即指向指针的指针。因为你要修改的是指针的值,所以你要找到它的地址。
  22. {
  23.         struct Book *book, *temp;
  24.        
  25.         book = (struct Book *)malloc(sizeof(struct Book *));  //待插入的项
  26.         if (book == NULL)
  27.         {
  28.                 printf ("很遗憾,内存失败了!\n");
  29.                 exit(1);
  30.         }
  31.        
  32.         getinput(book);
  33.        
  34.         if (*library == NULL) //如果原来的头没有数据
  35.         {
  36.                 *library = book;
  37.                 book->next = NULL;
  38.         }
  39.         else
  40.         {
  41.                 temp = *library; //将temp指向头指针
  42.                 while (temp != NULL) //验证temp的第一个值是不是NULL
  43.                 {
  44.                         temp = temp->next; //如果不是NULL,则给他指向下一个值的地址
  45.                 }
  46.                 temp = book; //将NULL的地址指向新书
  47.                 book->next = NULL; //book后面的地址指向NULL
  48.         }
  49. }

  50. void printLibrary (struct Book *library)
  51. {
  52.         struct Book *book;
  53.         int count = 1;
  54.        
  55.         book = library;
  56.         while (book != NULL)
  57.         {
  58.                 printf ("Book%d: ", count);
  59.                 printf ("书名:%s ", book->title);
  60.                 printf ("作者:%s\n", book->author);
  61.                 book = book->next;  //类似于 *i++ ,指向下一个结构体
  62.                 count++;
  63.         }
  64. }

  65. void releaseLibrary(struct Book **library)
  66. {
  67.         struct Book *temp;
  68.        
  69.         while (*library != NULL)
  70.         {
  71.                 temp = *library;
  72.                 *library = (*library)->next;  //因为这里我们需要修改指针所指向的地址,所以要从指针的地址下手
  73.                 free(temp);
  74.         }
  75. }

  76. int main(void)
  77. {
  78.         struct Book *library = NULL; //*library就是头号元素
  79.         char ch;
  80.        
  81.         while (1)
  82.         {
  83.                 printf ("请问是否需要录入图书信息:");
  84.                 do
  85.                 {
  86.                         ch = getchar();
  87.                 }while (ch != 'Y' && ch != 'N');
  88.                
  89.                 if (ch == 'N')
  90.                 {
  91.                         break;
  92.                 }
  93.                 if (ch == 'Y')
  94.                 {
  95.                         addBook (&library);
  96.                 }
  97.         }
  98.         printf ("请问是否需要打印图书信息:");
  99.        
  100.         do
  101.         {
  102.                 ch = getchar();
  103.         }while (ch != 'Y' && ch != 'N');
  104.        
  105.         if (ch == 'Y')
  106.         {
  107.                 printLibrary(library);
  108.         }
  109.        
  110.         releaseLibrary(&library); // 清除内存
  111.                
  112.         return 0;
  113. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 17:03:35 | 显示全部楼层
第41行和46行是将第一本书的指针域给temp
你得弄清楚原理,里面本来就什么也没有,你不需要去把前一个指针去指向它,因为它是第一个,但你后面是不一样的,后面要插入时,链表已经有数据了,
但当你要插入时,你就需要把上一本书的指针域去指向新的书
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 17:19:51 | 显示全部楼层
temp和temp->next是不一样的。temp存是一个地址,它肯定存在,只要你不赋为NULL。temp->next是temp地址处的内容里面有一个数据是temp->next。这个数据也是一个地址,和temp相同类型,但是,却是不同的两个变量。它们存的地址也不同。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 17:46:19 | 显示全部楼层
本帖最后由 xiaozhangxuexi 于 2020-8-12 18:16 编辑

这个最好用图来解释,很清楚,可惜不会传图片。这里的temp=book;出了大问题。通过结点可以明白了问题出在哪里。  结点由数据域和指针域两部分组成。要想在链表中添加元素,只要找到链表最后一个结点,该结点的next肯定是NULL,这是只要让next指向book结点即可。 在temp=book;语句前,已经完成了找到最后一个结点的工作。最后一个结点为temp,让temp->next=book;book->next=NULL;即可。但是temp=book; 把最后一个结点temp变成了book; 前面的头指针或者头结点会发现我不认识这个结点,连接不上。链表就被破坏了。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-8-12 18:14:50 | 显示全部楼层
科科都不挂 发表于 2020-8-12 16:59
这里我把我自己的代码完整放出来吧,第41行和46行是不是将第一本书的指针域给temp呢?

举个例子比如我这里有三个变量a,b,c
其中a=1;
c=0;
你让
b=c;
然后你又让
b=a;
这时c的值是几?
c的值毫无疑问还是0,这里你在看看你的程序c就相当于与那个结构体里的next的指针,temp就相当于b,book就相当于a,不知道你明白了吗
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-8-12 18:42:22 | 显示全部楼层
guard99 发表于 2020-8-12 18:14
举个例子比如我这里有三个变量a,b,c
其中a=1;
c=0;

例子能理解,但是涉及到指针,我就有点搞不懂了。
那能帮我解释一下为什么像这样写就能实现呢?而我只是将temp指向第一个NULL,然后再将temp指向book,这是不是相当于将book给NULL呢?
还有,temp = temp->next 的作用是不是将temp指针的地址往后移一个next呢?
  1. temp = *library; //将temp指向头指针
  2.                 while (temp->next != NULL)
  3.                 {
  4.                         temp = temp->next;  
  5.                 }
  6.                 temp->next = book;
  7.                 book->next = NULL; //book后面的地址指向NULL
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-8-12 21:44:42 | 显示全部楼层
baige 发表于 2020-8-12 11:51
temp->next=NULL时循环退出,此时是最后一个元素,然后把最后一个元素的指针域指向book这一个节点,这个 ...

谢谢你,你真的太有耐心了!
temp = NULL,也就是一个一个未初始化新的节点————就是这句话点醒了我!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-7 11:22

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表