realloc(): invalid next size

0

Witajcie
Jestem w trakcie pisania programu w C, który ma zczytać nieokreśloną ilość liczb o różnej długości zapisanych w pliku tekstowym. Poniżej prezentuję kod oraz błąd, który pojawia się w konsoli po uruchomieniu poprawnie skompilowanego programu. Czy mógłbym liczyć na pomoc w rozwiązaniu problemu?

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

char* getNum (FILE *f)
{
  int size=1;
  int count;
  int len;
  char* num;
  int c;
  
  num=malloc(sizeof(char)*size);
  if (num==NULL) return NULL;
  len=size;
  count=0;
  while (isdigit(c=fgetc(f)))
  {
    num[count]=c;
    count++;
    if (count>=len)
    {
      len+=size;
      num=realloc(num,len*sizeof(char));
    }
  }
  ungetc(c,f);
  num[count]='\0';
  return num;
}

int main (int argc, char* argv[])
{
  FILE *in;
  char** n;
  int size=1;
  int count;
  int len;
  int i;
  
  if (argc!=2) exit(2);
  in=fopen(argv[1],"r");
  if (!in) exit(3);
  
  n=malloc(sizeof(char)*size);
  if (n==NULL) abort();
  len=size;
  count=0;
  while (!feof(in))
  {
    n[count]=getNum(in);
    if (n==NULL)
    {
      printf ("Malloc failed\n");
      break;
    }
    count++;
    if (count>=len)
    {
      len+=size;
      n=realloc(n,len*sizeof(char));
    }
    n[count]='\0';
  }
  
  for (i=0;i<count;i++)
  {
  printf ("%s",n[count]);
  }
  free(n);
  return 0;
}

*** glibc detected *** ./prog: realloc(): invalid next size: 0x087e8170 ***

0

Wygląda na to, jakbyś chciał zaalokować blok o zbyt dużym rozmiarze.
A zresztą, użyj debuggera i się przekonaj!

0
Patryk27 napisał(a):

Wygląda na to, jakbyś chciał zaalokować blok o zbyt dużym rozmiarze.
A zresztą, użyj debuggera i się przekonaj!

Oto co śpiewa mi valgrind:

==3049== Memcheck, a memory error detector
==3049== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==3049== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==3049== Command: ./sort infile
==3049== 
==3049== Invalid write of size 4
==3049==    at 0x80487F1: main (sort.c:51)
==3049==  Address 0x41f61b8 is 0 bytes inside a block of size 1 alloc'd
==3049==    at 0x402BB7A: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3049==    by 0x80487B0: main (sort.c:45)
==3049== 
==3049== Invalid write of size 4
==3049==    at 0x8048848: main (sort.c:63)
==3049==  Address 0x41f7cc4 is 2 bytes after a block of size 2 alloc'd
==3049==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3049==    by 0x8048832: main (sort.c:61)
==3049== 

valgrind: m_mallocfree.c:266 (mk_plain_bszB): Assertion 'bszB != 0' failed.
valgrind: This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata.  If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away.  Please try that before reporting this as a bug.

==3049==    at 0x3803D043: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x3803D152: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x380007B3: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x3804A760: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x3808441B: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x380161B2: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x38016395: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x38086C6A: ??? (in /usr/lib/valgrind/memcheck-x86-linux)
==3049==    by 0x38098BE7: ??? (in /usr/lib/valgrind/memcheck-x86-linux)

sched status:
  running_tid=1

Thread 1: status = VgTs_Runnable
==3049==    at 0x402BB7A: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3049==    by 0x80486A7: getNum (sort.c:13)
==3049==    by 0x80487F0: main (sort.c:51)


Note: see also the FAQ in the source distribution.
It contains workarounds to several common problems.
In particular, if Valgrind aborted or crashed after
identifying problems in your program, there's a good chance
that fixing those problems will prevent Valgrind aborting or
crashing, especially if it happened in m_mallocfree.c.

If that doesn't help, please report this bug to: www.valgrind.org

In the bug report, send all the above text, the valgrind
version, and what OS and version you are using.  Thanks.
0
  1. Po kiego masz ten ungets?
  2. W malloc i realloc nie zawsze sizeof(char) - zaś rozmiar elementu tablicy.
  3. Jak masz pętle po i to wyświetlaj to co masz pod i

http://ideone.com/yPQnL6

0

Dzięki!
Z Twoją pomocą Dragon udało mi się to ogarnąć, ale teraz mam kolejne pytanie. Jak można domyślić się po nazwie pliku, otrzymane wartości muszę posortować. Jest to jednak dwuwymiarowa tablica gdzie pierwszym wymiarem jest cała liczba, a drugim poszczególne cyfry. No i teraz pytanie: jak posortować tablicę względem pierwszego tylko wymiaru nie zaburzając kolejności w drugim? (A więc jak pozamieniać miejscami liczby nie ruszając przy tym cyfr je tworzących?)

0

wymieniasz tylko same wskaźniki: http://www.cplusplus.com/reference/cstdlib/qsort/

0
int compare (const void * a, const void * b)
{
    int _a = *(int*)a;
    int _b = *(int*)b;
    if(_a < _b) return -1;
    else if(_a == _b) return 0;
    else return 1;
}
     qsort (n, count, sizeof(char*), compare);

Co jest nie tak z taką funkcją porównującą/wywoływaniem qsorta?

0

Cały kod:

 #include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
 
char *getNum(FILE *f)
  {
   char* num;
   int count;
   int c;
 
   num=malloc(1);
   count=0;
   while(isdigit(c=fgetc(f)))
     {
      num[count]=c;
      num=realloc(num,++count);
     }
     //if (!isdigit(c)) return NULL;
   num[count]='\0';
   return num;
  }

int compare (const void * a, const void * b)
{
    int _a = *(int*)a;
    int _b = *(int*)b;
    if(_a < _b) return -1;
    else if(_a == _b) return 0;
    else return 1;
}
 
int main(int argc, char* argv[])
  {
   FILE *in;
   char** n;
   int count;
   int i;
 
  if (argc!=2) exit(2);
  in=fopen(argv[1],"r");
  if (!in) exit(3);
 
   n=NULL;
   count=0;
   while(!feof(in))
     {
      n=realloc(n,(count+1)*sizeof(char*));
      n[count++]=getNum(in);
     }
     qsort (n, count, sizeof(char*), compare);
   
   for(i=0;i<count;++i)
     {
      if (n[i][0]!='\0') printf ("%s\n",n[i]);
     }
   free(n);
   return 0;
  }
0
int compare (const void *a, const void *b)
  {
   return strcmp(*(const char**)a,*(const char**)b);
  }
0

Dzięki wielkie, teraz w miarę działa, ale z pewnym zastrzeżeniem. Mianowicie output wygląda tak:

0001234
123456789887878888888888777665564533353455523453535 <---Nieco za wysoko ;)
2345345555555555554435435345345353535353453452
2345345555555555554435435345345353535353453453

0

Bo masz sortowanie napisów jeżeli chcesz sortować to jako liczby to musisz to odpowiednio zaimplementować w funkcji compare

0
static int compare(const void* p1, const void* p2) {
int a,b;
const char **ia = (const char **)p1;
const char **ib = (const char **)p2;
a = atoi(*ia);
b = atoi(*ib);
if (a==b)
return 0;
else
if (a < b)
return 1;
else
return -1;
}

Próbuję w ten sposób i cóż.. output wygląda jak poniżej, choć chyba powinno być ok.. Może to nie w sortowaniu problem?

2345345555555555554435435345345353535353453453
2345345555555555554435435345345353535353453452
123456789887878888888888777665564533353455523453535
0001234
0

Nie możesz skonwertować tego do int'a - bo się nie mieści.
Zaimplementuj to w sposób w jaki porównujesz liczby ręcznie

1 użytkowników online, w tym zalogowanych: 0, gości: 1