1

I am trying to make my node size dynamically change with the size of the word from the dictionary in the load(dictionary) function.

I understand that the warning means I am trying to assign a pointer to an address to a char array, which is invalid. But how do I access the access the address which new_node->word points to?

UPDATE I changed my code so that it compiles, the changes are in the code and screenshot below

typedef struct node
{
    char word[LENGTH + 1];
    struct node* next;
}
node;
int main(void)
{
    FILE* speller = fopen("dictionary.txt", "r");
    FILE* test = fopen("test.txt", "w");

    while (feof(speller) == 0)
    {
        // malloc a node for each new word
        node* new_node = malloc(sizeof(node));
        fscanf(speller, "%s", new_node->word);

        // resize the node to free the extra memory
        char* temp = realloc(new_node->word, sizeof(*char)*(strlen(new_node->word)+1));
        if (temp == NULL)
        {
            free(new_node);
            printf("could not allocate memory\n");
            break;
        }
        else
        {
            *new_node->word = *temp;
        }

        fwrite(&new_node->word, sizeof(new_node->word), 1, test);

My understanding of it is that new_node->word points to the string from fscanf, and that realloc returns a pointer to the new memory. new_node->word = "hello" accesses the char[46] array, not the address, so I understand why there is an error. But I don't understand how to update the pointer to the memory that stores new_node->word, in the way new_node->next = head assigns a pointer, instead of doing what I am doing and trying to assign an address to a char [46] array.

UPDATE After making the reference to the char pointer *temp equal the reference to the node *new_node->word, I got the code to compile. However, looking through gdb, it still seems that new_node->word is a char * array [46]. Does that mean it did not realloc?
GDB Screenshot

It seems that having a dynamic array size in a struct would be the main cause of the original problem. Is this because in order for a struct to be effective its variables (ie word, node* next) must always be at the same offset in memory from the struct? I'm asking this because I thought about working around by creating a node* next linked to the index after NULL in a char array[strlen(currentstring) + 2], but to find which index has the node* next I'd have to check at each index number, correct? So in other words, this is a limitation of a hashtable, with no solution?

UPDATE I found part of the problem was with the fscanf function, and that I need to use the m modifier to get a char string in my char * pointer. I used the following code:

fscanf(speller, "%ms", &new_node->word);

to get the program to work with my hash function and return the correct index, however I still have an issue with a seg fault now, which I need to resolve. It happens near the end of the z's in my `load' function.

UPDATE

I've gotten the above code to work, the seg fault due to another issue I posted here: Pset6 "Size" giving the wrong output

2
  • 1
    I also have weird issues with strlen(new_node->word) returning the correct value in gdb, but it does not print correctly using fwrite(&new_node->word, sizeof(strlen(new_node->word)), 1, test); If someone could explain this as well in a chat, it's not as important but I'd like to know what's happening – Erin Magner Dec 26 '14 at 21:26
  • Hi Kareem thanks for helping out! I haven't finished trying to work out the dynamic size because I thought I'd have to rewrite the whole program, but I did manage to get the cons *char passed by speller to check into a local char array so I could modify it for my hash function, but I had to loop through each char and set it equal. Like you say, you can set *p = array, but not the other way around. Is my problem mainly because I'm not using strings correctly? – Erin Magner Dec 27 '14 at 22:07
2

You are confusing things here. First, according to the manual page of realloc

Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc().

That is obviously not the case here since

  1. the member word of the struct node is NOT returned by a call to any of these functions (but new_node itself is).
  2. you can't really assign an array to a pointer.

What you're basically doing is that you're allocating memory for a new pointer, namely temp. This has nothing to do with the size of the member word. You then appear to be trying to replace the member word with temp which is not actually possible.

*What you are actually doing here is that you are dereferencing temp (which same thing as temp[0] and storing the resulted in value into *new_node->word (which is the same thing as (new_node->word)[0].

Here's more couple of points

  1. the result of evaluating sizeof(char) is NOT the same as the result of evaluating sizeof(char *). The latter could have the same value as the former multiplied by 4 or 8.
  2. strings are arrays of chars not char *s.
  3. the name of an array by itself is a pointer to the array.
  4. an address of an array is the same as the address of the first element in the array.
  5. dereferencing the name of an array evaluates to the first element of the array.
  6. we don't dereference char * variables to get the string in there because the string in there is actually an array and the name of the char * variable is the name of the array.

Recommendation: you do not appear to be standing on a solid ground when it comes to pointers and the dynamic memory allocation stuff. I recommend you (re-)watch/read the related material and search for answers/ask questions to/about the things that are not very clear to you.


Update: a string is a char array in either cases. It's just that a char * could either point to a char (i.e., a single char) or an array of chars (which could be a string, if it ends with a '\0')

char *p;

char c = 'A';
p = &c; // points to c

char arr[] = {'A', 'B', 'C', 'D'}; // you CANNOT change the size of this array
p = arr; // points to the char array pointed to by arr (and/or arr[0])

sprintf(arr, "bar"); /* arr now stores the string "bar"
                      * arr and p now point to the array {'b', 'a', 'r', '\0'}
                      * notice that I could NOT store a string like "quux"
                      * inside arr because it's of size 4 only */

printf("%c\n", p[2]); // prints 'r'
printf("%c\n", *p); // prints 'b'
printf("%c\n", p[0]); // prints 'b'

p = "foo"; // points to the CONSTANT array {'f', 'o', 'o', '\0'}

A variable of type char [], on the other hand is declared to be an array of chars. And since you cannot change the type of a declared variable, it is not possible for arr in the previous example to be of the same type as c or p even though the result of evaluating arr could be treated as a char *. However, you cannot do something like

/* COMPILE-TIME ERRORS */

// arr = NULL; 
// arr = malloc(sizeof(char));
// arr = {'X', 'Y', 'Z'};

which would be perfectly valid for p.

I guess it's pretty obvious now why you don't need to dereference char * variables that point to strings to get the strings that they point to. And be careful, a string array is NOT a char array nor a string.

If you want to use malloc, calloc or realloc, maybe you should declare word as a char *.

2
  • Thank you for being so helpful! When I was looking "under the hood", a char* string created by malloc or calloc was not a char[array], which you've explained nicely. If I use a char* for my word variable to realloc for each string, I can't dereference char* in my struct for my hash. new_node->word instead returns an address, because it is a pointer. But it is also a string array at that address. How would you dereference a pointer to a pointer within a struct? I tried *new_node->word but no luck. Do I need to try harder? Will realloc array never be an array? – Erin Magner Dec 27 '14 at 16:19
  • @ErinMagner updated my answer! – kzidane Dec 27 '14 at 21:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .