У меня есть программа с двумерным массивом. Сначала я выделяю массив следующим образом:
char **crossword;
crossword = (char **) malloc(n* sizeof(*crossword));
for (i = 0; i < n; i++)
crossword[i] = (char *)malloc(n);
Где n = 50.
Затем у меня есть функция, которая читает строки из стандартного ввода. Проблема в том, что я не знаю, сколько и какой длины будут эти строки.
void read(char **p,int *n)
{
char tmp = 0,prevtmp = 0;
int i = 0, j = 0,x;
while (1)
{
prevtmp = tmp;
tmp = getchar();
if ((tmp == '\n' && prevtmp == '\n') || feof (stdin))
{
*n = i;
break;
}
if (tmp == '\n')
{
p[i][j] = '\0';
i++;
if (i == *n)
{
p = (char **) realloc(p, 2*i); // if there is more strings than space for them, allocate more memory.
for (x = i; x < 2*i; x++)
p[x] = (char *) malloc (*n);
*n *= 2;
}
j = 0;
continue;
}
p[i][j] = tmp;
j++;
if (j == *n)
p[i] = (char *)realloc(p[i], 2*j); //same as above
}
}
Функция вызывается так:
read(crossword,&n);
Эта функция прекрасно работает, когда нет необходимости в realloc (менее 50 строк, каждая меньше 50 символов). Но для больших входов это не удается с
*** glibc detected *** ./a.out: malloc(): memory corruption (fast): 0x00000000014282f0 *** error.
Я думаю, что моя проблема в той части, где я перераспределяю больше памяти, вот вывод valgrind:
==8885== Invalid write of size 1
==8885== at 0x40084C: read (in /home/xerw/Dropbox/CVUT/PROGTEST/du6/a.out)
==8885== by 0x40177F: main (in /home/xerw/Dropbox/CVUT/PROGTEST/du6/a.out)
==8885== Address 0x51f2b88 is not stack'd, malloc'd or (recently) free'd
==8885==
==8885== Invalid write of size 8
==8885== at 0x4008A6: read (in /home/xerw/Dropbox/CVUT/PROGTEST/du6/a.out)
==8885== by 0x40177F: main (in /home/xerw/Dropbox/CVUT/PROGTEST/du6/a.out)
==8885== Address 0x51f4f00 is not stack'd, malloc'd or (recently) free'd
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.
==8885== at 0x3804C6CF: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x3804C812: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x38000883: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x380574EA: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x38057E03: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x380212DC: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x3802146A: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x3808F656: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
==8885== by 0x3809E68C: ??? (in /usr/lib/valgrind/memcheck-amd64-linux)
sched status:
running_tid=1
Thread 1: status = VgTs_Runnable
==8885== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8885== by 0x4008A5: read (in /home/xerw/Dropbox/CVUT/PROGTEST/du6/a.out)
==8885== by 0x40177F: main (in /home/xerw/Dropbox/CVUT/PROGTEST/du6/a.out)
Я недолго экспериментировал с указателями, поэтому понятия не имею, что не так. Я пытался решить эту проблему в течение нескольких часов, но ничего не придумал.
Что я делаю не так?
p = (char **) realloc(p, 2*i);
в своем коде.p
указывает на кроссворд? Если это так, то вы выделили кроссворд размеромn * sizeof(*crossword)
. Так2*i
правильно? Кстати, плохо вызывать realloc и присваивать его результат указателю, который вы перераспределяете напрямую - если realloc() не работает, происходит утечка памяти, потому что ваш исходный указатель теперь потерян. - person Nik Bougalis   schedule 25.11.2012stringArray[i][j]
плохо получать символ с индексомj
в строке, заканчивающейся 0, на которую указываетstringArray[i]
? Я нахожу это намного яснее, чем*(*(stringArray + i) + j)
или*(stringArray[i] + j)
или(*(stringArray + i))[j]
. - person Daniel Fischer   schedule 25.11.2012"This function works fine, when there is no need for realloc (there is less than 50 strings, each smaller than 50 characters). But for large inputs, this fails"
дай угадаю. Вы используетеcrossword
после возвращенияread
?realloc
не изменяет адрес, хранящийся в переменнойcrossword
в вызывающем объекте, поэтому, когдаrealloc
меняет местоположение внутриread
, вызывающий объект остается с оборванным указателем. Запись через него может легко повредить жизненно важную память, а любое его использование вызывает неопределенное поведение. - person Daniel Fischer   schedule 25.11.2012