简体   繁体   中英

Why am I getting a segmentation fault when I try to assign an element from an array to a same type value in my data structure in C?

I'm writing a program that is supposed to assign characters from a buffer into a hash-table. I ran valgrind on my program and it signals to a particular line (tmp->word = buffer[i];) and keeps telling me there is a segmentation fault there.

I tried hardcoding the problem line to (tmp->word = 'c';) but the compiler rejected that implementation. I checked to see if the buffer array was initialized, which it was. The program compiles when the problem line is changed to (tmp->word = buffer[i];) but that leads back to a segmentation fault. I have also tried printing the character field in my data structure after I assign it, but the segmentation fault occurs before that can happen. This is what I've written so far. Any help would be greatly appreciated.

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



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

void unload(node* current);

int main(void)
{
        node* table[26];

        char buffer[5] = "Hello";
        printf("%s\n", buffer);
        int index = tolower(buffer[0]) - 'a';
        node* tmp = table[index];
        for(int i = 0, n = strlen(buffer); i < n - 1; tmp = tmp->next)
        {
            tmp->word = buffer[i];
            printf("%c\n", tmp->word);
            i++;

        }

        //follows word that was input
        index = tolower(buffer[0]) - 'a';
        for(int j = 0; j < 1; j++)
        {
            tmp = table[index]->next;
            unload(tmp);
        }


}

void unload(node* current)
{
    if (current->next != NULL)
        {
            unload(current->next);
        }

    free(current);
}

As is the comments the main problem is an array of uninitialized pointers. As "intuitive way" while you are coding you may think the once you typed node* table[26]; as int type variables, this will be set to NULL automatically as a pattern behavior or something.But it points to a random location in memory when you declare it. It could be pointing into the system stack, or the global variables, or into the program's code space, or into the operating system.

So, you must give them something to point to and in this case is a NULL . You can do it like this node* table[26] = {NULL}; . Another point is when you type char buffer[5] = "Hello"; . The char buffer[5] essentially is a pointer pointing to a memory address that the system saves so you can put your string. The memory is saved in blocks so when you type char buffer[1] for example you "jump" to the second part of the entire block which represents the string.

When you do char buffer[5] = "Hello"; " it's sounds like " you are trying to make the Hello string fit in the last piece of the block. To fix this just type char buffer[6] = {"Hello"}; (Because you need n+1 of size, you have to include the \0 character). And it will fit properly. Now i think you can figure out how to do the rest.

As was mentioned before in the comments and answer, my array of pointers wasn't initialized. This was a part of the main problem I had which was experiencing a segmentation fault when I tried to assign table[i]->word and table[i]->next a value. No memory was allocated for the nodes in the table so I went and did that which fixed most the problems, Something I learned, however, is that I could not assign a string to table[i]->word which is an array of characters in my now less buggy program, and instead had to use strcpy to read a string into that memory space (please correct me if I'm wrong on that). Thank you all for your help and advice, it was really useful, Posted below is the version of my program that actually works save for a conditional that I need to implement thanks to your guys' help! Again, thank you very much!

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

#define LENGTH 45
#define CAPACITY 26

typedef struct node
{
    struct node* next;
    char word[LENGTH + 1];
}
node;

int hash(char* current);
void unload(node* current);


int main(void)
{
    //const unsigned int N = 26;
    node* table[CAPACITY];

    for(int i = 0; i < CAPACITY; i++)
    {
        table[i] = malloc(sizeof(node)); // this was table[i]->next before. I didn't allocate memory for this node and then tried to defrefernce to a field in a node I though existed
        if(table[i] == NULL)
        {
            printf("Could not allocate memory for hashtable node");
            for(int j = 0; j < CAPACITY; j++)
            {
                unload(table[i]);
            }
            return 1;
        }
        table[i]->next = NULL; //just reinitializing the value here so that its not a garbage value
        //table[i]->word = "NULL";
    }

    int q = 0;
    while(q < 3) //ths will be chnaged so that we're reading from a file into a buffer and that get_string is gone, hash() stays tho
    {
        char* name = get_string("Here: ");
        int index = hash(name);

        if(table[index]->next == NULL)
        {
            node* cursor = malloc(sizeof(node)); //I'm not executing this if the hash code is the same
            table[index]->next = cursor;
            strcpy(cursor->word, name);  //for some reason you can't just assign a value to an element in an array in a data structure, seems that you need to read the data you want to assign into the location of the element
            //cursor->word = name;
            cursor->next = NULL;
            printf("%s\n", cursor->word);
        }

        q++;
    }


    for(int i = 0; i < CAPACITY; i++)
    {
        unload(table[i]); //wonder why I don't need to do table[i]->next? does this not free the hash table after the first iteration?
                          // the answer to above is because we are only freeing the node which is that element in the array, not the array itself
    }


        strcpy(table[6]->word, "Zebra");
        printf("%lu\n", sizeof(table[6]));
        printf("%s\n", table[6]->word);

    /*for(int i = 0; i < CAPACITY; i++)
    {
        unload(table[i]); //only problem here is that it will eventually free the hash table itself after the first linked list
    }*/



}

int hash(char* current)
{
    int index = tolower(current[0]) - 'a';
    return index;
}

void unload(node* current)
{
        if (current->next != NULL)
        {
            unload(current->next);
        }

        free(current);

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM