2013-10-06 2 views
0

Я пытаюсь перераспределить массив структур, когда у него заканчивается пространство, когда я помещаю в него элементы, но я продолжаю получать realloc stderr. Массив структуры в конечном итоге будет содержать 235 000 элементов. Когда я устанавливаю начальный размер начала до 100 000, я получаю stderr при попытке перераспределения. Если размер первоначального запуска до 300 000, он не дает ошибку, потому что он никогда не достигает инструкции realloc.Array of Structs memory realloc stderr

#define _XOPEN_SOURCE 
#include <stdlib.h> 
#include <stdio.h> 
#include <assert.h> 
#include <string.h> 

#define BUFFERLEN 200 
#define START_SIZE 100000 
#define GROW 1000 
#define TRUE 1 
#define FALSE 0 

typedef struct{ 
    char *forw; 
    char *back; 
} word; 

typedef struct{ 
    char *entry; 
} single_words; 


FILE *words; 
/*-------------Function Prototypes------------*/ 
void reverse(char* string, char* revstr, int len); 
int search_struct(char* find, word* words, int length); 
int compare(const void* eventa, const void* eventb); 
int length(char* string); 


int main(void) 
{ 
    char *buffer; 
    int letter_index[26]; 
    char alpha[] = "abcdefghijklmnopqrstuvwxyz"; 
    int i=0, found = FALSE, strlen=0, letter=0; 
    word *word_storage; 
    single_words *output_storage; 
    int num_words = 0, size = 0; 
    int num_output = 0, output_size = 0; 

    /*buffer for the input strings of the words in the input file*/ 
    buffer = (char*) malloc (sizeof(char)*BUFFERLEN); 
     if(!buffer){ 
      fprintf(stderr, "Error in buffer string mem alloc\n"); 
      exit(1); 
     } 

    /*Initializing the array of structs to store the forward and reverse of each word*/ 
    word_storage = (word*) malloc (sizeof(word)*START_SIZE); 
     if(!word_storage){ 
      fprintf(stderr, "Error in word_storage string mem alloc\n"); 
      exit(1); 
     } 
     size = START_SIZE; 

    /*Initializing the array of structs for the output*/ 
    output_storage = (single_words*) malloc (sizeof(single_words)*START_SIZE); 
     if(!output_storage){ 
      fprintf(stderr, "Error in output_storage mem alloc\n"); 
      exit(1); 
     } 
     output_size = START_SIZE; 

    /*Set the letter index 0(which is a) to the first character*/ 
    letter_index[0] = 0; 

    words = fopen("words", "r"); 

    /*Read the words(forward and reverse) in from stdin into the word_storage*/ 
    while(fgets(buffer, BUFFERLEN, words) != NULL){ 
     buffer = strtok(buffer, "\n"); 
     strlen = length(buffer); 
     if (num_words < size){ 
      /*Allocate memory for the forward and reverse strings*/ 
      word_storage[num_words].forw = (char *) malloc (sizeof(char) * strlen); 
       if(!word_storage[num_words].forw){ 
        free(word_storage[num_words].forw); 
        fprintf(stderr, "word_storage forward string malloc was unsuccessful"); 
        exit(1); 
       } 
      word_storage[num_words].back = (char *) malloc (sizeof(char) * strlen); 
       if(!word_storage[num_words].back){ 
        free(word_storage[num_words].back); 
        fprintf(stderr, "word_storage forward string malloc was unsuccessful"); 
        exit(1);; 
       }    

      /*Store the forward and reverse in the strings*/ 
      strncpy(word_storage[num_words].forw, buffer, strlen); 
      reverse(word_storage[num_words].forw, word_storage[num_words].back, strlen); 
      printf("%d: %s %s\n", num_words, word_storage[num_words].forw, word_storage[num_words].back); 

      /*Increment the letter if it changes*/ 
      if(word_storage[num_words].forw[0] != alpha[letter]){ 
       letter++; 
       letter_index[letter] = num_words + 1; 
      } 
      num_words++; 
     } 
     else{ 
      /*Increase the size of word_storage*/ 
      word_storage = (word*) realloc (word_storage, sizeof(word) * size * GROW); 
       if(!word_storage){ 
        free(word_storage); 
        fprintf(stderr, "Error in word_storage realloc string mem realloc\n"); 
        exit(1); 
       } 
      size = size * GROW; 
     }  
    } 


    return 0; 
} 

Ошибка перераспределить происходит здесь:

word_storage = (word*) realloc (word_storage, sizeof(word) * size * GROW); 
    if(!word_storage){ 
     free(word_storage); 
     fprintf(stderr, "Error in word_storage realloc string mem realloc\n"); 
     exit(1); 
    } 
    size = size * GROW; 

ответ

1

Итак, вы изначально установили size в START_SIZE, что составляет 100 000. Затем, когда вы используете это, вы пытаетесь выделить sizeof(word) * size * GROW байт. sizeof(word) - предположительно 16 байт; мы знаем, что size составляет 100000, а GROW - 1000. Таким образом, это позволяет создать достаточное пространство для 100 000 000 записей, из которых вы говорите, что будете использовать 235 000. Кажется, что выделение немного на щедрой стороне.

Общая площадь за 100 000 000 записей составляет 1 600 000 000 байт. Это похоже на много, хотя в наши дни многие настольные компьютеры могут справиться с этим. Но это тоже не выглядит удивительно, что realloc не удается.

Может быть, вы должны сделать что-то GROW более разумным, как 2.

Кстати, как только вы установили, что word_storage является NULL, то нет смысла в вызове free(word_storage). Это не наносит вреда, так как free(NULL) не является оператором, но по той же причине он тоже не подходит.

0

Вы умножив размер на 1000, который слишком много (высоко экспоненциальный рост 1 -> 1000 -> 1000 000 -> 1000 000 000 .. .), и вы не показываете errno. Я предлагаю вместо

size_t newsize = 3*size/2 + 1000; 
word_storage = realloc(word_storage, sizeof(word)*newsize); 
if (!word_storage) { 
    fprintf(stderr, "Cannot grow storage to %ld size, %s\n", 
        (long) newsize, strerror(errno)); 
    exit (EXIT_FAILURE); 
} 
else size = newsize; 

тогда, если, начиная с начальным размером 1000, вы получаете гораздо более разумную прогрессию 1000 -> 2500 -> 4750 -> 8125 -> 13187 -> 20780 ... и что еще более важно вы тратите не более 50% бесполезной памяти, а не почти на 1000!