复制结构数组时导致segfault的Memcpy



我正在尝试制作一个rehashing函数,该函数将适用于非常大的哈希表(超过100万个条目),而我目前的方法效率非常低。这是我的结构

typedef struct {
   int id, count, correct, valid;
   char* word;
} Entry;
typedef struct {
   Entry* arr;
   int size, numValid;
} Hash;

以下是它现在的功能(非常慢,不使用memcpy):

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 %dn",tempArr[i].word,tempArr[i].count);*/
        free(tempArr[i].word);
      }
   }
   free(tempArr);
}

我更喜欢使用memcpy,但我一辈子都无法让它正常工作。以下是我正在尝试的(这是不起作用的代码,我正在寻求帮助):

void rehash(Hash* hash) {
   Entry* tempArr;
   int i;
   tempArr = calloc(hash->size, sizeof(Entry));
   fprintf(stderr,"size: %dn",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 %dn",tempArr[i].word,tempArr[i].count);*/
        free(tempArr[i].word);
     }
   }
   free(tempArr);
}

我确信这是一个简单的单行修复,但我就是看不到。

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++;
}

我认为memcpy没有问题。问题是removeAllEntries(hash);释放所有条目,然后tempArr[i].wordfree(tempArr[i].word);中的双free,因为它是复制的指针。在addEntry(hash,tempArr[i].word,tempArr[i].count);中使用tempArr[i].word也是无效的。已经是free'd了。


一种解决方案提出使用CCD_ 8。

更换

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

带有

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));
}

不为调整大小而重新散列。


另一种解决方案

如果出于某种原因需要重新清洗。更改以下

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: %dn",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 %dn",tempArr[i].word,tempArr[i].count);*/
            free(tempArr[i].word);
        }
    }
    free(tempArr);
}

如果numValid代表有效的注册号,我认为只保存一个wordcount就足够了。

最新更新