Search code examples
ctokenizedynamic-memory-allocationdouble-pointer

dynamic allocate double pointer in c


This question is a continuation of this question.

Here's the code:

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

int main(void)
{
    int ch;
    char *ptrChFromFile;
    char **ptrWords;
    int strSize = 1;
    int i;
    int j = 0;
    int numberOfWords = 1;

    ptrChFromFile = malloc(sizeof(char));

    if (ptrChFromFile == NULL)
    {
        puts("COULDN'T ALLOICATE MEMORY");
        exit(EXIT_FAILURE);
    }

    while ((ch = getchar()) != '\n')
    {
        ptrChFromFile = realloc(ptrChFromFile, (strSize+1) * sizeof(char));

        if (ptrChFromFile == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }

        if (ch == ' ')
        {
            numberOfWords++;
        }

        ptrChFromFile[strSize] = ch;
        strSize++;
    }

    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptr

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
    {
        ptrWords[i] = malloc(sizeof(char*)* strSize);
        if (ptrWords[i] == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < strSize; i++)
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j] = &ptrChFromFile[i];
        }
        else
        {
            ptrWords[j] = 0;
            j++;
        }
    }

    for (i = 0; i < numberOfWords; i++) // free's each slot in ptrWords
    {
        free(ptrWords[i]);
    }

    free(ptrChFromFile);
    free(ptrWords);
    return 0;
}

I am trying to dynamically allocate my double char pointer ptrWords. Allow me to explain my thought process:

ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptr

This creates the number of slots (indices) in ptrWords. so if I have 3 words ptrWords should look like this:

ptrWords[index 0]

ptrWords[index 1]

ptrWords[index 2]

for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
{
    ptrWords[i] = malloc(sizeof(char*)* strSize);
    if (ptrWords[i] == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }
}

This for loop allocates memory to each slot in ptrWords equal to the total number of characters in the input file. So if the input file has 26 total characters for example then each slot in ptrWords will have 26 bytes allocated to it.

ptrWords[index 0] has 26 bytes of memory

ptrWords[index 1] has 26 bytes of memory

ptrWords[index 2] has 26 bytes of memory

I think my memory allocation of ptrWords is correct, but I am not sure.

for (i = 0; i < strSize; i++)
{
    if (ptrChFromFile[i] != ' ')
    {
        ptrWords[j] = &ptrChFromFile[i];
    }
    else
    {
        ptrWords[j] = 0;
        j++;
    }
}

This for loop is supposed to take the characters from ptrChFromFile and store them in ptrWords as separate words. My logic with loop is as follows:

1) As long as ch does not equal a space take that character and store it at the first position (index 0) of ptrWords.

2) if ch does equal a space then place a terminating character ('\0') in its place then increment j by 1 to move to the next index in ptrWords to store the next word.

I have used a debugger to step through the code, but I still can't figure out whats wrong, so any help would be appreciated.

Thank you


My implementation:

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

int main(void)
{
    int ch;
    char *ptrChFromFile;
    char **ptrWords;
    int strSize = 1;
    int i;
    int j = 0;
    int k = 0;
    int numberOfWords = 1;

    ptrChFromFile = malloc(sizeof(char));

    if (ptrChFromFile == NULL)
    {
        puts("COULDN'T ALLOCATE MEMORY");
        exit(EXIT_FAILURE);
    }

    while ((ch = getchar()) != '\n')
    {
        ptrChFromFile = realloc(ptrChFromFile, (strSize+1) * sizeof(char));

        if (ptrChFromFile == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }

        if (ch == ' ')
        {
            numberOfWords++;
        }

        ptrChFromFile[strSize] = ch;
        strSize++;
    }

    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptrWords

    for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
    {
        ptrWords[i] = malloc(sizeof(char*)* strSize);
        if (ptrWords[i] == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    }

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < strSize; i++)
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j][k++] = ptrChFromFile[i];
        }
        else
        {
            ptrWords[j][k] = 0;
            ptrWords[j] = realloc(ptrWords[j], k+1);
            j++;
            k = 0;
        }
    }
    printf("%s", ptrWords[0]);

    free(ptrChFromFile);
    free(ptrWords);

    return 0;
}

sample input: "hey there"

output: hey there

¿hey


Current version of code:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int getStrLength(char *word)
{
    int lengthOfWord = 0;
    int i;

    for (i = 0; word[i] != 0; i++)
    {
        lengthOfWord++;
    }
    return lengthOfWord;
}

int compareWords(char *firstWord, char *secondWord)
{
    while (*firstWord && *firstWord == *secondWord)
    {
        firstWord++;
        secondWord++;
    }
    return *firstWord - *secondWord;
}

