【问题标题】:Linked List - C - correctly access value of a struct node from an array of node pointers链表 - C - 从节点指针数组中正确访问结构节点的值
【发布时间】:2014-04-11 04:20:38
【问题描述】:

第一次发帖,编码知识极其有限,刚接触C。要温柔!我正处于“尝试”不同的事情让我越来越困惑的地步。我需要有人正确的指导!

这个特殊的问题来自我正在尝试的在线 edX 课程,当正确实施时,最终会检查从文本文件中读入的给定单词(“检查”功能)并将其与读入的每个单词进行比较(来自 ' load' 函数)结构的链接列表。

我相信我在使用 gdb 时正确实现了加载功能,因为我在逐步完成它时看到了我的预期,但我的问题和我的问题与检查功能特别相关。我还有很多东西要完成我的代码,但是在使用 gdb 进行测试时,我没有看到结构的 char* 成员的值与我预期应该看到的一致。

  1. 当使用 gdb 并单步执行“检查”函数并尝试访问我在加载函数中创建的链表中结构节点的 dword 成员时,我预计应该会看到 char* 成员的字符串.例如,我预计将“猫”一词分配给 current->dword ,但在我测试时却在 gdb 中看到:

    ~(gdb) 打印当前->dword

    $13 = 0xbffffede2 "\004\b\214\365\372D\300\355\377\277"

我的想法是我仍然只是以某种方式访问​​地址而不是实际值,但我不知道为什么会这样。在加载函数中创建节点时,会正确地为 dword 成员分配一个值(至少据我在单步执行 gdb 中的代码时所知),但在检查中似乎没有正确访问功能。对新手的任何帮助将不胜感激!

    #include <ctype.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include "dictionary.h"

    typedef struct node
    {
        char* dword;
        struct node* next;
    }
    node;

    // keep track of #of words in dictionary loaded
    int wordCounter = 0;

    // create root for hash table
    node* root[26];

    // create cursor to keep place in creating, pointing, and traversing through nodes
    node* current = NULL;

    /**
     * Returns true if word is in dictionary else false.
     */
    bool check(const char* word)
    {
        // size of word read into buffer
        int wordSize = sizeof(word);

        // prepare to make a new lowercase only word for comparison to lowercase only dictionary
        char bufWord[wordSize];

        // make it
        for(int i = 0; i < wordSize; i++)
        {   
            if (i == wordSize - 1)
            {
                bufWord[i] = '\0';
            }

            else
            {
                bufWord[i] = tolower(word[i]);
            }
        }

        // hash word to achieve proper root node location
        int hash = bufWord[0] - 97;

        // point to the correct root node to begin traversing
        current = root[hash];

        // make sure there is even a word in hash table location
        if(root[hash] == NULL)
        {
            return false;
        }

        else if(root[hash] != NULL)
        {
            // progress through the nodes until the last node's next pointer member is NULL
            while(current != NULL)
            {
                // compare 1st letter only of current->dword[i] to bufWord[i] to save time

                    // if they don't match, return false

                    // if they do match then continue
    \
                char dictWord[wordSize];

                // hold copy of struct member value to compare to dictWord
                char* wordTemp = current->dword;

                // 
                for(int i = 0; i < wordSize; i++)
                {   
                    dictWord[i] = wordTemp[i];
                }

                // do a spell check
                if(strcmp(bufWord, dictWord) == 0)
                {
                    return true;
                }

                else
                {
                    // set current to the next node if any or NULL if it's already the last node in the list
                    current = current->next;
                }
            }    
        }

        return false;
    }

    /**
     * Loads dictionary into memory.  Returns true if successful else false.
     */
    bool load(const char* dictionary)
    {   
        // buffer for reading in dictionary words
        char wordIn[LENGTH + 1];

        // open the dictionary file
        FILE* newDict = fopen(dictionary, "r");

        for (int i = 0; i < 27; i++)
        {
            root[i] = NULL;
        }

        // while there are words to read
        while(fscanf(newDict, "%s ", wordIn) > 0)
        {

            // keep track of #of words for constant time read in size function
            wordCounter++;

            // hash the first letter for the location in root
            int hash = wordIn[0] - 97;

            // malloc space for a new node
            node* newNode = malloc(sizeof(node));

            // error check
            if (newNode == NULL)
            {
                return false;
            }

            // set value member of node to current word
            newNode->dword = wordIn;

            // first insertion into linked list if that root node has not been used yet 
            if(root[hash] == NULL)
            {
                // sets to NULL
                newNode->next = root[hash];

                // link it
                root[hash] = newNode;
            }

            else if(root[hash] != NULL)
            {
                // starts at the root
                node* current = root[hash];

                // insert into new beginning of list
                newNode->next = current;
                root[hash] = newNode;
            }
        }

        fclose(newDict);
        return true;
    }

    /**
     * Returns number of words in dictionary if loaded else 0 if not yet loaded.
     */
    unsigned int size(void)
    {
        return wordCounter;
    }

    /**
     * Unloads dictionary from memory.  Returns true if successful else false.
     */
    bool unload(void)
    {
        // TODO
        return false;
    }

【问题讨论】:

    标签: c linked-list


    【解决方案1】:

    你的问题的根源是这一行:

    newNode->dword = wordIn;
    

    wordInload 中的一个本地数组。您将wordIn 的地址存储在节点的dword 中。当您从load 返回时,这些地址不再有效。

    你需要做的是为wordIn中的字符串分配内存,将分配的内存分配给newNode-&gt;dword并将wordIn的内容复制到newNode-&gt;dword

    如果您的平台提供了非标准功能strdup,您可以将上面的行改为:

    newNode->dword = strdup(wordIn);
    

    如果没有,很容易实现:

    char* strdup(char const* in)
    {
       char* r = malloc(strlen(in)+1);
       strcpy(r, in);
       return r;
    }
    

    【讨论】:

    • 另一个问题是int wordSize = sizeof(word);,它给出了指针的大小,而不是它指向的字符串的长度。 strlen 是您所需要的。
    • 感谢 R Sahu 提供的信息。所以应该分配空间来保存读入wordIn 的每个字符*,然后如果我正确理解您的答案,该词将分配给newNode-&gt;sword?出现了几个问题。我的第一直觉是,似乎为每个 char* 分配了两次内存(一次将其读入wordIn,然后再次在结构newNode 中保存相同的值)。它是否正确?如果是这样,我是否可以将wordIn 声明为全局变量,然后将每次读入wordIn 的值简单地分配给每个节点的newNode-&gt;sword
    • 感谢 Retired Ninja 发现我的 sizeof 错误。在下午剩下的时间里,我的脸上都有一个手掌印。那是一个我应该抓住的简单的,但一直盯着我的脸! :)
    • @wertytrew 对问题 1 的回答:是的。对 Q2 的回答:否。wordIn 的内存在堆栈上分配,并在循环中的每次迭代中重复使用。当您将字符串读入wordIn 时,并未为其分配新内存。
    猜你喜欢
    • 1970-01-01
    • 2020-05-10
    • 2020-05-09
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多