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

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

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.92
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
#1

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

13.08.2011, 23:24. Просмотров 1599. Ответов 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
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.08.2011, 23:24
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Что такое двумерный массив? (C++):

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

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

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

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

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

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

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
ValeryLaptev
Эксперт С++
1041 / 820 / 48
Регистрация: 30.04.2011
Сообщений: 1,659
13.08.2011, 23:52 #2
C++
1
2
typedef vector<byte> Line;
vector<Line> Grid;              // -- решетка для демонстрации --
Вместо byte - любой тип
0
talis
791 / 543 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
14.08.2011, 00:01 #3
двумерный массив в памяти выглядит так:

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
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 00:17  [ТС] #4
Цитата Сообщение от talis Посмотреть сообщение
Не надо его путать с массивом указателей на int, который записывается как int * array[3]; или int ** array; (обе записи равносильны).
Вы книжки читали?!
"Везде" написано: "Двухмерный массив — это массив одномерных массивов."
0
talis
791 / 543 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
14.08.2011, 00:28 #5
skvor, не, ну пардон, а я о чём?
0
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 00:46  [ТС] #6
Двумерный массив - это не массив массивов. Многомерная таблица реализуется за счет пересчета индексов, а не за счет последовательного доступа по схеме слой-строка-элемент.
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
791 / 543 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
14.08.2011, 00:49 #7
Цитата Сообщение от skvor Посмотреть сообщение
Многомерная таблица реализуется за счет пересчета индексов
Цитата Сообщение от talis Посмотреть сообщение
положение элемента a[2][4] рассчитывается как адрес_начала + 2*5 + 4
Давайте не будем спорить о терминах.
0
grizlik78
Эксперт С++
1913 / 1445 / 113
Регистрация: 29.05.2011
Сообщений: 3,001
14.08.2011, 01:06 #8
Цитата Сообщение от 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
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 01:44  [ТС] #9
Спасибо, вот так только надо
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
Эксперт С++
1913 / 1445 / 113
Регистрация: 29.05.2011
Сообщений: 3,001
14.08.2011, 01:57 #10
Тогда уж
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
skvor
640KB мне хватило на всё.
118 / 49 / 2
Регистрация: 07.06.2009
Сообщений: 442
14.08.2011, 02:15  [ТС] #11
Да, спасибо, я постепенно прихожу к пониманию первого варианта.

Второй вариант не подходит, т.к. работает только для двумерного массива, а я хочу что б выглядело как массив массивов. Собственно, самый быстрый проход по любому массиву (но не массиву массивов) будет если поставить указатель на первый элемент и итерировать до конца циклом без вложения.
0
fasked
Эксперт С++
4937 / 2517 / 180
Регистрация: 07.10.2009
Сообщений: 4,311
Записей в блоге: 1
14.08.2011, 11:35 #12
Цитата Сообщение от skvor Посмотреть сообщение
Собственно, самый быстрый проход по любому массиву (но не массиву массивов) будет если поставить указатель на первый элемент и итерировать до конца циклом без вложения.
Есть мнение, что чем проще код, тем проще его автоматически оптимизировать. Ну знаете, в кэш не попадет или предсказание ветвления подведет, или просто компилятор оставит все как есть. Так что Ваше утверждение весьма спорное. Тесты обязательно нужны.
1
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
14.08.2011, 11:53 #13
Цитата Сообщение от skvor Посмотреть сообщение
Что такое двумерный массив?
Размерность массива есть количество индексов, с помощью которых адресуются его элементы, то есть элементы двумерного массива адресуются двумя индексами одновременно. При этом на конкретный элемент указывает сочетание значений обоих индексов, указываемых в строгом порядке, то есть элементы a[1,2] и a[2,1] - разные. Но на сях и плюсах нет понятия многомерных массивов, поэтому с учётом того, что на тех языках, где оно есть, многомерный массив синонимичен массиву массивов равной суммарной размерности, на сях и плюсах двумерные массивы представляются только линейными массивами линейных массивов и ни как иначе.
1
Сыроежка
Заблокирован
14.08.2011, 19:41 #14
Цитата Сообщение от 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
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.08.2011, 19:41
Привет! Вот еще темы с ответами:

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

Убедитесь, что двумерный массив упорядоченным по возрастанию - C++
Убедитесь, что двумерный массив упорядоченным по возрастанию.

Двумерный динамический массив, что и с чем есть? - C++
собственно как сделать Двумерный динамический массив. и как можно проверить его работу?

Правильное обьявление функции, что возвращает двумерный массив символов - C++
Есть функция goUP. Как ее объявить так, чтобы она принимала двумерный массив символов и возвращала двумерный массив символов (если можно,...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
14.08.2011, 19:41
Ответ Создать тему
Опции темы

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