Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.88/8: Рейтинг темы: голосов - 8, средняя оценка - 4.88
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
#1

Теория по динамической памяти

13.12.2012, 06:06. Просмотров 1485. Ответов 41
Метки нет (Все метки)

Предположим, применяется оператор new в форме для массива:
C++
1
p=new int [n];
. n ведь может быть и большим. Может n==1000000? Где запоминается, сколько выделено памяти и откуда система знает, сколько надо освободить памяти по
C++
1
delete [] p;
? Ведь там то я n не указываю. Может надо освободить сразу много страниц? Освобождаются все страницы, расположенные подряд? Эйси. А если я сначала выделили две страницы, а потом ещё три и все пять оказались подряд? А освобождаю сначала две? За счёт чего система заберёт только первую страницу, а не все пять? Или они не могут быть подряд?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.12.2012, 06:06
Ответы с готовыми решениями:

Выделение динамической памяти
Всем привет. Возникла задача, в которой мне необходимо знать как выделяется...

Освобождение динамической памяти
После первого вызова функции(при повторном) пишет ошибку. В функции sort один...

Удаление динамической памяти
Всем здрасьте. Имеется вот такая структура. struct ModelType { DWORD FVF;...

Вопросы по динамической памяти.
У меня вопросы по работе с динамической памятью. Пожалуйста, помогите...

Перераспределение динамической памяти
дан двумерный массив 3х5 выделить динамически память под него, затем...

41
Vourhey
Почетный модератор
6491 / 2265 / 185
Регистрация: 29.07.2006
Сообщений: 12,534
13.12.2012, 06:16 #2
Цитата Сообщение от taras atavin Посмотреть сообщение
Где запоминается, сколько выделено памяти
Например, пишется в область перед выделенным буфером.
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
13.12.2012, 08:44  [ТС] #3
То есть дополнительный size_t перед самим блоком? А как оно в винде на самом деле? И может ли к этой инфе достучаться прилада? Чтоб не дублировать её каунтом.

Добавлено через 1 час 4 минуты
Такой:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
int main()
{
 int    *p;
 size_t *s;
 int     i;
 int     start;
 std::cin>>start;
 for (i=1; i<=16; ++i)
 {
  p=new int [i*start];
  s=(size_t*)p;
  std::cout<<i<<", "<<i*start<<", "<<(*s-1)<<std::endl;
  delete [] p;
 }
 return 0;
}
тест показал, что там мусор.
0
aLarman
644 / 565 / 164
Регистрация: 13.12.2012
Сообщений: 2,112
Завершенные тесты: 1
13.12.2012, 09:55 #4
Цитата Сообщение от taras atavin Посмотреть сообщение
То есть дополнительный size_t перед самим блоком?
нет не там) читай http://www.cplusplus.com/reference/new/operator%20new[]/

Добавлено через 57 секунд
и это http://www.cplusplus.com/reference/new/operator%20delete[]/
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
13.12.2012, 10:59  [ТС] #5
Ещё: откуда new знает, можно ли выделить память в уже имеющейся странице, или уже нет?

Добавлено через 6 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
int main()
{
 int *p[16];
 int  i;
 for (i=15; i>=0; --i)
 {
  p[i]=new int [16];
 }
 for (i=15; i>=0; --i)
 {
  std::cout<<i<<", "<<p[i];
  if (i>0)
  {
   std::cout<<", "<<(p[i]-p[i-1]);
  }
  std::cout<<std::endl;
 }
 for (i=15; i>=0; --i)
 {
  delete [] p;
 }
 return 0;
}
показывает, что иногда несколько раз выделяется память в одной и той же странице.

Добавлено через 17 минут
Цитата Сообщение от aLarman Посмотреть сообщение
нет не там) читай http://www.cplusplus.com/reference/new/operator%20new[]/
Добавлено через 57 секунд
и это http://www.cplusplus.com/reference/n...rator%20delete[]/
Как применять я знаю и так. А откуда известно, использована ли страница полностью, или нет и какие именно байты из неё можно выдать?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
int main()
{
 int *p[16];
 int  i;
 for (i=15; i>=0; --i)
 {
  p[i]=new int [2];
 }
 for (i=15; i>=0; --i)
 {
  std::cout<<i<<", "<<p[i];
  if (i>0)
  {
   std::cout<<", "<<(p[i-1]-p[i])<<", "<<((p[i-1]-p[i])/sizeof(int));
  }
  std::cout<<std::endl;
 }
 for (i=15; i>=0; --i)
 {
  delete [] p;
 }
 return 0;
}
показывает, что могут быть выданы много адресов в одной странице. Кстати, почему-то шаг равен размеру одного инта. Откуда делит знает, можно ли у прилады забрать всю страницу?

Добавлено через 30 минут
Сам прогнал, не учёл, что вычитание даёт разницу в сайзофах, а не байтах.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
int main()
{
 int *p[16];
 char *v1;
 char *v2;
 int  i;
 size_t t;
 for (i=15; i>=0; --i)
 {
  p[i]=new int [2];
 }
 for (i=15; i>=0; --i)
 {
  std::cout<<i<<", "<<p[i];
  if (i>0)
  {
   v1=(char *)p[i];
   v2=(char *)p[i-1];
   t=v2-v1;
   std::cout<<", "<<t<<", "<<(t/sizeof(int));
  }
  std::cout<<std::endl;
 }
 for (i=15; i>=0; --i)
 {
  delete [] p;
 }
 return 0;
}
Выделяет почти вплотную.
0
aLarman
644 / 565 / 164
Регистрация: 13.12.2012
Сообщений: 2,112
Завершенные тесты: 1
13.12.2012, 16:15 #6
Цитата Сообщение от taras atavin Посмотреть сообщение
for (i=15; i>=0; --i)
{
delete [] p;
}
кажется
C++ (Qt)
1
2
3
4
for (i=15; i>=0; --i)
 {
 delete [] p[i];
 }
ну это не суть
в твоем примере тут
C++ (Qt)
1
2
3
4
for (i=15; i>=0; --i)
 {
  p[i]=new int [2];
 }
оператор new выделяет память на 2 элемента типа int и возвращает указатель на начало этого массива, который в итоге записывается в p[i].То, что он должен выделять эти 16 массивов по 2 элемента не означает, что они будут находиться в памяти линейно- где выделилось на то и вернул указатель)
0
Vourhey
Почетный модератор
6491 / 2265 / 185
Регистрация: 29.07.2006
Сообщений: 12,534
13.12.2012, 17:03 #7
Цитата Сообщение от taras atavin Посмотреть сообщение
То есть дополнительный size_t перед самим блоком?
Да.
Цитата Сообщение от taras atavin Посмотреть сообщение
тест показал, что там мусор.
Не смотрел, какой у тебя тест, у меня все нормально:
$ cat ./main.cpp
#include <iostream>

int main()
{
char *a = new char[16];
std::cout<<(long long)*(a-8)<<std::endl;
}
$ g++ main.cpp
$ ./a.out
33
33 - потому что new выделяет память дополнительно к тому, что была запрошена.
Если увеличить кол-во памяти, которое нужно, например, до 64:
$ cat main.cpp
#include <iostream>

int main()
{
char *a = new char[64];
std::cout<<(long long)*(a-8)<<std::endl;
}
$ g++ main.cpp
$ ./a.out
81
Видно, что разница опять на 17.

Добавлено через 15 минут
Цитата Сообщение от Vourhey Посмотреть сообщение
Цитата Сообщение от taras atavin Посмотреть сообщение
То есть дополнительный size_t перед самим блоком?
Да.
Точнее, почти
2
aLarman
644 / 565 / 164
Регистрация: 13.12.2012
Сообщений: 2,112
Завершенные тесты: 1
13.12.2012, 17:14 #8
Цитата Сообщение от Vourhey Посмотреть сообщение
Не смотрел, какой у тебя тест, у меня все нормально:
$ cat ./main.cpp
#include <iostream>
int main()
{
char *a = new char[16];
std::cout<<(long long)*(a-8)<<std::endl;
}
$ g++ main.cpp
$ ./a.out
33
33 - потому что new выделяет память дополнительно к тому, что была запрошена.
сделал что то подобное
C++
1
2
3
4
5
int *pInt;
    pInt = new int[10];
    for(int i=0;i<10;i++)
        pInt[i]=i;
    cout<<*(pInt-1)<<endl;
при каждом запуске разные числа и я почему то не удивлен) например сейчас получил -33686019

Добавлено через 3 минуты
хотя нет оно не меняется, ибо является мусором и видимо его никто не переписывает, даже если я меняю размер исходного массива, число не меняется) так что не там хранится размер массива)

Добавлено через 3 минуты
Vourhey, а твой пример выдал -98 и так же не меняется с изменением размера массива)
0
Vourhey
Почетный модератор
6491 / 2265 / 185
Регистрация: 29.07.2006
Сообщений: 12,534
13.12.2012, 17:15 #9
Цитата Сообщение от aLarman Посмотреть сообщение
при каждом запуске разные числа и я почему то не удивлен)
Наверное, потому что ты невнимателен.

Добавлено через 38 секунд
Цитата Сообщение от aLarman Посмотреть сообщение
Vourhey, а твой пример выдал -98 и так же не меняется с изменением размера массива)
Ты почитай мое первое сообщение, чтобы глупых вопросов больше не возникало.
0
aLarman
644 / 565 / 164
Регистрация: 13.12.2012
Сообщений: 2,112
Завершенные тесты: 1
13.12.2012, 17:20 #10
твой пример работает не так как ты пишешь, у меня в частности, проверь сам, что бы не было глупых ответов)
0
Vourhey
Почетный модератор
6491 / 2265 / 185
Регистрация: 29.07.2006
Сообщений: 12,534
13.12.2012, 17:44 #11
Цитата Сообщение от aLarman Посмотреть сообщение
твой пример работает не так как ты пишешь, у меня в частности, проверь сам, что бы не было глупых ответов)
Тяжелый случай...
Цитата Сообщение от Vourhey Посмотреть сообщение
Например, пишется в область перед выделенным буфером.
Слово "например" тебе о чем-то говорит? Тебе оно должно было сказать, что "это зависит от реализации" и один из вариантов - блок перед буфером. Это так же работает не только в g++ Linux, но и в VxWorks.
То, как это работает у тебя - это будет другое "например", поэтому ответь автору по-нормальному, а не пытайся доказать то, что заранее неправда, так как, вариантов несколько.

Добавлено через 17 минут
Цитата Сообщение от aLarman Посмотреть сообщение
int *pInt; pInt = new int[10]; for(int i=0;i<10;i++) pInt[i]=i; cout<<*(pInt-1)<<endl;
Если запускать его в студии, то я бы поменял вот так:
C++
1
2
3
4
5
    int *pInt;
    pInt = new int[10];
    for(int i=0;i<10;i++)
        pInt[i]=i;
    cout<<*(pInt-4)<<endl;
И вывод - 40. Что и есть 10 * размер int. Если поменяю на:
C++
1
pInt = new int[128];
То вывод - 512
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
13.12.2012, 17:49  [ТС] #12
Если я триллион раз выделю память и освобожу указатель, то по методе "каждый следующий выделяется впереди" уйдём за границу адресного пространства. По кругу нельзя, так удаляться и снова выделяться мог второй по порядку указатель, а первый существовать всегда. Если выделять только целыми страницами то другая пакость. Может у меня 67108864 динамичских массива по 32 чара? Перерасход адресного пространства в 32768, так как в странице можно разместить 1048576 байт. + уйдём за физическую память, та как страница виртуальной памяти занимает столько же и в физической. А если разделять терминальными страницами, то адресное пространство будет исчерпано в 2 раза быстрее физической памяти. Как ни крути, надо вести учёт байтов, а не страниц. Как это делается в винде?
0
Vourhey
Почетный модератор
6491 / 2265 / 185
Регистрация: 29.07.2006
Сообщений: 12,534
13.12.2012, 17:49 #13
Ну и так...чисто посмотреть на "мусор" в памяти, если брать винду:
Теория по динамической памяти
0
v.a.l.i.d
416 / 381 / 113
Регистрация: 21.09.2012
Сообщений: 913
13.12.2012, 17:50 #14
Vourhey, Напишите, пожалуйста, как найти количество элементов в дин. массиве float и double. Для int вот это работает
C++
1
cout << "Количество элементов в динамическом массиве: " << *(a - sizeof(a[0])) / sizeof(a[0]) << endl;
а вот для float и double почему то не получается
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
13.12.2012, 17:55  [ТС] #15
Цитата Сообщение от Vourhey Посмотреть сообщение
И вывод - 40. Что и есть 10 * размер int. Если поменяю на:
У меня при некоторых размерах наблюдается несколько лишних не выделенных интов между выделенными.

Добавлено через 3 минуты
Цитата Сообщение от v.a.l.i.d Посмотреть сообщение
(a - sizeof(a[0])) / sizeof(a[0]) << endl;
Это работает со статическими. И без разности.
0
Vourhey
Почетный модератор
6491 / 2265 / 185
Регистрация: 29.07.2006
Сообщений: 12,534
13.12.2012, 18:03 #16
Цитата Сообщение от v.a.l.i.d Посмотреть сообщение
Vourhey, Напишите, пожалуйста, как найти количество элементов в дин. массиве float и double. Для int вот это работает
Я вот так сделал: (под виндой, vs 2012)
C++
1
2
3
    float *pInt;
    pInt = new float[32];
    cout<<(int)*((int*)pInt-4)<<endl;
Вывод - 128

Добавлено через 6 минут
taras atavin, насколько я помню (но могу и ошибаться), то каждый последующий не "впереди" выделяется, а ищется свободный непрерывный блок памяти. Он может быть не обязательно "впереди". Но это уже, скорее, относится к менеджеру памяти конкретной ОС, а не к С++.
1
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
13.12.2012, 18:04  [ТС] #17
И без квадратных скобок в числителе. А прямо так даже не компилится: указатели на сайзофы не деляться.
0
v.a.l.i.d
416 / 381 / 113
Регистрация: 21.09.2012
Сообщений: 913
13.12.2012, 18:08 #18
Цитата Сообщение от taras atavin Посмотреть сообщение
Это работает со статическими.
Ну я не знаю. Сейчас делал так и все получается. Вот эта программа у меня всегда правильно результат показывает
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "stdafx.h"
#include "iostream"
using namespace std;
 
int _tmain(int argc, _TCHAR* argv[])
{
    setlocale(LC_ALL, "Russian");
 
    unsigned int arr_size;
 
    cout << "Введите размер массива: ";
    cin >> arr_size;
 
    int *a = new int[arr_size];
 
    for (int i=0; i<arr_size; i++)
        *(a + i) = (i+1)*10;
 
    cout << "Количество элементов в динамическом массиве int: " << (int)*((int*)a-4) / sizeof(*(a+0)) << endl << endl;
 
    delete [] a;
 
    system("pause")
    return 0;
}
Извиняюсь, не то
0
taras atavin
4204 / 1764 / 211
Регистрация: 24.11.2009
Сообщений: 27,565
13.12.2012, 18:11  [ТС] #19
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
int main()
{
 int *p[16];
 char *v1;
 char *v2;
 int *b;
 int  i;
 size_t t;
 size_t n;
 size_t *s;
 std::cin>>n;
 for (i=15; i>=0; --i)
 {
  p[i]=new int [n];
 }
 for (i=15; i>=0; --i)
 {
  std::cout<<i<<", "<<p[i];
  if (i>0)
  {
   v1=(char *)p[i];
   v2=(char *)p[i-1];
   t=v2-v1;
   s=(size_t *)p[i];
   --s;
   std::cout<<", "<<t<<", "<<(t/sizeof(int))<<", "<<(*s)<< std::endl;
  }
  std::cout<<std::endl;
 }
 for (i=15; i>=0; --i)
 {
  delete [] p;
 }
 return 0;
}
В конце всех строк 1134233773. n вводил 20.

Добавлено через 1 минуту
Цитата Сообщение от v.a.l.i.d Посмотреть сообщение
*(a - sizeof(a[0])) / sizeof(a[0]) << endl;
А, там ещё звёздочка. Щас попробую.

Добавлено через 1 минуту
C++
1
std::cout<<i<<", "<<p[i]<<", "<<(*(p[i] - sizeof(p[i][0]))) / sizeof(p[i][0]);
Выводит 0.
0
ValeryS
Модератор
7170 / 5437 / 674
Регистрация: 14.02.2011
Сообщений: 18,372
13.12.2012, 18:22 #20
Цитата Сообщение от v.a.l.i.d Посмотреть сообщение
"Количество элементов в динамическом массиве: " << *(a - sizeof(a[0])) / sizeof(a[0])
я вообще то всегда так делал
C++
1
sizeof(a) / sizeof(a[0])
где
sizeof(a) размер всего массива в байтах
sizeof(a[0]) размер первого элемента в байтах
можно написать так (например для double)
C++
1
sizeof(a) / sizeof(double)
0
13.12.2012, 18:22
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
13.12.2012, 18:22

Перераспределение динамической памяти
дан двумерный массив 3х5 выделить динамически память под него, затем...

выделение динамической памяти
помогите пожалуйста , нужно написать функцию для ввода новой матрицы, не...

Удаление new из динамической памяти
Здравствуйте, у меня есть следующее присвоение: sign-&gt;numb = new int; Мне...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru