2016-04-30 8 views
-1

Ich versuche eine Umschäumungsfunktion zu erstellen, die bei sehr großen Hash-Tabellen (mit mehr als 1 Million Einträgen) funktioniert und meine aktuelle Methode ist sehr ineffizient. Hier sind meine StrukturenMemcpy verursacht segfault beim Kopieren von Struct-Arrays

typedef struct { 
    int id, count, correct, valid; 
    char* word; 
} Entry; 

typedef struct { 
    Entry* arr; 
    int size, numValid; 
} Hash; 

Hier ist, wie es jetzt funktioniert (sehr langsam, nicht memcpy verwenden):

void rehash(Hash* hash) { 
    Entry* tempArr; 
    int i; 

    tempArr = calloc(hash->size, sizeof(Entry)); 
    for(i = 0; i < hash->size; i++) { 
     if(hash->arr[i].count) { 
     tempArr[i].count = hash->arr[i].count; 
     tempArr[i].correct = hash->arr[i].valid; 
     tempArr[i].word = malloc(strlen(hash->arr[i].word) + 1); 
     strcpy(tempArr[i].word,hash->arr[i].word); 
     tempLen++; 
     } 
     memcpy(&tempArr[i],&hash->arr[i],sizeof(Entry)); 
     tempArr[i] = hash->arr[i]; 
    } 

    removeAllEntries(hash); 
    resize(hash); 


    for(i = 0; i < (hash->size/2); i++) { 
     if(tempArr[i].count > 0) { 
     addEntry(hash,tempArr[i].word,tempArr[i].count); 
     /*printf("Added %s with count %d\n",tempArr[i].word,tempArr[i].count);*/ 
     free(tempArr[i].word); 
     } 
    } 
    free(tempArr); 
} 

Ich würde es vorziehen Memcpy zu verwenden, aber ich kann nicht für das Leben Ich bekomme es richtig zu arbeiten. Hier ist, was ich versuche, (dies ist der Code, der nicht funktioniert, und was für die Hilfe bei ich suche):

void rehash(Hash* hash) { 
    Entry* tempArr; 
    int i; 

    tempArr = calloc(hash->size, sizeof(Entry)); 

    fprintf(stderr,"size: %d\n",hash->size * sizeof(Entry)); 
    memcpy((tempArr),(hash->arr),hash->size * sizeof(Entry)); 

    removeAllEntries(hash); 
    resize(hash); 

    for(i = 0; i < (hash->size/2); i++) { 
    if(tempArr[i].count > 0) { 
     addEntry(hash,tempArr[i].word,tempArr[i].count); 
     /*printf("Added %s with count %d\n",tempArr[i].word,tempArr[i].count);*/ 
     free(tempArr[i].word); 
    } 
    } 
    free(tempArr); 
} 

Ich bin sicher, es ist eine einfache, einzeilige fix, aber ich kann mich einfach nicht dazu bringen, es zu sehen.

void addEntry(Hash* hash, char* tag, int count) { 
    int value = CHV(hash->size, tag), flag = 1, iter = 0; 
    int possIndex = findEntry(hash, tag); 
    /*fprintf(stderr,"AddEntry...\n");*/ 


    if(possIndex >= 0) { 
     (hash->arr[possIndex].count)++; 
     return; 
    } 



    if((hash->size - hash->numValid) < ((double)hash->size/10)) 
    { 
     rehash(hash); 
    } 
    while(flag) { 
     iter++; 
     if(!(hash->arr[value].valid)) { 
     hash->arr[value].word = calloc(strlen(tag) + 1, sizeof(char)); 
     strcpy(hash->arr[value].word, tag); 
     wordsAlloced++; 
     hash->arr[value].valid = 1; 
     hash->arr[value].correct = 1; 
     hash->arr[value].count = count; 
     flag = 0; 
     } 
     else { 
     value++; 
     if(value == hash->size) { 
      value = 0; 
     } 
     } 
    } 
    hash->numValid++; 
} 
+1

Wäre es praktisch, die Deklarationen von 'Entry' und' Hash' zu kennen –

+1

Mit welchem ​​Snippet haben Sie Probleme? Welchen benutzen Sie? Worauf bezieht sich Ihre Frage? – alk

+1

Sie wollen uns die Definition von'Entry' zeigen. – alk

Antwort

1

Ich denke, dass memcpy kein Problem ist. Problem ist frei alle Eintrag von removeAllEntries(hash); dann tempArr[i].word ist die doppelte free in free(tempArr[i].word); Weil es Zeiger kopiert wird. Auch die Verwendung von tempArr[i].word in addEntry(hash,tempArr[i].word,tempArr[i].count); ist ungültig. Es ist bereits free 'd.


Eine Lösung schlägt die Verwendung von realloc vor.

void resize(Hash* hash) { 
    free(hash->arr); 
    hash->size *= 2; 
    hash->arr = calloc(hash->size, sizeof(Entry)); 
    //TOTALALLOC += (hash->size * sizeof(Entry)); 
} 

mit

void resize(Hash* hash) { 
    Entry* tempArr; 

    if((tempArr = realloc(hash->arr, 2 * hash->size * sizeof(Entry)))==NULL){ 
     fprintf(stderr,"failed realloc in resize.\n"); 
     return ; 
    } 
    hash->size *= 2; 
    hash->arr = tempArr; 
    //TOTALALLOC += (hash->size * sizeof(Entry)); 
} 

Hat aufwärmen nicht Zweck ersetzen zum Ändern der Größe.


Eine andere Lösung

Wenn Aufguß aus irgendeinem Grund notwendig ist. in den folgenden

void rehash(Hash* hash) { 
    Entry* tempArr; 
    int i; 

    tempArr = malloc(hash->size * sizeof(Entry));//Initialization isn't required because it is replaced by memcpy. 

    //fprintf(stderr,"size: %d\n",hash->size * sizeof(Entry)); 
    memcpy(tempArr,hash->arr, hash->size * sizeof(Entry)); 
    //To replicate word 
    for(i = 0; i < hash->size; i++) { 
     if(hash->arr[i].count) { 
      tempArr[i].word = malloc(strlen(hash->arr[i].word) + 1); 
      strcpy(tempArr[i].word, hash->arr[i].word); 
     } 
    } 
    removeAllEntries(hash); 
    resize(hash); 

    for(i = 0; i < (hash->size/2); i++) { 
     if(tempArr[i].count > 0) { 
      addEntry(hash,tempArr[i].word, tempArr[i].count); 
      /*printf("Added %s with count %d\n",tempArr[i].word,tempArr[i].count);*/ 
      free(tempArr[i].word); 
     } 
    } 
    free(tempArr); 
} 

zu ändern, wenn numValid die die gültige Registrierungsnummer darstellen, denke ich, dass es ausreichend ist, nur ein word und count zu speichern.

+0

Das funktioniert, und scheint definitiv ein bisschen schneller. Das Problem besteht darin, dass ein erneutes Hashing mit großen Hash-Größen immer noch sehr viel Zeit in Anspruch nimmt, ein erneuter Vorgang dauert in späteren Fällen 5 Minuten. Wie kann ich das einschränken? –

+0

@EvanCooper Wenn Sie versuchen, in diesem Teil zu verbessern, denke ich wieder, ob nur das "Wort" und "Count" (ungetestet) zu verarbeiten. Ich denke, dass einige Zeit unumgänglich ist. Was benötigt wird, ist eine große Menge an Datenwiederaufbereitung. – BLUEPIXY

Verwandte Themen