Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 13.10.2016, 11:22   #1
v4567
Пользователь
 
Регистрация: 06.07.2008
Сообщений: 91
По умолчанию динамическое выделение памяти под структуры

Есть вот такая структура:
Код:
struct asd
{
 int data;
 struct asd *next;
};
Динамически выделяю память под такую структуру:

Код:
struct asd *newst(struct asd *head)
{
 struct asd *newstructura;
 newstructura = (struct asd *)malloc(sizeof(struct asd));
 newstructura -> next = head;
 return newstructura;
}
Потом в основном теле программы инициализирую несколько таких структур с динамическим выделением памяти под каждую:

Код:
int i, n = 20;
struct asd *head;
head = NULL;

for(i = 0; i < n; i++)
{
 head = newst(head);
}
Вопрос можно ли перемещаться по структурам меняя указатель head вот таким образом head-- или head++
Я думаю что нельзя, хотя написал небольшую тестовую программку и всё работает. Но работает я думаю из-за того, что данные структуры занимают очень мало места в памяти и при выделении памяти они все будут в одном месте, поэтому меняя указатель head - head-- или head++ мы будем перемещаться по структурам. Но если бы структуры были очень большими и их было очень много, то, есть вероятность, что одна часть их будет расположена в одном месте, а другая в другом месте памяти и тогда перемещаться по структурам меняя head не получиться.
Хотелось бы узнать правильно я думаю или ошибаюсь!
Правильно перемещаться по структурам надо наверное так:

Код:
int i, n = 20;
struct asd *head;
head = NULL;

for(i = 0; i < n; i++)
{
 head = newst(head);
}

struct asd *p;
p = head;
p = p -> next;
Исходя из этого перемещаться можно сверху вниз и если нужно подняться на одну структуру вверх, то надо переместиться в самый вверх, а потом опуститься до нужной структуры. Можно ли как то произвольно гулять по структурам?

Следующий непонятный момент вот какой. После выделения памяти под структуры и поработав с ними, освобождаю память free(head), head в данном случае указывает на самую верхнюю структуру.
В интернете вычитал вот что:
free
Цитата:
Освобождение памяти с помощью free

Теперь рассмотри, как происходит освобождение памяти. Переменная указатель хранит адрес области памяти, начиная с которого она может им пользоваться. Однако, она не хранит размера этой области. Откуда тогда функция free знает, сколько памяти необходимо освободить?

Очевидно, что информация о размере выделенного участка должна где-то храниться. Есть несколько решения этой проблемы.
1. Можно создать карту, в которой будет храниться размер выделенного участка. Каждый раз при освобождении памяти компьютер будет обращаться к этим данным и получать нужную информацию.
2. Второе решение более распространено. Информация о размере хранится на куче до самих данных. Таким образом, при выделении памяти резервируется места больше и туда записывается информация о выделенном участке. При освобождении памяти функция free "подсматривает", сколько памяти необходимо удалить.
Функция free освобождает память, но при этом не изменяет значение указателя, о чём нужно помнить.
Но у меня почему то при освобождении памяти выдаёт ошибку хотя до освобождения памяти программа работает нормально:

Код:
*** glibc detected *** ./yrok161: double free or corruption (out): 0x0812e020 ***
======= Backtrace: =========
/lib/libc.so.6[0xb35231]
./yrok161[0x8048654]
/lib/libc.so.6(__libc_start_main+0xe6)[0xadba66]
./yrok161[0x8048411]
======= Memory map: ========
003e7000-00411000 r-xp 00000000 08:02 2237624    /lib/libgcc_s-4.4.0-20090506.so.1
00411000-00412000 rw-p 00029000 08:02 2237624    /lib/libgcc_s-4.4.0-20090506.so.1
00a77000-00a78000 r-xp 00a77000 00:00 0          [vdso]
00a9d000-00abd000 r-xp 00000000 08:02 2236420    /lib/ld-2.10.1.so
00abd000-00abe000 r--p 0001f000 08:02 2236420    /lib/ld-2.10.1.so
00abe000-00abf000 rw-p 00020000 08:02 2236420    /lib/ld-2.10.1.so
00ac5000-00c30000 r-xp 00000000 08:02 2236959    /lib/libc-2.10.1.so
00c30000-00c31000 ---p 0016b000 08:02 2236959    /lib/libc-2.10.1.so
00c31000-00c33000 r--p 0016b000 08:02 2236959    /lib/libc-2.10.1.so
00c33000-00c34000 rw-p 0016d000 08:02 2236959    /lib/libc-2.10.1.so
00c34000-00c37000 rw-p 00c34000 00:00 0
08048000-08049000 r-xp 00000000 08:02 7955556
08049000-0804a000 rw-p 00000000 08:02 7955556
0812e000-0814f000 rw-p 0812e000 00:00 0          [heap]
b7efe000-b7f00000 rw-p b7efe000 00:00 0
b7f29000-b7f2b000 rw-p b7f29000 00:00 0
bfa15000-bfa2a000 rw-p bffeb000 00:00 0          [stack]
Аварийный останов
И последний вопрос надо ли после освобождения памяти обнулять указатель head: head = NULL?

