Memcpy在复制struct数组时导致段错误

时间:2016-04-30 10:13:13

标签: c

我正在尝试制作一个可以在非常大的哈希表(超过100万个条目)上工作的rehashing函数,而且我当前的方法效率非常低。这是我的结构

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 %d\n",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: %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);
}

我确信这是一个简单的单行修复,但我无法让自己看到它。

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 个答案:

答案 0 :(得分:1)

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

一种解决方案建议使用realloc

替换

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

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