Home > other >  Why cant i reallocate my matrix after a certain point?
Why cant i reallocate my matrix after a certain point?

Time:11-20

I am working on a problem, and part of it is storing words in a matrix which i create using malloc().

When I run out of given memory, im supposed to use realloc() and double the memory of my matrix. The code works until i reach 16 capacity, in which case the program exits.

How can i fix this problem? I tried finding the cause, i thought somehow i might have run out of memory but it only works if the capacity comes out exactly to 16. What am i doing wrong?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){


    int cap;
    printf("Give capacity: ");
    scanf("%d", &cap);

    char** matrix = malloc(sizeof(char) * cap); //matrix memory allocation
    for (int i = 0; i < cap;   i)
    {
        matrix[i] = malloc(sizeof(char)*129);
    }

    char tmp_word[129];
    int words = 0;
    int overflow = 0;
    while (fscanf(stdin,"%s",tmp_word) != EOF){  //read from cmd
        matrix[words] = tmp_word;
        words  ;
        printf("words stored: %d, Capacity: %d\n", words, cap);
        if (words == cap){
            printf("Limit reached, reallocating....\n");
            matrix = realloc(matrix, sizeof(char)*2*cap);
            for (int i = 0; i < (cap*2);   i)
            {       
                if (matrix[i] == NULL)
                {
                    printf("Memory reallocation failed due to a lack of memory\n");
                    exit(1);
                }
            }
            printf("1D reallocated\n");
            cap *= 2;   
            printf("Capacity increased\n");
                for (int i = (cap/2); i < cap;   i)
                {
                    matrix[i] = malloc(sizeof(char)*129);
                }
            printf("Succesful reallocation, new capacity: %d\n", cap);
        } 
    }


    for (int i = 0; i < cap;   i)  //free matrix
    {
        free(matrix[i]);
    }
    free(matrix);
    return 0;
}

CodePudding user response:

Unless you are on a very unusual platform where sizeof(char) is not smaller than sizeof(char *), you are writing past the bounds of your array (ie, you didn't allocate enough space). Try:

char** matrix = malloc(sizeof *matrix * cap); //matrix memory allocation

and always check the value returned by malloc. Even if you expect to run on a platform that overcommits memory, it's still best practice to check the return value.

Similarly, your realloc should be:

matrix = realloc(matrix, sizeof *matrix * 2 * cap);

and you should check that allocation as well.

CodePudding user response:

  1. As you always allocate 129 bytes for the string it makes a little sense to use a double pointer. For your use case a flexible structure array member is much more suitable. It simplifies the memory allocation and deallocation (only one realloc and free needed)

  2. It is also not very memory efficient to double the memory amount after every memory overflow. See why - (1)

  3. Use functions for repeated tasks - do not program in the main function. See how it makes code simpler and easier to read.

  4. Use objects not types in sizeof

typedef struct {
  size_t used;
  size_t size;
  char array[][129];
} Array;

#define STEP    64

Array *addString(Array *arr, const char *str)
{
    size_t newsize;
    if(!arr || arr -> size == arr -> used)
    {
        newsize = arr ? arr -> size   STEP : STEP;
        arr = realloc(arr, sizeof(*arr)   newsize * sizeof(arr -> array[0]));
        arr -> size = newsize;
        arr -> used = newsize == STEP ? 0 : arr -> used;
    }
    if(arr)
    {
        strncpy(arr -> array[arr -> used], str, sizeof(arr -> array[0]));
        arr -> array[arr -> used][sizeof(arr -> array[0]) - 1] = 0;
        arr -> used  ;
    } 
    return arr;
}

int main()
{
    Array *matrix = NULL;
    char tmp_word[129];
    int result;
    while ((result = fscanf(stdin,"8s",tmp_word)) != EOF && result == 1)  //read from cmd
    {
        Array *tmp = addString(matrix, tmp_word);
        if(tmp)
        {
            matrix = tmp;
        }
        else
        {
            /* handle memory allocation error */
        }
    }

    free(matrix);
    return 0;
}

(1)

According to legend, chess was invented by Grand Vizier Sissa Ben Dahir, and given as a gift to King Shirham of India. The king was so delighted that he offered him any reward he requested, provided that it sounded reasonable. The Grand Vizier requested the following: "Just one grain of wheat on the first square of a chessboard. Then put two on the second square, four on the next, then eight, and continue, doubling the number of grains on each successive square, until every square on the chessboard is reached." grains on chessboard

Intuitively, King Shirham — just like almost anybody else — underestimated the number of grains and laughed at Sissa because he had asked such a small gift. When he had someone to calculate the total number of grains, it took more than a week before he came back with the solution. King Shirham undoubtedly became very pale when he got the answer: the aggregated number of grains on all squares of a chessboard would be 18.446.744.073.709.551.615 grains. This is the harvest of all the wheat of the world, of several decades.

The story contains an important lesson: people are psychologically bad at dealing with exponential growth. Exponential growth shows an early stage of inertia during which it does not catch the eye. But suddenly, completely unexpected, it shows up like a tsunami, flooding everything and everyone.

  • Related