Вот моя небольшая тестовая программка:

Код:
#include <stdio.h>
#include <stdlib.h>

struct asd
{
 int data;
 struct asd *next;
};

struct asd *newst(struct asd *);
void zdan(struct asd *, int);
int vivod(struct asd *);

void main(void)
{
 int i, n;
 struct asd *head;
 head = NULL;

 scanf("%d", &n);

 for(i = 0; i < n; i++)
 {
  head = newst(head);
 }

 for(i = 0; i < (n - 1); i++)
 {
  head--;
 }

 for(i = 0; i < n; i++)
 {
  zdan(head, i);
  if(i != (n - 1))
  {
   head++;
  }
 }

 for(i = 0; i < (n - 1); i++)
 {
  head--;
 }

 for(i = 0; i < n; i++)
 {
  printf("%d", vivod(head));
  if(i != (n - 1))
  {
   printf(" --> ");
   head++;
  }
 }
 printf("\n");

 for(i = 0; i < n; i++)
 {
  printf("%d", vivod(head));
  if(i != (n - 1))
  {
   printf(" --> ");
   head--;
  }
 }
 printf("\n");

 if(i != (n - 1))
 {
  head++;
 }
 free(head);
 head = NULL;
}

struct asd *newst(struct asd *head)
{
 struct asd *newstructura;
 newstructura = (struct asd *)malloc(sizeof(struct asd));
 newstructura -> next = head;
 return newstructura;
}

void zdan(struct asd *head, int x)
{
 head -> data = x;
}

int vivod(struct asd *head)
{
 return head -> data;
}
Компилирую командой:

Код:
gcc -o yrok161 yrok161.c
За помощь заранее благодарен!
v4567 вне форума Ответить с цитированием
Старый 13.10.2016, 11:59   #2
New man
Форумчанин
 
Регистрация: 24.01.2011
Сообщений: 774
По умолчанию

Цитата:
Вопрос можно ли перемещаться по структурам меняя указатель head вот таким образом head-- или head++
Я думаю что нельзя, хотя написал небольшую тестовую программку и всё работает. Но работает я думаю из-за того, что данные структуры занимают очень мало места в памяти и при выделении памяти они все будут в одном месте, поэтому меняя указатель head - head-- или head++ мы будем перемещаться по структурам. Но если бы структуры были очень большими и их было очень много, то, есть вероятность, что одна часть их будет расположена в одном месте, а другая в другом месте памяти и тогда перемещаться по структурам меняя head не получиться.
Хотелось бы узнать правильно я думаю или ошибаюсь!
Правильно перемещаться по структурам надо наверное так:
Всё верно думаешь.

При выполнении оператора ++ и -- к указателю, происходит перемещение по адресу на размер типа структуры.
Ты всё выделяешь в цикле, поэтому у тебя все они рядом.

Движение по структуре верно.


Для доступа к любому элементу можно использовать два метода:
  1. Хранить отдельно голову и текущий указатель и двигаться начиная от головы.
  2. Сделать двусвязный список.
В двусвязном списке есть указатель на предыдущий элемент. Инициализация его происходит так:
Код:
struct asd *newst(struct asd *head)
{
 struct asd *newstructura;
 newstructura = (struct asd *)malloc(sizeof(struct asd));
 newstructura -> next = head;
 if(head){
    head.prev = newstructura;
 }
 newstructura->prev = NULL;
 return newstructura;
}
Ошибка у тебя получается из-за того, что ты пытаешься освободить NULL, а саму выделенную память не трогаешь.
Для освобождения нужной памяти тебе надо освобождать в цикле, начиная с головы:
Код:
while(head!=NULL){
    asd*  tmp = head;
    head = head->next;
    free(tmp);
}
a.k.a. Angelicos Phosphoros
Мой сайт

Последний раз редактировалось New man; 13.10.2016 в 12:08.
New man вне форума Ответить с цитированием
Старый 13.10.2016, 12:07   #3
v4567
Пользователь
 
Регистрация: 06.07.2008
Сообщений: 91
По умолчанию

New man спасибо за помощь!
Только хотел уточнить. Если в цикле выделял память, структуры всегда одна за одной будут располагаться, или не обязательно?
Если не обязательно, то выделяя в цикле память, перемещаться по head--, head++ выходит нельзя.
v4567 вне форума Ответить с цитированием
Старый 13.10.2016, 12:57   #4
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,708
По умолчанию

Цитата:
Если в цикле выделял память, структуры всегда одна за одной будут располагаться, или не обязательно?
Как повезет... Если свободной памяти у процесса будет много. Если найденного фрагмента будет достаточно под все структуры. Если в процессе цикла менеджер памяти не обнаружит более подходящее место для структуры. И т.д.

Цитата:
Если не обязательно, то выделяя в цикле память, перемещаться по head--, head++ выходит нельзя.
Нельзя. Это авось и повезло. Не зря есть массивы и связные списки.
p51x вне форума Ответить с цитированием
Старый 13.10.2016, 13:30   #5
v4567
Пользователь
 
Регистрация: 06.07.2008
Сообщений: 91
По умолчанию

p51x огромное спасибо!

Теперь осталось уяснить моменты с free.
v4567 вне форума Ответить с цитированием
Старый 13.10.2016, 13:57   #6
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,708
По умолчанию

А что с free не понятно? Вы ей указатель она грит системе, что память ее.
p51x вне форума Ответить с цитированием
Старый 13.10.2016, 14:35   #7
v4567
Пользователь
 
Регистрация: 06.07.2008
Сообщений: 91
По умолчанию

free передаю указатель на начало списка структур, но вываливаются ошибки и аварийный останов. Не пойму в чём моя ошибка.
v4567 вне форума Ответить с цитированием
Старый 13.10.2016, 15:06   #8
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,708
По умолчанию

Поставьте точку останова и посмотрите, чему указатель равен. Может он нулл.
p51x вне форума Ответить с цитированием
Старый 13.10.2016, 15:59   #9
pproger
C++ hater
СтарожилДжуниор
 
Аватар для pproger
 
Регистрация: 19.07.2009
Сообщений: 3,333
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
Поставьте точку останова и посмотрите, чему указатель равен. Может он нулл.
ну может и нулл, что с того?
I invented the term Object-Oriented, and I can tell you I did not have C++ in mind. (c)Alan Kay

My other car is cdr.

Q: Whats the object-oriented way to become wealthy?
A: Inheritance
pproger вне форума Ответить с цитированием
Старый 13.10.2016, 17:51   #10
New man
Форумчанин
 
Регистрация: 24.01.2011
Сообщений: 774
По умолчанию

Цитата:
Сообщение от v4567 Посмотреть сообщение
New man спасибо за помощь!
Только хотел уточнить. Если в цикле выделял память, структуры всегда одна за одной будут располагаться, или не обязательно?
Если не обязательно, то выделяя в цикле память, перемещаться по head--, head++ выходит нельзя.
Если тебе надо юзать эти операторы, то может лучше использовать массивы?
Код:
size_t size = ввод;
int * arr = (int*)malloc(size*sizeof(int));

// можно ходить по массиву так:
for(int* iterator = arr; iterator!=arr+size;iterator++){
   *iterator = 5;
}
А вообще, я как-то писал свою реализацию связного списка. Там можно было перемещаться так с помощью итератора, но это был кровавый C++, а не C.
a.k.a. Angelicos Phosphoros
Мой сайт
New man вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Динамическое выделение памяти под матрицу. Не понимаю как работает. Че Гевара Общие вопросы C/C++ 8 03.06.2013 17:48
Язык СИ! Динамическое выделение памяти под массивы и матрицы, передача матрицы в функции Андрей! Общие вопросы C/C++ 33 31.01.2012 22:07
Динамическое выделение памяти под массив объектов со специализированным конструктором capta1n Общие вопросы C/C++ 6 07.03.2010 16:01
динамическое выделение памяти под верхний треугольник квадратной матрицы juventine Помощь студентам 2 12.04.2009 13:02
Динамическое выделение памяти под массивы Артем125 Общие вопросы C/C++ 4 07.04.2009 09:52