Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
640KB мне хватило на всё.
119 / 50 / 3
Регистрация: 07.06.2009
Сообщений: 442

Что такое двумерный массив?

13.08.2011, 23:24. Показов 2531. Ответов 13

Студворк — интернет-сервис помощи студентам
Не буду долго объяснять мотивы subj-а, но не получается организовать работу с матрицей как с массивом векторов.

Пытаюсь написать цикл просмотра массива с использованием указателя на элемент в качестве счетчика.

Для вектора
C++
1
2
int b[5]={1,2,3,4,5};
for (int *i=b; i<b+5; ++i) std::cout<<*i<<' ';
Для матрицы, если считать что структура представлена вектором в котором строки последовательно сомкнуты, получается так
C++
1
2
3
4
5
int a[3][5]={{11,12,13,14,15},{21,22,23,24,25},{31,32,33,34,35}};
for (int *i=*a; i<*(a+3); i+=5)
{ for (int j=0; j<5; ++j) std::cout<<*(i+j)<<' ';
  std::cout<<std::endl;
}
это не устраивает тем, что счетчик-указатель внешнего цикла указывает на элемент матрицы (int *), а не на строки, и требуется приращение 5 (длинна строк), а не 1.

Пытаюсь написать
C++
1
2
3
4
5
int a[3][5]={{11,12,13,14,15},{21,22,23,24,25},{31,32,33,34,35}};
for (int **i=a; i<a+3; i+=1)
{ for (int *j=*i; j<*i+5; ++j) std::cout<<*j<<' ';
  std::cout<<std::endl;
}
test.cpp:57: error: cannot convert 'int (*)[5]' to 'int**' in initialization
test.cpp:57: error: comparison between distinct pointer types 'int**' and 'int (*)[5]' lacks a cast
57 строка в файле == 2 строка в примере.

Не понимаю, почему указатель совместим с вектором, а указатель-на-указатель не совместим с указатель-на-вектор?
Из этого следует сделать вывод, что n-мерный массив - это n-мерный массив, а не вектор (n-1)-мерных массивов!? Косвенно это подтверждается тем, что sizeof от матрицы пропорционален размеру матрицы, т.е. указателей на строки не создаётся.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
13.08.2011, 23:24
Ответы с готовыми решениями:

Что такое файловый буфер? Что такое режим (модификатор) доступа, при работе с файлами?
Что такое файловый буфер? Что такое режим (модификатор) доступа, при работе с файлами?

Что такое рекурсивный тип данных? Что такое конструкция рекурсивного типа?
Что такое рекурсивный тип данных? Что такое конструкция рекурсивного типа?

Что такое бинарный массив
Создать бинарный массив размером 20 и проверить если ли в нем элемент. Вопрос: бинарный массив это когда в нем элементы только либо 1 либо...

13
Эксперт С++
1069 / 848 / 60
Регистрация: 30.04.2011
Сообщений: 1,659
13.08.2011, 23:52
C++
1
2
typedef vector<byte> Line;
vector<Line> Grid;              // -- решетка для демонстрации --
Вместо byte - любой тип
0
 Аватар для talis
794 / 546 / 61
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
14.08.2011, 00:01
двумерный массив в памяти выглядит так:

C
1
int array[3][5]={{11,12,13,14,15},{21,22,23,24,25},{31,32,33,34,35}};
11 12 13 14 15 21 22 23 24 25 31 32 33 34 35

То есть реально элементы лежат последовательно, и положение элемента a[2][4] рассчитывается как адрес_начала + 2*5 + 4. Не надо его путать с массивом указателей на int, который записывается как int * array[3]; или int ** array; (обе записи равносильны).
0
640KB мне хватило на всё.
119 / 50 / 3
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 00:17  [ТС]
Цитата Сообщение от talis Посмотреть сообщение
Не надо его путать с массивом указателей на int, который записывается как int * array[3]; или int ** array; (обе записи равносильны).
Вы книжки читали?!
"Везде" написано: "Двухмерный массив — это массив одномерных массивов."
0
 Аватар для talis
