[英]C pointers, inserting elements to HEAD of linked list
我正在处理K&R书(#6.3)中的一个问题,在该问题中,用户输入了一个单词序列,您必须创建这些单词的列表以及每个单词出现的行。 它应该涉及结构,所以这些是我现在拥有的结构:
struct entry {
int line;
int count;
struct entry *next;
};
struct word {
char *str;
struct entry *lines;
struct word *next;
};
static struct word *wordlist = NULL; // GLOBAL WORDLIST
但是,当我输入一些东西并且程序尝试向结构中添加新条目(有点像链表)时,出现了问题,程序终止,没有错误消息。 为此的代码:
void add_entry(char *word, int line)
{
if (word == NULL || line <= 0 || is_blocked_word(word))
return;
struct word *w;
for (w = wordlist; w != NULL && w->next != NULL && !strcmp(w->str, word); w = w->next);
// If word is found in the wordlist, then update the entry
if (w != NULL) {
struct entry *v;
for (v = w->lines; v != NULL && v->next != NULL && v->line != line; v = v->next);
if (v == NULL) {
struct entry *new = (struct entry*) malloc(sizeof(struct entry));
new->line = line;
new->count = 1;
new->next = NULL;
if (w->lines == NULL)
w->lines = new;
else
v->next = new;
}
else v->count++;
}
// If word is not found in the word list, then create a new entry for it
else {
struct word *new = (struct word*) malloc(sizeof(struct word));
new->lines = (struct entry*) malloc(sizeof(struct entry));
new->next = NULL;
new->str = (char*) malloc(sizeof(char) * strlen(word));
new->lines->line = line;
new->lines->count = 1;
new->lines->next = NULL;
strcpy(new->str, word);
// If the word list is empty, then populate head first before populating the "next" entry
if (wordlist == NULL)
wordlist = new;
else
w->next = new;
}
}
即使仅将第一个单词添加到wordlist
该程序也会终止。 这是说if (wordlist == NULL) wordlist = new;
其中new
包含指向我分配的有效结构的指针。 这怎么可能?
据我所知,这是我的指针使用问题,但是我不确定它到底在哪里。 有人可以帮忙吗?
一些相当明显的东西,还有一些不太明显的东西。
w
的for循环限制停止一小段
for (w = wordlist; w != NULL && w->next != NULL && !strcmp(w->str, word); w = w->next);
这将从第一个开始,一直持续到
几乎相同的问题,不同的for循环
for (v = w->lines; v != NULL && v->next != NULL && v->line != line; v = v->next);
如上所述,它具有相似的属性(但第三个选项没有,因为只要行号不匹配,它就可以正确继续。只要任何单词不匹配,先前的循环就会中断。
这就是该函数的前十行。
字符串分配大小无法说明nulchar终止符
这不足以零终止的字符串所需的分配大小的一个字符:
malloc(sizeof(char) * strlen(word))
终结者总是需要空间。 最简单的方法是考虑零长度C字符串需要多少个字符? 答案:一,因为终结者需要去某个地方。 之后就是length+1
一种可行的方法是通过指针对指针方法,如下所示:
void add_entry(const char *word, int line)
{
if (word == NULL || line <= 0 || is_blocked_word(word))
return;
struct word **pp = &wordlist;
for (; *pp && strcmp((*pp)->str, word); pp = &(*pp)->next);
if (*pp)
{
// search for matching line number
struct entry **vv = &(*pp)->lines;
for (; *vv && (*vv)->line != line; vv = &(*vv)->next);
if (!*vv)
{
*vv = malloc(sizeof(**vv));
if (!*vv)
{
perror("Failed to allocate line entry.");
exit(EXIT_FAILURE);
}
(*vv)->count = 1;
(*vv)->line = line;
(*vv)->next = NULL;
}
else
{ // found an entry. increment count.
(*vv)->count++;
}
}
else
{ // no matching word. create a new word with a new line entry
size_t len = strlen(word);
*pp = malloc(sizeof(**pp));
if (!*pp)
{
perror("Failed to allocate word entry.");
exit(EXIT_FAILURE);
}
(*pp)->lines = malloc(sizeof(*(*pp)->lines));
if (!(*pp)->lines)
{
perror("Failed to allocate line count entry.");
exit(EXIT_FAILURE);
}
(*pp)->str = malloc(len + 1);
if (!(*pp)->str)
{
perror("Failed to allocate word string entry.");
exit(EXIT_FAILURE);
}
(*pp)->lines->count = 1;
(*pp)->lines->line = line;
(*pp)->lines->next = NULL;
(*pp)->next = NULL;
memcpy((*pp)->str, word, len+1);
}
}
这个怎么运作
在这两种情况下,我们都使用指针到指针。 当需要在链表上执行尾端插入而不必保留“单向”或“上一个”指针时,它们是最常用的构造。 就像任何指针一样,它们拥有一个地址。 与常规指向某物的指针不同,指向某物的指针保存另一个指针的地址。 有了它,我们可以通过将其初始设置为头部指针的地址(进入搜索)来“循环”。
struct word **pp = &wordlist;
for (; *pp && strcmp((*pp)->str, word); pp = &(*pp)->next);
在这里,我们从头指针的地址开始。 如果pp
保存的地址的指针为NULL,或者该单词实际匹配,则循环将终止。 否则,它设置的地址(而不是地址) next
我们跑出去的话,从来没有找到匹配的循环将打破目前node.If的指针,但有一个最方便的后果: pp
包含的地址我们需要设置为新分配的指针。 如果列表最初是空的, 则包含头指针的地址。
这样,我们可以执行以下操作:
if (*pp)
{
// search for matching line number
struct entry **vv = &(*pp)->lines;
for (; *vv && (*vv)->line != line; vv = &(*vv)->next);
注意,我们在行输入列表中使用了相同的想法。 我们要么找到一个条目,要么循环将以*vv
为NULL
退出,并且vv
包含我们要设置为新分配的next
指针的地址。
我强烈建议您逐行调试器中的代码,并了解其工作原理。 利用这种技术具有许多可赎回的品质,其中包括一种非常简单的方法,即以O(n)
复杂度填充前向链接列表, 而不必为每次插入检查头指针或遍历列表并保持原始顺序(相对而言)将顺序颠倒为堆栈式解决方案):
struct node *head = NULL;
struct node **pp = &head;
while (get-data-for-our-list)
{
*pp = malloc(sizeof(**pp));
// TODO: populate (*pp)->members here
pp = &(*pp)->next;
}
*pp = NULL;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.