C valgrind大小为8的读取无效

C valgrind大小为8的读取无效,c,valgrind,C,Valgrind,我试图理解Valgrind报告“大小为4的无效读取”错误的原因。在Linux控制台上编译代码并给出正确的输出。 我们的目标是构建一个动态的结构记录数组(最多10Mil项),这些记录动态增长,并通过结构列表按语言进行组织 代码: #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <unistd.h> #incl

我试图理解Valgrind报告“大小为4的无效读取”错误的原因。在Linux控制台上编译代码并给出正确的输出。
我们的目标是构建一个动态的结构记录数组(最多10Mil项),这些记录动态增长,并通过结构列表按语言进行组织

代码:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include "../crc64.c"

typedef struct {
  char          cat;
  uint64_t      crc;
  int           id;
} record;

typedef struct {
  int           count;
  char          *lang;
  record        **records;
} list;

record *records = NULL;
int record_count = 0;
list *lists = NULL;
int list_count = 0;

void addItemToList(record *r, char *lang){  
  int found = 0;
  for(int i = 0; i<list_count; i++){
    if(strcmp(lists[i].lang, lang) == 0){
      list *l = &lists[i];
      found = 1;      
      record **tmp  = realloc(l->records, (l->count + 1) * sizeof(record *));
      if (tmp == NULL)
        printf("Problem on realloc - records/list\n");
      else{
        l->records = tmp;
        l->count ++;
        l->records[l->count -1] = r;
      }        
      break;
    }
  }
  if(found == 0){
    list_count ++;
    list *tmp = realloc(lists, list_count  * sizeof(list));
    if(!tmp) 
      printf("Error on realloc - list");
    lists = tmp;
    lists[list_count - 1].count =1 ;
    lists[list_count - 1].lang = lang ;
    record **tmp1 = realloc(NULL, sizeof(record *));
    if(!tmp1)
      printf("Error on realloc records/list \n");          
    lists[list_count - 1].records = tmp1;      
    tmp1[0] = r;    
  }  
}

int addRecord(char cat, char *name, int id, char lang[3]){  
  record *tmp;
  if(record_count == 0){
    tmp = malloc(1 * sizeof(record));         
  }  
  else 
    tmp = realloc(records, (record_count + 1)  * sizeof(record));
  if(tmp == NULL){
    printf("Error on m(re)alloc records\n");
    return(1);
  }  

  records = tmp;
  record r = {cat, crc64(name), id};
  records[record_count ] = r; 
  addItemToList(&(records[record_count]), lang);
  record_count ++;
  return 0;  
}

int main(void){
  addRecord('l', "torino",1, "it");
  addRecord('l', "berlin",20, "de");
  addRecord('l', "paris",30, "fr");  
  addRecord('l', "hamburg",21, "de");
  addRecord('l', "sassari",2, "it");
  addRecord('l', "cagliari",3, "it");
  addRecord('l', "milano",4, "it");


  for(int i=0; i< list_count;i++){
    printf("lang: %s, count :%d\n", lists[i].lang, lists[i].count);  
    for (int z = 0; z < lists[i].count; z ++){
      printf("  crc:  %lu -   id: %d \n", lists[i].records[z]->crc, lists[i].records[z]->id);
    }
  }
  return 0;
}

您正在重新分配记录,但不更新指针

tmp = realloc(records, (record_count + 1)  * sizeof(record));
执行此操作时,指向旧
记录的所有指针
数组将变得无效。

下面是一个简单的例子

record *array = malloc(sizeof(*array));
record *r1 = &array[0];
array = realloc(array, sizeof(*array) * 2);
record *r2 = &array[1];
// r1 is probably invalid, since 'array' changed
有几种方法可以解决这个问题

  • 当您
    realloc
    时,检查并更新所有指针。这真的很痛苦

  • 分别分配每个记录,而不是在一个大数组中。(不,这不会浪费内存。至少与由于字段顺序而浪费的每条记录的8字节相比是如此。)

  • 在记录数组中使用索引,而不是指向记录的指针。这些不需要更新


  • 谢谢,alloc每一张唱片都很好用。大约第三点,您的意思是只在列表中存储大数组中记录的位置吗?。在这种情况下,使用qsort会发生什么?在这种情况下,位置会丢失吗?
    record *array = malloc(sizeof(*array));
    record *r1 = &array[0];
    array = realloc(array, sizeof(*array) * 2);
    record *r2 = &array[1];
    // r1 is probably invalid, since 'array' changed