"损坏的双链表"在结构中的2D数组上使用malloc()时

时间:2015-07-16 07:35:47

标签: malloc

我正在尝试制作一个小型的自动完成程序。 我从文件中取出字符串并将它们逐行放入2D char类型数组中。

这是我的代码:

Dictionnary.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "Dictionnary.h"

int getDictionnarySize(FILE *theDictionnary)
{  
  size_t pos = ftell(theDictionnary);
  fseek(theDictionnary, 0, SEEK_END);
  size_t len = ftell(theDictionnary);
  fseek(theDictionnary, pos, SEEK_SET);

  return (len);
}

int getNbLines(char *buff)
{
  int   lines = 1;
  int   i = 0;

  while (buff[i] != '\0')
    {
      if (buff[i] == '\n')
    lines++;
      i++;
    }

  return (lines);
}

int allocDictionnary(t_dictionnary *d, char *buff)
{
  d->lines = getNbLines(buff) - 1;
  int i;
  char str[2048];
  int len;

  rewind(d->dico);
  d->dictionnary = malloc(sizeof(*d->dictionnary) * d->lines);
  for (i = 0; i <= d->lines; i++)
    {
      memset(str, 0, 2048);
      fgets(str, 256, d->dico);
      len = strlen(str);
      printf("len = %d\n", len);
      d->dictionnary[i] = malloc(sizeof(**d->dictionnary) * len);
      if (d->dictionnary[i] == NULL)
    return (1);
      strcpy(d->dictionnary[i], str);
      printf("String is : %s\n", d->dictionnary[i]);
    }

  return (0);
}

int initDictionnary(t_dictionnary *d)
{
  int   size;
  char  *buff;

  if ((d->dico = fopen(d->theDictionnary, "r")) != NULL)
    {
      size = getDictionnarySize(d->dico);
      buff = malloc(size + 1);
      fread(buff, size, 1, d->dico);
      allocDictionnary(d, buff);
      fclose(d->dico);
    }
  else
    {
      return (1);
    }

  free(buff);
  return (0);
}

int killDictionnary(char **theDictionnary, int size)
{
  int   i = 0;

  while (i <= size)
    {
      free(theDictionnary[i]);
      i++;
    }
  free(theDictionnary);

  return (0);
}

Dictionnary.h

#ifndef __DICTIONNARRY_H__
# define __DICTIONNARY_H___

/* STRUCTURES */

typedef struct s_dictionnary
{
  const char *theDictionnary;
  FILE *dico;
  char **dictionnary;
  int lines;
}       t_dictionnary;

/* PROTOTYPES */

int     getDictionnarySize(FILE *theDictionnary);
int     allocDictionnary(t_dictionnary *d, char *buff);
int     initDictionnary(t_dictionnary *dico);
int     getNbLines(char *buff);
int     killDictionnary(char **theDictionnary, int size);

#endif /* __DICTIONNARY_H__ */

的main.c

#include <stdlib.h>
#include <stdio.h>
#include "Dictionnary.h"

int main(int ac, char **av)
{
  t_dictionnary d;

  d.theDictionnary = "./miniDico";
  initDictionnary(&d);
  killDictionnary(d.dictionnary, d.lines);
  return (0);
}

编译时,我没有任何错误或警告。 但是当我运行这个时,我得到了:

*** Error in `./a.out': corrupted double-linked list: 0x0000000000f19550 ***

Valgrind结果:

==4004== Memcheck, a memory error detector
==4004== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4004== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4004== Command: ./a.out
==4004== 
==4004== Conditional jump or move depends on uninitialised value(s)
==4004==    at 0x40095C: getNbLines (Dictionnary.c:22)
==4004==    by 0x40098B: allocDictionnary (Dictionnary.c:34)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
len = 35
==4004== Invalid write of size 1
==4004==    at 0x4C2D623: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x400AB8: allocDictionnary (Dictionnary.c:50)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004==  Address 0x51d8723 is 0 bytes after a block of size 35 alloc'd
==4004==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x400A61: allocDictionnary (Dictionnary.c:47)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
==4004== Invalid read of size 1
==4004==    at 0x4E7E1C2: vfprintf (in /usr/lib/libc-2.21.so)
==4004==    by 0x4E84E38: printf (in /usr/lib/libc-2.21.so)
==4004==    by 0x400AE5: allocDictionnary (Dictionnary.c:51)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004==  Address 0x51d8723 is 0 bytes after a block of size 35 alloc'd
==4004==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x400A61: allocDictionnary (Dictionnary.c:47)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
String is : Paris, 458 boulevard Saint-Germain

len = 35
String is : Paris, 343 boulevard Saint-Germain

len = 44
String is : Marseille, 343 boulevard Camille Flammarion

len = 37
String is : Marseille, 29 rue Camille Desmoulins

len = 34
String is : Marseille, 1 chemin des Aubagnens

len = 25
String is : Paris, 12 rue des singes

len = 24
String is : Paris, 34 quai VoLtAiRe

len = 23
String is : Paris, 34 rue Voltaire

len = 33
String is : Lille, 120 boulevard Victor Hugo

len = 27
String is : Marseille, 50 rue Voltaire

len = 26
String is : Toulouse, 90 rue Voltaire

len = 30
String is : Strasbourg 84 rue du Bouclier

len = 42
String is : Marseille, 78 boulevard de la libération

len = 27
String is : Lille, 30 rue Victor Danel

len = 38
String is : Mont Saint Martin, 42 rue de Bordeaux

len = 47
String is : Mont de Marsan, 100 avenue Pierre de Coubertin

len = 35
String is : Strasbourg, 391 boulevard de Nancy

len = 38
String is : Lyon, 56 rue du Docteur Albéric Pont

len = 35
String is : Lyon, rue du Docteur Albéric Pont

len = 38
String is : 56 rue du Docteur Albéric Pont, Lyon

len = 19
String is : Lyon 56 grande rue

len = 24
String is : Lille, 90 rue d’Arras

len = 35
String is : Lille, 76 impasse Georges Pompidou

len = 25
==4004== Invalid write of size 8
==4004==    at 0x400A62: allocDictionnary (Dictionnary.c:47)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004==  Address 0x51d86b8 is 0 bytes after a block of size 184 alloc'd
==4004==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x4009C3: allocDictionnary (Dictionnary.c:40)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
==4004== Invalid read of size 8
==4004==    at 0x400A7D: allocDictionnary (Dictionnary.c:48)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004==  Address 0x51d86b8 is 0 bytes after a block of size 184 alloc'd
==4004==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x4009C3: allocDictionnary (Dictionnary.c:40)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
==4004== Invalid read of size 8
==4004==    at 0x400AA4: allocDictionnary (Dictionnary.c:50)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004==  Address 0x51d86b8 is 0 bytes after a block of size 184 alloc'd
==4004==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x4009C3: allocDictionnary (Dictionnary.c:40)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
==4004== Invalid read of size 8
==4004==    at 0x400AD1: allocDictionnary (Dictionnary.c:51)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004==  Address 0x51d86b8 is 0 bytes after a block of size 184 alloc'd
==4004==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x4009C3: allocDictionnary (Dictionnary.c:40)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
String is : Lyon, 2 allée des fleurs
==4004== Invalid read of size 8
==4004==    at 0x400BF6: killDictionnary (Dictionnary.c:85)
==4004==    by 0x400C53: main (main.c:11)
==4004==  Address 0x51d86b8 is 0 bytes after a block of size 184 alloc'd
==4004==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4004==    by 0x4009C3: allocDictionnary (Dictionnary.c:40)
==4004==    by 0x400B9F: initDictionnary (Dictionnary.c:67)
==4004==    by 0x400C42: main (main.c:10)
==4004== 
==4004== 
==4004== HEAP SUMMARY:
==4004==     in use at exit: 0 bytes in 0 blocks
==4004==   total heap usage: 27 allocs, 27 frees, 2,289 bytes allocated
==4004== 
==4004== All heap blocks were freed -- no leaks are possible
==4004== 
==4004== For counts of detected and suppressed errors, rerun with: -v
==4004== Use --track-origins=yes to see where uninitialised values come from
==4004== ERROR SUMMARY: 54 errors from 8 contexts (suppressed: 0 from 0)

1 个答案:

答案 0 :(得分:0)

也许这个循环会引起麻烦:

for (i = 0; i <= d->lines; i++)

它似乎应该是(我改变了停止条件):

for (i = 0; i < d->lines; i++)

否则你写在分配的空间后面......

<强>更新

澄清:

使用d->dictionnary = malloc(sizeof(*d->dictionnary) * d->lines);分配数组会为您提供具有d->lines元素的精确数据。它从0索引开始,可以使用d->lines-1索引访问最后一个元素。因此,当您使用从0到{且包含d->lines的循环时,最后一个循环周期将写入数组边界之外(即d->lines索引)。那就是你腐败堆的地方。通常,C运行时不会检查这些错误,您只会在罕见的情况下看到它们,并且可能远离导致它们的代码。

“损坏的链表”是关于堆损坏的。分配有malloc的块通常链接到链表(这实际上取决于您的内存分配器的实现)。因此,在编写外部分配边界时 - 您可以破坏此列表。因此抱怨。