int main(void)
{
    int ch;
    char *ptrChFromFile;
    char **ptrWords;
    char **ptrCrunchWord;
    int strSize = 0;
    int i;
    int j = 0;
    int k = 0;
    int numberOfWords = 0;
    int defaultWordLength = 6;

    srand(time(0)); // Use current time as seed for random generator

    ptrChFromFile = malloc(sizeof(char));

    if (ptrChFromFile == NULL)
    {
        puts("COULDN'T ALLOCATE MEMORY");
        exit(EXIT_FAILURE);
    }

    while ((ch = getchar()) != '\n') // this reads in chars from file to ch variable
    {
        ptrChFromFile = realloc(ptrChFromFile, (strSize+1) * sizeof(char));

        if (ptrChFromFile == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }

        if (ch == ' ')
        {
            numberOfWords++;
        }

        ptrChFromFile[strSize] = ch;
        strSize++;
    }

    numberOfWords++;
    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptrWords

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
    {
        ptrWords[i] = malloc(strSize);
        if (ptrWords[i] == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < strSize; i++) // This inserts words in ptrWords separated by spaces.
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j][k++] = ptrChFromFile[i];
        }
        else
        {
            ptrWords[j][k] = 0;
            ptrWords[j] = realloc(ptrWords[j], k+1);
            j++;
            k = 0;
        }
    }
    // terminate and resize last word
    ptrWords[j][k] = 0;
    ptrWords[j] = realloc(ptrWords[j], k+1);
    j = 0;
    k = 0;

    // crunchWord code starts here:
      ptrCrunchWord = malloc(sizeof(char*));
      ptrCrunchWord[0] = malloc(strSize);

      if (ptrCrunchWord == NULL || ptrCrunchWord[0] == NULL)
       {
           puts("failed to allocate memory");
           exit(EXIT_FAILURE);
       }


    for (i = 0; i < numberOfWords; i++)
    {
        int randomIndex = rand() % numberOfWords;

    if (compareWords(ptrCrunchWord[i], ptrWords[randomIndex]) != 0) 
    {
        if (getStrLength(ptrWords[randomIndex]) >= defaultWordLength) 
        {
            ptrCrunchWord[i] = ptrWords[randomIndex]; // main problem here
        }
    }
}

    printf("The crunch word is: %s", ptrCrunchWord[0]);


    for (i = 0; i < numberOfWords; i++) // Free's allocated memory from all pointers
    {
        free(ptrWords[i]);
    }

    free(ptrChFromFile);
    free(ptrWords);
    free(ptrCrunchWord[0]);
    free(ptrCrunchWord);

    return 0;
}

This is the most current code. The last thing I need to do is store all words that are greater than or equal to six in ptrCrunchWord. My main issue is allocating space in ptrCrunchWord[0] for the final crunch word and storing the words in index 0. I am only allocating space for the element because there will be only one word stored in ptrCrunchWord. I have written two methods one checks the length of each word and the other method compares two words to see if they are the same. Finally, I need to print the crunch word with no spaces.

Thank you


Solution

  • This loop is wrong:

    for (i = 0; i < strSize; i++)
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j] = &ptrChFromFile[i];
        }
        else
        {
            ptrWords[j] = 0;
            j++;
        }
    }
    

    You shouldn't be reassigning ptrWords[j], you should copy into the memory you allocated in the previous loop. You need another variable k to hold the index you're assigning in the destination array.

    int k = 0;
    for (i = 0; i < strSize; i++)
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j][k++] = ptrChFromFile[i];
        }
        else
        {
            ptrWords[j][k] = 0;
            j++;
            k = 0;
        }
    }
    

    You also went way overboard in the amount of memory you assigned for ptrWords. Each word has as many characters allocated as the entire size of the file. When you reach the end of each word, after assigning ptrWords[j][k] = 0 you can shrink that allocation to the size of the word with:

    ptrWords[j] = realloc(ptrWords[j], k+1);
    

    Another problem is that you initialized strSize = 1;. That's causing you to put the first character of the input into ptrChFromFile[1] instead of ptrChFromFile[0], so the first word doesn't get copied correctly. It should be initialized as int strSize = 0. But to adjust for this change, you need to increase all the ptrChFromFile allocations by 1 character (or do another realloc at the end to add space for the trailing null).

    When you're allocating the memory for ptrWords[i], you shouldn't multiply by sizeof(char *). ptrWords is an array of pointers, ptrWords[i[ is an array of char.

    After you finish the loop that reads the initial input into ptrChFromFile, you need to increment numberOfWords. Otherwise you won't count the last word before the newline.

    You shouldn't have removed the loop at the end that frees all the ptrWords[i]. Anything you allocate with malloc needs to be freed.

    Here's the working version:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
        int ch;
        char *ptrChFromFile;
        char **ptrWords;
        int strSize = 0;
        int i;
        int j = 0;
        int k = 0;
        int numberOfWords = 1;
    
        ptrChFromFile = malloc(2);
    
        if (ptrChFromFile == NULL)
        {
            puts("COULDN'T ALLOCATE MEMORY");
            exit(EXIT_FAILURE);
        }
    
        while ((ch = getchar()) != '\n')
        {
            ptrChFromFile = realloc(ptrChFromFile, (strSize+2));
    
            if (ptrChFromFile == NULL)
            {
                puts("failed to allocate memory");
                exit(EXIT_FAILURE);
            }
    
            if (ch == ' ')
            {
                numberOfWords++;
            }
    
            ptrChFromFile[strSize] = ch;
            strSize++;
        }
        numberOfWords++; // increment for last word
    
        ptrChFromFile[strSize] = 0;
    
        ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptrWords
    
        for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
        {
            ptrWords[i] = malloc(strSize);
            if (ptrWords[i] == NULL)
            {
                puts("failed to allocate memory");
                exit(EXIT_FAILURE);
            }
        }
    
        if (ptrWords == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    
        for (i = 0; i < strSize; i++)
        {
            if (ptrChFromFile[i] != ' ')
            {
                ptrWords[j][k++] = ptrChFromFile[i];
            }
            else
            {
                ptrWords[j][k] = 0;
                ptrWords[j] = realloc(ptrWords[j], k+1);
                j++;
                k = 0;
            }
        }
        printf("%s\n", ptrWords[0]);
    
        for (i = 0; i < strSize; i++) {
            free(ptrWords[i]);
        }
        free(ptrChFromFile);
        free(ptrWords);
    
        return 0;
    }