Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
#1

Динамический массив указателей - C++

04.09.2010, 08:34. Просмотров 25830. Ответов 28
Метки нет (Все метки)

Чегото не пойму такое вообще возможно?
Странно, что при объявлении можно не указывать размерность: int *a[];
Но как потом память выделять не известно.

Добавлено через 2 минуты
p.s. прошу не путать с указателем на массив.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nick Alte
Эксперт С++
1599 / 991 / 117
Регистрация: 27.09.2009
Сообщений: 1,910
Завершенные тесты: 1
04.09.2010, 15:19     Динамический массив указателей #2
Память обычно выделяется инициализацией:
C
1
2
int a, b, c;
int* array[] = {&a, &b, &c};
Day
 Аватар для Day
1152 / 957 / 57
Регистрация: 29.10.2009
Сообщений: 1,384
05.09.2010, 22:26     Динамический массив указателей #3
darkAngel, объявление int *a[]; эквивалентно int **a;
А память выделяется так:
C
1
2
3
  a = malloc(10*sizeof(int *));
  for(i=0; i<10; i++)
    a[i] = malloc((5+i)*sizeof(int));
Получится такая "косая" матрица
1-я строка - 5 элементов
2-я - 6
...
10-я - 14
А можно и по-другому, скажем чтоб все строки были одинаковы...
Это уж твое дело, управляешь этим ТЫ
easybudda
Эксперт С++
 Аватар для easybudda
9412 / 5435 / 917
Регистрация: 25.07.2009
Сообщений: 10,428
05.09.2010, 22:37     Динамический массив указателей #4
Цитата Сообщение от Day Посмотреть сообщение
darkAngel, объявление int *a[]; эквивалентно int **a;
Ничего подобного! Выражение int **a; обявляет указатель на указатель на int; а int *a[]; объявляет массив указателей, но в таком виде оно не правильно, и так даже не скомпилируется. Если при объявлении массива не указывается размер, вместе с объявлением должна быть инициализация значений, тогда компилятор вычисляет размер автоматически:
C
1
2
3
int **a; // при объявлении инициализация не требуется
int *b[] = { NULL, NULL, NULL }; // создаёт массив из трёх указателей, инициализирует их значением NULL
int *c[]; // выдаст ошибку при компиляции
Day
 Аватар для Day
1152 / 957 / 57
Регистрация: 29.10.2009
Сообщений: 1,384
05.09.2010, 22:44     Динамический массив указателей #5
easybudda, Приношу извинения. Ты прав.
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
06.09.2010, 08:13  [ТС]     Динамический массив указателей #6
int *b[] = { NULL, NULL, NULL };
Размер массива мне не известен заранее.
Массив указателей - это поле моего класса, на сколько объектов он будет ссылаться - будет известно лишь в процессе инициализации.
easybudda
Эксперт С++
 Аватар для easybudda
9412 / 5435 / 917
Регистрация: 25.07.2009
Сообщений: 10,428
06.09.2010, 09:05     Динамический массив указателей #7
Цитата Сообщение от darkAngel Посмотреть сообщение
Массив указателей - это поле моего класса, на сколько объектов он будет ссылаться - будет известно лишь в процессе инициализации.
На форуме полно примеров!

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
...
int **matrix, rows, columns;
/* инициализировать rows и columns */
matrix = new int* [ rows ];
for ( int i = 0; i < rows; ++i )
  matrix[i] = new int [ columns ];
...
for ( int i = 0; i < rows; ++i ){
  for ( int j = 0; j < columns; ++j ){
    /* что-то сделать с matrix[i][j] */
  }
}
...
for ( int i = 0; i < rows; ++i )
  delete [] matrix[i];
delete [] matrix;
...
C - стиль, с классами не использовать!
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
#include <stdlib.h>
#include <stdio.h>
...
int ** matrix, rows, columns, i, j;
/* инициализировать rows и columns */
if ( ( matrix = (int**)malloc(sizeof(int*) * rows) ) == NULL ){
  perror("malloc");
  exit(1);
}
for ( i = 0; i < rows; ++i ){
  if ( ( matrix[i] = (int*)malloc(sizeof(int) * columns) ) == NULL ){
    perror("malloc");
    exit(1);
  }
}
...
for ( i = 0; i < rows; ++i ){
  for ( j = 0; j < columns; ++j ){
    /* что-то сделать с matrix[i][j] */
  }
}
...
for ( i = 0; i < rows; ++i )
  free(matrix[i]);
free(matrix);
...
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
06.09.2010, 10:09  [ТС]     Динамический массив указателей #8
easybudda, арррр... попросил же не путать с указателем на массив.

То что вы предложили, выделяет память по элементы типа int. Мне же нужен массив указателей, элементы которого будут ссылатся на уже выделенные участки памяти.

Добавлено через 7 минут
p.s. вот, в кратце:
C++
1
2
3
4
5
6
7
8
9
10
11
12
struct top{   //Такой тип
...
};
top *N[50];   //Нужен такой массив указателей, только количество элементов мне не известно при компиляции
top *A;        //Указатель на массив, где последовательно хранятся элементы типа top
...
/*выделяем память под массив типа top, на начало которого ссылается указатель A*/
...
/*Теперь мне выборочно нужно ссылатся на некоторые элементы из множества A*/
N[0] = &A[3];
N[1] = &A[17];
N[2] = &A[22];
И повторяю, проблема в том, что не известна размерность массива N до компиляции
easybudda
Эксперт С++
 Аватар для easybudda
9412 / 5435 / 917
Регистрация: 25.07.2009
Сообщений: 10,428
06.09.2010, 10:42     Динамический массив указателей #9
Цитата Сообщение от darkAngel Посмотреть сообщение
И повторяю, проблема в том, что не известна размерность массива N до компиляции
Ну и в чём проблема?
C++
1
2
3
4
5
6
7
8
9
10
11
12
...
struct Top{
...
};
int tops_needed;
...
Top * tops = new Top [ tops_needed ];
for ( int i = 0; i < tops_needed; ++i )
  tops[i] = another_top_object;
...
delete [] tops;
...
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
06.09.2010, 10:52  [ТС]     Динамический массив указателей #10
В том что выделяется память и создаётся копия, а мне нужна не копия данных, а указатель на уже выделенную память.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Top{
int d;
...
};
int tops_needed;
...
Top A;                             //Создали объект A типа Top и инициализировали поле d
A.d = 5;              
 
Top * tops = new Top [ tops_needed ];
for ( int i = 0; i < tops_needed; ++i )
  [B]tops[i] = A;[/B]                            //Создали копию объекта A
 
A.d = 7;                    //Изменили значение поля d
Выводим данные:
A.d равно 7
tops[0].d равно 5
ибо копия
easybudda
Эксперт С++
 Аватар для easybudda
9412 / 5435 / 917
Регистрация: 25.07.2009
Сообщений: 10,428
06.09.2010, 11:33     Динамический массив указателей #11
Цитата Сообщение от darkAngel Посмотреть сообщение
выделяется память и создаётся копия, а мне нужна не копия данных, а указатель на уже выделенную память.
C++
1
2
3
4
5
6
7
8
9
10
11
...
Top a, b, c;
int numTops = 3;
Top ** pTops = new Top * [ numTops ];
pTops[0] = &a;
pTops[1] = &b;
pTops[2] = &c;
for ( int i = 0; i < numTops; ++i )
  std::cout << pTops[i]->d;
...
delete [] pTops;
for.joke
Сообщений: n/a
25.12.2010, 14:08     Динамический массив указателей #12
Цитата Сообщение от easybudda Посмотреть сообщение
Ничего подобного! Выражение int **a; обявляет указатель на указатель на int; а int *a[]; объявляет массив указателей, но в таком виде оно не правильно, и так даже не скомпилируется.
С помощью выражения int **a; можно спокойно создать динамический массив указателей)

Добавлено через 22 минуты
Вот допустим динамический массив указателей на объекты класса, с конструктором:
C++
1
2
3
4
5
6
ex::ex(char* s, int n)
{
    str=new char[strlen(s)+1];
    strcpy(str,s);
    num=n;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void main()
{
    int nm,n;
        cin>>n;
 
    ex **spisok= new ex*[n];
    char **temp=new char*[n];
    for(int i=0;i<n;i++)
        temp[i]=new char[50];
    
    for(int i=0;i<n;i++)
    {
        cin>>temp[i];
        cin>>nm;
        spisok[i]= new ex(temp[i], nm);
        cout<<spisok[i]->getstr()<<"\t"<<spisok[i]->getint()<<"\n";
    }
 
}
Izual
 Аватар для Izual
93 / 118 / 6
Регистрация: 13.11.2012
Сообщений: 1,531
27.12.2016, 18:56     Динамический массив указателей #13
Не хотел создавать новую тему.. а т.к. вопрос к месту, то думаю можно и тут:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void **ppv;
unsigned long long MXsize = 10;
int *pi=NULL, mi[]={7,10,5,3};
pi = mi;
 
ppv = new(nothrow) void* [MXsize]; // создали 10 указателей на указатели
if(ppv == NULL)
    return -3;
for(int i=0;i<MXsize;i++){ppv[i]=NULL;}
cout << "**ppv adress: " << &ppv << endl;
for(int i=0;i<MXsize;i++){cout << "**ppv[" << i << "] adress: " << &ppv[i];
if(ppv[i]==NULL) cout << ". No data" << endl;
else cout << ". data: " << ppv[i] << endl;}
ppv[0]=pi;
if(ppv[0]!=NULL) cout << "pInt-M[0] adress: " << ppv[0] << " and ppv[0] adress: " << &ppv[0] << " and data: " << *(int*)ppv[0] << endl;
else cout << "ppv[0] adress: " << &ppv[0] << " and it is NULL" << endl;
delete [] ppv;
Меня интересует, почему я не могу обратиться вместо этого: *(int*)ppv[0] как обычно вот так: ppv[0][0]
Компиллер MSVC выдаёт ошибку..
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
27.12.2016, 19:16  [ТС]     Динамический массив указателей #14
Цитата Сообщение от Izual Посмотреть сообщение
Меня интересует, почему я не могу обратиться вместо этого: *(int*)ppv[0] как обычно вот так: ppv[0][0]
потомучто у вас указатель типа void, а не int.

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

Добавлено через 4 минуты
И кстати в таком виде *(int*)ppv[0] вы указывате доступ только к первому элементу массива. Более точнее можно сделать так: ((int**)ppv)[i][j]

Сперва вы указываете, чтобы ваш массив ppv типа void** читался компилятором как тип int**, далее вы уже работаете с этим массивом как с массивом int и можете осуществлять обычный доступ через [i][j]

Добавлено через 4 минуты
Так, и кажется у вас там ошибки. Если вы хотите, чтобы ваш массив void хранил данные типа int, то вы должны явно выделять память для int, а не для void пеерменных (строка ppv = new(nothrow) void* [MXsize] и когда присваиваете значения к этому массиву, вы также должны делать явное приведение к тому типу, который присваиваете.

Вообще, зачем вам понадобился void, если вы явно потом используете int? Void обычно используется, если не известно заранее, на какой типа данных он будет указывать.
Izual
 Аватар для Izual
93 / 118 / 6
Регистрация: 13.11.2012
Сообщений: 1,531
27.12.2016, 19:28     Динамический массив указателей #15
Цитата Сообщение от darkAngel Посмотреть сообщение
((int**)ppv)[i][j]
Спасибки.

Цитата Сообщение от darkAngel Посмотреть сообщение
Компилятору нужно знать информацию о типе
Ну это понятно, что кастить надо, просто оно ни как не работало, вот и не стал писать.
Цитата Сообщение от darkAngel Посмотреть сообщение
Если вы хотите, чтобы ваш массив void хранил данные типа int, то вы должны явно выделять память для int, а не для void пеерменных
Не переменные, а указатели! А вот "указатели указателей" буду кастить.
По факту указатель любого типа - 4 байтный (в 32 битной ОС), так что выделяя память под указатели - чисто по логике вообще фиолетово что написать void или int, да что угодно..

Цитата Сообщение от darkAngel Посмотреть сообщение
зачем вам понадобился void, если вы явно потом используете int? Void обычно используется, если не известно заранее, на какой типа данных он будет указывать.
Потому что это лишь пример.. на самом деле всё будет "не известно", и под каждый тип будет свой каст.
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
27.12.2016, 22:57  [ТС]     Динамический массив указателей #16
Цитата Сообщение от Izual Посмотреть сообщение
По факту указатель любого типа - 4 байтный (в 32 битной ОС), так что выделяя память под указатели - чисто по логике вообще фиолетово что написать void или int, да что угодно..
Потом захотите на другой машине скомпилировать и все вылезет. Особенно с учетом зоопарка архитектур в наши дни.
Izual
 Аватар для Izual
93 / 118 / 6
Регистрация: 13.11.2012
Сообщений: 1,531
28.12.2016, 00:53     Динамический массив указателей #17
Цитата Сообщение от darkAngel Посмотреть сообщение
на другой машине скомпилировать и все вылезет
Для 64 битки буду писать отдельно в любом случае... (если вообще буду)

На самом деле тут посидел подумал, и стало интересно что за касты такие интересные..
((int**)ppv)[i][j] - тут вроде как две звёздочки приводят ppv к типу "указатель на указатель типа инт".(т.е. получение значения указателя указателя.. *только плз без слова "разименовывание", т.к. оно как то по русски не сочитается с реальным действием)
А вот расставление скобок я таки не совсем доганал.. хотел было убрать большую скобку.. ан нет, компилер не дал этого сделать.
*(int*)ppv[0] - да и это я написал набум, ну чисто по логике было понятно что нужно нечто подобное.. ну и бумкнуло с 3 попытки))
Кстати, а каков порядок выполнения действий у данных примеров получения значения? Т.е. 1 - каст к птр.инт, 2 - извлечение значений из обоих указателей?
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
28.12.2016, 01:31  [ТС]     Динамический массив указателей #18
Разница между ((int**)ppv)[i][j] и (int**)ppv[i][j] в порядке выполнения операций.
В 1 варианте сперва указатель типа void** приводится к типу int**, а после этого просиходят операции доступа. Квадратные скобки транслируют компилятором в смещения в памяти.
Во 2 варианте сперва просиходит доступ к элементам типа void**: после первых квадратных скобок мы получаем указатель на void*, а после вторых - void. И после этого уже пытаемся привести тип void к типу int**. И разумеется компилятор ругается
Izual
 Аватар для Izual
93 / 118 / 6
Регистрация: 13.11.2012
Сообщений: 1,531
28.12.2016, 02:23     Динамический массив указателей #19
Цитата Сообщение от darkAngel Посмотреть сообщение
((int**)ppv)[i][j]
Цитата Сообщение от darkAngel Посмотреть сообщение
сперва указатель типа void** приводится к типу int**, а после этого просиходят операции доступа. Квадратные скобки транслируют компилятором в смещения в памяти.
Значит:
1) "Вы хотите обратиться к ppv?" - говорит компиллер
2) Кастуем к инт.птр
3) Считаем где там этот [i][j]
4) Запрашиваем данные
Ну вроде логично, за исключением того, нафига он кастует перед тем как получить адрес [i][j]? Логичнее, имхо, было бы сначала получить искомый адрес, а уже потом через каст получить значение. (ведь каст означает, что мы хотим прочитать опр. кол-во байт по правилу int.

Цитата Сообщение от darkAngel Посмотреть сообщение
(int**)ppv[i][j]
Цитата Сообщение от darkAngel Посмотреть сообщение
сперва просиходит доступ к элементам типа void**: после первых квадратных скобок мы получаем указатель на void*, а после вторых - void. И после этого уже пытаемся привести тип void к типу int**. И разумеется компилятор ругается
Ну ежели по вашей логике, то получается что кастовать в 2ом случае нужно к int, а не к int**?

Я бы хотел чтоб порядок действий, если это возможно, совпадал бы с тем как я предпочёл бы чтоб это работало(если это вообще возможно).. т.е. так как ты* написал в 2ом варианте, т.е. чтоб компиллер сначала бы получил искомый адрес ppv[i][j], а уже потом кастом бы выдал мне DWORD (int_32).
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
28.12.2016, 02:51     Динамический массив указателей
Еще ссылки по теме:

C++ Динамический массив с использованием указателей
C++ Динамический массив указателей на объекты класса
Динамический массив указателей(не пойму в чем ошибка в коде) C++
Динамический массив указателей на структуру C++
C++ Как сделать динамический массив из указателей?

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

Или воспользуйтесь поиском по форуму:
darkAngel
Технофашист
211 / 192 / 4
Регистрация: 11.03.2009
Сообщений: 850
28.12.2016, 02:51  [ТС]     Динамический массив указателей #20
Izual, такой вариант еще ((int*)ppv[i])[j]

Добавлено через 4 минуты
В таком виде (int)ppv[i][j] мой MinGW выдает
C++
1
error: 'void*' is not a pointer-to-object type
По-моему все предельно понятно.
Yandex
Объявления
28.12.2016, 02:51     Динамический массив указателей
Ответ Создать тему
Опции темы

Текущее время: 04:49. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru