指针指向 NULL 指针
A pointer points to a NULL pointer
cs50哈佛处理链表课程的代码:
---我不明白的问题是,当节点*ptr指向数字时,它是一个空指针,for循环怎么能:(节点*ptr =数字; ptr!= NULL)运行因为 *numbers = NULL?---
完整版代码可在以下位置找到:https://cdn.cs50.net/2017/fall/lectures/5/src5/list2.c
#include <cs50.h>
#include <stdio.h>
typedef struct node
{
int number;
struct node *next;
}
node;
int main(void)
{
// Memory for numbers
node *numbers = NULL;
// Prompt for numbers (until EOF)
while (true)
{
// Prompt for number
int number = get_int("number: ");
// Check for EOF
if (number == INT_MAX)
{
break;
}
// Check whether number is already in list
bool found = false;
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
{
if (ptr->number == number)
{
found = true;
break;
}
}
如果您检查也在 while
循环中的其余代码,您可以在共享 link.
上看到 numbers
的更改
if (!found)
{
// Allocate space for number
node *n = malloc(sizeof(node));
if (!n)
{
return 1;
}
// Add number to list
n->number = number;
n->next = NULL;
if (numbers)
{
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
{
if (!ptr->next)
{
ptr->next = n;
break;
}
}
}
else
{
numbers = n;
}
}
此外,它一开始并没有命中for
循环体,所以你的想法是正确的。
该循环用于检查正在构建的列表中是否存在先前存在。如果不存在(found
从未设置为真),则剩余的不方便省略的代码会将其添加到列表中。
初始运行时,numbers
链表头指针为空,表示空表。这不会改变 search + if-not-found-insert 的算法。这只是意味着永远不会进入循环,因为 bail-case 立即为真。换句话说,numbers
为 NULL
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
继续的条件,ptr != NULL
已经为假,所以for-loop的body就直接跳过了。这导致您没有执行实际插入的其余代码 post。插入之后,列表现在有了一些东西,outer-while 循环的下一次迭代最终将在读取下一个预期值后再次扫描列表。这一直持续到不再满足 outer-while 条件。
不同的方法
我从来没有喜欢cs50开发策略,以及哈佛教授C语言给entry-level CS学生的技巧。 cs50
header 和 lib 对 real-world 软件工程造成的过渡性混乱超出了人们的想象。下面是读取值链接列表的替代方法,只保留唯一条目。它可能看起来很多,但其中一半是描述正在发生的事情的内嵌注释。其中一些看起来微不足道,但 search-and-insert 方法才是您应该关注的。它使用了您可能不熟悉的 pointer-to-pointer 策略,这是一个很好的曝光。
尽情享受吧。
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node *next;
};
int main()
{
struct node *numbers = NULL;
int value = 0;
// retrieve list input. stop when we hit
// - anything that doesn't parse as an integer
// - a value less than zero
// - EOF
while (scanf("%d", &value) == 1 && value >= 0)
{
// finds the address-of (not the address-in) the first
// pointer whose node has a value matching ours, or the
// last pointer in the list (which points to NULL).
//
// note the "last" pointer will be the head pointer if
// the list is empty.
struct node **pp = &numbers;
while (*pp && (*pp)->value != value)
pp = &(*pp)->next;
// if we didn't find our value, `pp` holds the address of
// the last pointer in the list. Again, not a pointer to the
// last "node" in the list; rather the last actual "pointer"
// in the list. Think of it as the "next" member of last node,
// and in the case of an empty list, it will be the address of
// the head pointer. *That* is where we will be hanging our
// new node, and since we already know where it goes, there is
// no need to rescan the list again.
if (!*pp)
{
*pp = malloc(sizeof **pp);
if (!*pp)
{
perror("Failed to allocate new node");
exit(EXIT_FAILURE);
}
(*pp)->value = value;
(*pp)->next = NULL;
}
}
// display entire list, single line
for (struct node const *p = numbers; p; p = p->next)
printf("%d ", p->value);
fputc('\n', stdout);
// free the list
while (numbers)
{
struct node *tmp = numbers;
numbers = numbers->next;
free(tmp);
}
return EXIT_SUCCESS;
}
这种方法在构建 sorted 列表时特别方便,因为只需进行一些更改即可更改它。
cs50哈佛处理链表课程的代码: ---我不明白的问题是,当节点*ptr指向数字时,它是一个空指针,for循环怎么能:(节点*ptr =数字; ptr!= NULL)运行因为 *numbers = NULL?---
完整版代码可在以下位置找到:https://cdn.cs50.net/2017/fall/lectures/5/src5/list2.c
#include <cs50.h>
#include <stdio.h>
typedef struct node
{
int number;
struct node *next;
}
node;
int main(void)
{
// Memory for numbers
node *numbers = NULL;
// Prompt for numbers (until EOF)
while (true)
{
// Prompt for number
int number = get_int("number: ");
// Check for EOF
if (number == INT_MAX)
{
break;
}
// Check whether number is already in list
bool found = false;
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
{
if (ptr->number == number)
{
found = true;
break;
}
}
如果您检查也在 while
循环中的其余代码,您可以在共享 link.
numbers
的更改
if (!found)
{
// Allocate space for number
node *n = malloc(sizeof(node));
if (!n)
{
return 1;
}
// Add number to list
n->number = number;
n->next = NULL;
if (numbers)
{
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
{
if (!ptr->next)
{
ptr->next = n;
break;
}
}
}
else
{
numbers = n;
}
}
此外,它一开始并没有命中for
循环体,所以你的想法是正确的。
该循环用于检查正在构建的列表中是否存在先前存在。如果不存在(found
从未设置为真),则剩余的不方便省略的代码会将其添加到列表中。
初始运行时,numbers
链表头指针为空,表示空表。这不会改变 search + if-not-found-insert 的算法。这只是意味着永远不会进入循环,因为 bail-case 立即为真。换句话说,numbers
为 NULL
for (node *ptr = numbers; ptr != NULL; ptr = ptr->next)
继续的条件,ptr != NULL
已经为假,所以for-loop的body就直接跳过了。这导致您没有执行实际插入的其余代码 post。插入之后,列表现在有了一些东西,outer-while 循环的下一次迭代最终将在读取下一个预期值后再次扫描列表。这一直持续到不再满足 outer-while 条件。
不同的方法
我从来没有喜欢cs50开发策略,以及哈佛教授C语言给entry-level CS学生的技巧。 cs50
header 和 lib 对 real-world 软件工程造成的过渡性混乱超出了人们的想象。下面是读取值链接列表的替代方法,只保留唯一条目。它可能看起来很多,但其中一半是描述正在发生的事情的内嵌注释。其中一些看起来微不足道,但 search-and-insert 方法才是您应该关注的。它使用了您可能不熟悉的 pointer-to-pointer 策略,这是一个很好的曝光。
尽情享受吧。
#include <stdio.h>
#include <stdlib.h>
struct node
{
int value;
struct node *next;
};
int main()
{
struct node *numbers = NULL;
int value = 0;
// retrieve list input. stop when we hit
// - anything that doesn't parse as an integer
// - a value less than zero
// - EOF
while (scanf("%d", &value) == 1 && value >= 0)
{
// finds the address-of (not the address-in) the first
// pointer whose node has a value matching ours, or the
// last pointer in the list (which points to NULL).
//
// note the "last" pointer will be the head pointer if
// the list is empty.
struct node **pp = &numbers;
while (*pp && (*pp)->value != value)
pp = &(*pp)->next;
// if we didn't find our value, `pp` holds the address of
// the last pointer in the list. Again, not a pointer to the
// last "node" in the list; rather the last actual "pointer"
// in the list. Think of it as the "next" member of last node,
// and in the case of an empty list, it will be the address of
// the head pointer. *That* is where we will be hanging our
// new node, and since we already know where it goes, there is
// no need to rescan the list again.
if (!*pp)
{
*pp = malloc(sizeof **pp);
if (!*pp)
{
perror("Failed to allocate new node");
exit(EXIT_FAILURE);
}
(*pp)->value = value;
(*pp)->next = NULL;
}
}
// display entire list, single line
for (struct node const *p = numbers; p; p = p->next)
printf("%d ", p->value);
fputc('\n', stdout);
// free the list
while (numbers)
{
struct node *tmp = numbers;
numbers = numbers->next;
free(tmp);
}
return EXIT_SUCCESS;
}
这种方法在构建 sorted 列表时特别方便,因为只需进行一些更改即可更改它。