794 / 546 / 61
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
14.08.2011, 00:28
skvor, не, ну пардон, а я о чём?
0
640KB мне хватило на всё.
119 / 50 / 3
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 00:46  [ТС]
Двумерный массив - это не массив массивов. Многомерная таблица реализуется за счет пересчета индексов, а не за счет последовательного доступа по схеме слой-строка-элемент.
type ** эквивалентен type [][] или type *[], но компилятор считает их разными типами и не позволяет прямо присваивать.

Вобщем, тред можно закрыть, задача частично решается приведением типов
C++
1
2
3
4
for (int *i=(int *)a; i<(int *)a+3*5; i+=5)
{ for (int *j=i; j<i+5; ++j) std::cout<<*j<<' ';
   std::cout<<std::endl;
}
хотя итерация i+=5 угнетает, но думаю переделать на ++i без использования структур с явным вложением невозможно.
0
 Аватар для talis
794 / 546 / 61
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
14.08.2011, 00:49
Цитата Сообщение от skvor Посмотреть сообщение
Многомерная таблица реализуется за счет пересчета индексов
Цитата Сообщение от talis Посмотреть сообщение
положение элемента a[2][4] рассчитывается как адрес_начала + 2*5 + 4
Давайте не будем спорить о терминах.
0
Эксперт С++
 Аватар для grizlik78
2382 / 1666 / 279
Регистрация: 29.05.2011
Сообщений: 3,402
14.08.2011, 01:06
Цитата Сообщение от skvor Посмотреть сообщение
type ** эквивалентен type [][] или type *[]
type ** никогда не был эквивалентен ни type [][], ни type *[].
То, что Вы пытаетесь сделать могло бы выглядеть так:
C++
1
2
3
4
5
6
7
int a[3][5]={{11,12,13,14,15},{21,22,23,24,25},{31,32,33,34,35}};
for (int (*i)[5] = a; i < a+3; ++i)
{
    for (int j=0; j<5; ++j)
        std::cout<<*(*i+j)<<' ';
    std::cout<<std::endl;
}
1
640KB мне хватило на всё.
119 / 50 / 3
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 01:44  [ТС]
Спасибо, вот так только надо
C++
1
2
3
4
5
int a[3][5]={{11,12,13,14,15},{21,22,23,24,25},{31,32,33,34,35}};
for (int (*i)[5]=a; i<a+3; ++i)
{ for (int *j=(int *)i; j<(int *)i+5; ++j) std::cout<<*j<<' ';
  std::cout<<std::endl;
}
собственно решался вопрос снижения затрат на пересчет индексов и последовательный доступ в многомерных массивах.

Жить стало веселей :dance3:
0
Эксперт С++
 Аватар для grizlik78
2382 / 1666 / 279
Регистрация: 29.05.2011
Сообщений: 3,402
14.08.2011, 01:57
Тогда уж
C++
1
2
3
4
for (int (*i)[5]=a; i<a+3; ++i)
{ for (int *j= *i; j<*(i+1); ++j) std::cout<<*j<<' ';
  std::cout<<std::endl;
}
Правда я совсем не уверен, что это чем-то лучше нижеследующего кода
C++
1
2
3
4
5
int *ptr = a[0];
for (int i = 0; i < 3; ++i)
{ for (int j= 0; j < 5; ++j) std::cout<<*(ptr++)<<' ';
  std::cout<<std::endl;
}
А запросто может и хуже оказаться.
Да и вообще, индексы на x86 вычисляются довольно эффективно, а современные компиляторы зачастую хитрее "оптимизаторов". Так что обязательно надо сравнивать, в том числе и с доступом через a[i][j]
1
640KB мне хватило на всё.
119 / 50 / 3
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 02:15  [ТС]
Да, спасибо, я постепенно прихожу к пониманию первого варианта.

Второй вариант не подходит, т.к. работает только для двумерного массива, а я хочу что б выглядело как массив массивов. Собственно, самый быстрый проход по любому массиву (но не массиву массивов) будет если поставить указатель на первый элемент и итерировать до конца циклом без вложения.
0
Эксперт С++
 Аватар для fasked
5045 / 2624 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 5
14.08.2011, 11:35
Цитата Сообщение от skvor Посмотреть сообщение
Собственно, самый быстрый проход по любому массиву (но не массиву массивов) будет если поставить указатель на первый элемент и итерировать до конца циклом без вложения.
Есть мнение, что чем проще код, тем проще его автоматически оптимизировать. Ну знаете, в кэш не попадет или предсказание ветвления подведет, или просто компилятор оставит все как есть. Так что Ваше утверждение весьма спорное. Тесты обязательно нужны.
1
 Аватар для taras atavin
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
14.08.2011, 11:53
Цитата Сообщение от skvor Посмотреть сообщение
Что такое двумерный массив?
Размерность массива есть количество индексов, с помощью которых адресуются его элементы, то есть элементы двумерного массива адресуются двумя индексами одновременно. При этом на конкретный элемент указывает сочетание значений обоих индексов, указываемых в строгом порядке, то есть элементы a[1,2] и a[2,1] - разные. Но на сях и плюсах нет понятия многомерных массивов, поэтому с учётом того, что на тех языках, где оно есть, многомерный массив синонимичен массиву массивов равной суммарной размерности, на сях и плюсах двумерные массивы представляются только линейными массивами линейных массивов и ни как иначе.
1
Заблокирован
14.08.2011, 19:41
Цитата Сообщение от skvor Посмотреть сообщение
Не буду долго объяснять мотивы subj-а, но не получается организовать работу с матрицей как с массивом векторов.

Пытаюсь написать цикл просмотра массива с использованием указателя на элемент в качестве счетчика.

Для вектора
C++
1
2
int b[5]={1,2,3,4,5};
for (int *i=b; i<b+5; ++i) std::cout<<*i<<' ';
Для матрицы, если считать что структура представлена вектором в котором строки последовательно сомкнуты, получается так
C++
1
2
3
4
5
int a[3][5]={{11,12,13,14,15},{21,22,23,24,25},{31,32,33,34,35}};
for (int *i=*a; i<*(a+3); i+=5)
{ for (int j=0; j<5; ++j) std::cout<<*(i+j)<<' ';
  std::cout<<std::endl;
}
это не устраивает тем, что счетчик-указатель внешнего цикла указывает на элемент матрицы (int *), а не на строки, и требуется приращение 5 (длинна строк), а не 1.

Пытаюсь написать
C++
1
2
3
4
5
int a[3][5]={{11,12,13,14,15},{21,22,23,24,25},{31,32,33,34,35}};
for (int **i=a; i<a+3; i+=1)
{ for (int *j=*i; j<*i+5; ++j) std::cout<<*j<<' ';
  std::cout<<std::endl;
}
test.cpp:57: error: cannot convert 'int (*)[5]' to 'int**' in initialization
test.cpp:57: error: comparison between distinct pointer types 'int**' and 'int (*)[5]' lacks a cast
57 строка в файле == 2 строка в примере.

Не понимаю, почему указатель совместим с вектором, а указатель-на-указатель не совместим с указатель-на-вектор?
Из этого следует сделать вывод, что n-мерный массив - это n-мерный массив, а не вектор (n-1)-мерных массивов!? Косвенно это подтверждается тем, что sizeof от матрицы пропорционален размеру матрицы, т.е. указателей на строки не создаётся.
Я вам помогу разобраться, а то тут те, которые считают себя "экспертами по С++", вам внятно ответить не могут.

Итак, вы имеете массив a[ 3 ][ 5 ] и хотите его элементы вывести на пкечать. Фактически, вы имеете массив массивов, то есть a[ 0 ] указывает на массив из 5 элементов, a[ 1 ] указывает на следующимй массив из пяти элементов, а a[ 2 ] указывает на последний массив из пяти элементов. То есть значением a[ i ] является одномерный массив.

Когда вы испеользуете имя массива в выражениях, то он преобразуется в казатель на свой пекрвый элемент. Для вашего массива он преобразуется в указатель int ( * )[ 5 ]. Поэтому в своем внешнем цикле вы должны написать

for ( int ( *p )[ 5 ] = a; p < a + 3; ++p )

А что написать во внутреннем цикле?

Во внутренний цикл вы передаете указатель на массив, то есть int ( *p )[ 5 ]. Тогда если разыменовать этот указатель, то есть использовать выражение *p, то вы получите одномерный массив. В свою очерель если использовать имя одномерного массива в выражении, то оно преобразуется в указатель на его первый элемент.

Итак, мы имеем что выражение *p представляет собой массив вида int[ 5 ]. Если его использовать в выражениях, то он преобразуется в указатель вида int *.

Следовательно внутренний цикл должен быть записан в виде

for ( int *p1 = *p; p1 < *p + 5; ++p1 )

Как говорятфранцузу, вуаля!

Добавлено через 2 часа 37 минут
Хотел бы себя поправить, то есть заменить слово "указывать" на "представляет собой", когда я говорил об a[i] то есть a[0] представляет собой массив размерностью 5, a[1] представляет собой массив размерности 5 и т.д.
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
14.08.2011, 19:41
Помогаю со студенческими работами здесь

Что такое массив строк?
Что такое массив строк и как его ввести/вывести? Напишите, пожалуйста, код

Что такое хэндлер файла? Что такое файловый указатель?
Что такое хэндлер файла? Что такое файловый указатель?

Массив фиксированного размера может быть динамическим? Что такое "динамический массив"?
есть код string line; char *dup=new char; Я так понимаю создается динамический массив фиксированного размера длинной символов...

Что такое заголовочный файл? Что такое файл исходного кода? Рассмотрите назначение каждого из них
Что такое заголовочный файл? Что такое файл исходного кода? Рассмотрите назначение каждого из них пожалуйста.

Объясните что такое массив объединений и с чем его едят
Написать программу удаления заданного числового значения из массива объединений. Объясните что такое массив объединений и с чем его...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
Автоматическое создание документа при проведении другого документа
Maks 29.03.2026
Реализация из решения ниже выполнена на нетиповых документах, разработанных в конфигурации КА2. Есть нетиповой документ "ЗаявкаНаРемонтСпецтехники" и нетиповой документ "ПланированиеСпецтехники". В. . .
Настройка движения справочника по регистру сведений
Maks 29.03.2026
Решение ниже реализовано на примере нетипового справочника "ТарифыМобильнойСвязи" разработанного в конфигурации КА2, с целью учета корпоративной мобильной связи в коммерческом предприятии. . . .
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
Сумматор с применением элементов трёх состояний.
Hrethgir 26.03.2026
Тут. https:/ / fips. ru/ EGD/ ab3c85c8-836d-4866-871b-c2f0c5d77fbc Первый документ красиво выглядит, но без схемы. Это конечно не даёт никаких плюсов автору, но тем не менее. . . всё может быть. . .
Автозаполнение реквизитов при создании документа
Maks 26.03.2026
Программный код из решения ниже размещается в модуле объекта документа, в процедуре "ПриСозданииНаСервере". Алгоритм проверки заполнения реализован для исключения перезаписи значения реквизита,. . .
Команды формы и диалоговое окно
Maks 26.03.2026
1. Команда формы "ЗаполнитьЗапчасти". Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. В качестве источника данных. . .
Кому нужен AOT?
DevAlt 26.03.2026
Решил сделать простой ланчер Написал заготовку: dotnet new console --aot -o UrlHandler var items = args. Split(":"); var tag = items; var id = items; var executable = args;. . .
Отправка уведомления на почту при создании или изменении элементов справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной записи электронной. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru