[SOLVED] Указатели и динамические массивы в С

Есть тут спецы по сям?)
Кусок кода:
  int *num_mol_agl;
  for (i=from; i<to+1; i++)
  {
/* здесь рабочий блок, объявление каких то переменный, в т.ч. и num_mol */
    if (i == from)
    {
      agl = (int *) malloc (num_mol * num_mol * sizeof (int));
      connect = (int *) malloc (num_mol * num_mol * sizeof (int));
      num_mol_agl = (int *) malloc (num_mol * sizeof (int));
      stat = (int *) malloc (num_mol * sizeof (int));
      stat_all = (int *) malloc (num_mol * sizeof (int));
    }
/* продолжение */
  }
  num_mol_agl[num_mol-1] = num_mol;
  printf ("%i - %i\n", num_mol-1, num_mol_agl[num_mol-1]);
//   free memory
  free (agl);
  free (connect);
  free (coords);
  free (crit);
  free (label_mol);
//   memory crash here
  free (num_mol_agl);
//   free (stat);
//   free (stat_all);
  free (true_label_mol);
  free (type_atoms);
  return 0;

Теперь описание проблемы:
Программа рабочая на 146%. Но крашится в конце на освобождении памяти для массивов (для любого из) num_mol_agl, stat и stat_all (те, что объявляются самые последние). Обращение к этим массивам (в т.ч. непосредственно перед free) осуществляется нормально. Но крашится( ЧЯДНТ?

PS лог ошибки
PPS весь main (многабукаф)
PGP 0x31361F01
arcanisrepo
Так как уже поздновато, давайте для начала с двумя очевидными возможными причинами разберемся:
1) Немного некрасиво выглядит блок выделения памяти внутри цикла for, но это больше касается стиля программирования, а не ошибка. Гораздо хуже, что не проверяется возвращаемое значение функции malloc, что бы убедиться, что память действительно выделена. То, что потом можно обращаться к членам массива, еще ни о чем не говорит.
2) В строке
printf ("%i - %i\n", num_mol-1, num_mol_agl[num_mol]);
"num_mol_agl[num_mol]" обращается к памяти за границей динамической области. (Последний член должен быть num_mol-1). Возможно, эта попытка чтения за границей выделенной памяти провоцирует вылет.
kurych
1) Немного некрасиво выглядит блок выделения памяти внутри цикла for, но это больше касается стиля программирования, а не ошибка. Гораздо хуже, что не проверяется возвращаемое значение функции malloc, что бы убедиться, что память действительно выделена. То, что потом можно обращаться к членам массива, еще ни о чем не говорит.
1) согласен, что не красиво, но num_mol, необходимый для выделения памяти, определяется только в первой процедуре цикла (дальше он каждый раз переприсваивается, хотя числовое значение не изменяется). Хотя, конечно, можно ресайз сделать (в ближайшее время так и сделаю). В цикле на тестовых данных программа находится 1 раз (to==from).
Насчет проверки, если честно, я плохо понял, что подразумевается. (num_mol_agl != NULL) возвращает true. Кстати, если выделить память под массив в самом начале (после определения переменных), то все равно крашится:
num_mol_agl = (int *) malloc (250 * sizeof (int));
(num_mol = 250)
kurych
2) В строке "num_mol_agl[num_mol]" обращается к памяти за границей динамической области. (Последний член должен быть num_mol-1). Возможно, эта попытка чтения за границей выделенной памяти провоцирует вылет.
2) извиняюсь, это было специально сделано таким образом (мне было любопытно, что изменится, если я вылезу за границу массива). При копировании сюда забыл исправить. Подредактирую первый пост, чтобы не вводить в заблуждение
Специально вернул назад, попробовал. Сейчас там вот так
num_mol_agl[num_mol-1] = num_mol;
printf ("%i - %i\n", num_mol-1, num_mol_agl[num_mol-1]);
вывод
249 - 250
/* текст ошибки */

Еще попробовал каждый раз в начале цикла выделять память (как показано выше в этом посте), в конце очищать - все равно краш (все другие упоминания, есно были убраны).
PGP 0x31361F01
arcanisrepo
Попробовать через valgrind?

А вообще - программа может крашиться из-за более раннего кода.
изменил код с выделением памяти в начале программы:
num_mol_agl = (int *) malloc (2 * sizeof (int));
/* */
и изменением размера в цикле for:
num_mol_agl = (int *) realloc (num_mol_agl, num_mol * sizeof (int));
+ добавил проверку NULL (если верить ману в случае неудачи возвращается именно это значение):
if (num_mol_agl == NULL)
{
  printf ("Memory error (error code: 17)\n");
  return 17;
}
ошибка не выпадает.

Проверил еще раз функции, в которых используется эта переменная - только либо присваивание, либо вызов значения
PGP 0x31361F01
arcanisrepo
sirocco
Попробовать через valgrind?

А вообще - программа может крашиться из-за более раннего кода.
че т там много букв, мне страшно)
valgrind -q --log-file=valgrind.log ./statgen -i oct-clb -s 1,1 -c 35.747,35.747,35.747 -a 1 -r 0-0:4.55 -o test.dat -l test.log -q
valgrind.log
(verbose не помещается =))
видимо, интересует этот кусок:
==4529== Syscall param write(buf) points to uninitialised byte(s)
==4529==    at 0x520A1D0: __write_nocancel (in /usr/lib/libc-2.17.so)
==4529==    by 0x51A5352: _IO_file_write@@GLIBC_2.2.5 (in /usr/lib/libc-2.17.so)
==4529==    by 0x51A4A12: new_do_write (in /usr/lib/libc-2.17.so)
==4529==    by 0x51A6184: _IO_do_write@@GLIBC_2.2.5 (in /usr/lib/libc-2.17.so)
==4529==    by 0x51A5B1F: _IO_file_close_it@@GLIBC_2.2.5 (in /usr/lib/libc-2.17.so)
==4529==    by 0x519A567: fclose@@GLIBC_2.2.5 (in /usr/lib/libc-2.17.so)
==4529==    by 0x404E82: summary_statistic (in /home/arcanis/Documents/github/moldyn/stat_new/statgen)
==4529==    by 0x4020DA: main (in /home/arcanis/Documents/github/moldyn/stat_new/statgen)
==4529==  Address 0x4023089 is not stack'd, malloc'd or (recently) free'd
только вот тут еще ругается на summary_statistic, который выглядит так:
int summary_statistic (char *filename, int step, int num_mol, const int *type_agl, const int *stat_all)
(в этой функции только печать).
До освобождения памяти стоит как раз эта функция, которая печатает в файл. она прорабатывается до конца без ошибок, т.е. падает именно на освобождении памяти. И именно конкретных 3х массивов (неважно где освобождать память).
PGP 0x31361F01
arcanisrepo
Еще эта строка смущает:
error = reading_coords (filename, type_inter, label_atom, cell, &num_mol,
                            &num_atoms, true_label_mol, label_mol, type_atoms, coords);
Аргумент num_mol передается по ссылке и может быть изменен в функции. С первым возвращенным значением выделяется память при i==from. В других итерациях возвращенные значения num_mol могут быть другие, и манипуляции с элементами массивов могут выходить за границы динамических областей, т.к. вложенные циклы зависят от этой переменной. Плюс, не производится проверка успеха вызова reading_coords.
arcanis
че т там много букв, мне страшно)
Программа собрана, как советуют, с -g -O0?

arcanis
До освобождения памяти стоит как раз эта функция, которая печатает в файл. она прорабатывается до конца без ошибок, т.е. падает именно на освобождении памяти. И именно конкретных 3х массивов (неважно где освобождать память).
Интересно, а если забить на освобождение памяти? Вроде при завершении программы она должна автоматом освобождаться?


Вариант - попробовать собрать clang-ом с Address Sanitizer.

На stackoverflow встречаются подобные проблемы.
kurych
Аргумент num_mol передается по ссылке и может быть изменен в функции. С первым возвращенным значением выделяется память при i==from. В других итерациях возвращенные значения num_mol могут быть другие, и манипуляции с элементами массивов могут выходить за границы динамических областей, т.к. вложенные циклы зависят от этой переменной. Плюс, не производится проверка успеха вызова reading_coords.
так и задумано - он определяется именно в этой функции (вместе с большинством аргументов, которые передаются ссылками). То что он может быть изменен - да (в теории), но не задумано программой (и входными данными) априори. К тому же, как я говорил выше, для теста используется только 1 проход по циклу.
sirocco
Программа собрана, как советуют, с -g -O0?
мм, неа. Пересобрал, вроде вывод не изменился. Ну бОльшая часть ругани там на вызовы типа:
a = atoi (&string[n]);
(к массивам, на которых крашится эти команды отношения не имеют - num_mol и num_mol_agl набираются "++", обнуление в начале есть)
sirocco
Интересно, а если забить на освобождение памяти? Вроде при завершении программы она должна автоматом освобождаться?
в этом плане да, я уже думал - все рабочее вроде как, утечки памяти быть не может здесь. Но вроде как уже самому интересно, что там не так. За ссылку спасибо, видел уже подобное, правда решений (объяснений) внятных так и не увидел
PGP 0x31361F01
arcanisrepo
Если временно собрать программу с закомментированным вызовом summary_statistic, ошибка все равно вылетает?
 
Зарегистрироваться или войдите чтобы оставить сообщение.