![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| JackYF |
|
||||
![]() полуавантюрист ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 5814 Регистрация: 28.8.2004 Где: страна тысячи озё р Репутация: 18 Всего: 162 |
Попробую оспорить эту фразу таким кодом:
Если двумерные массива приводятся к двойному указателю, то объясни, почему не компилируется часть 1 моего примера. И почему, если даже сделать reinterpret_cast<int**>, то функция будет работать неверно? |
||||
|
|||||
| Fazil6 |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
Что дает разные результаты? при чем здесь sizeof(a) и sizeof(aa) ??? Вы Вместо того чтобы с пеной у рта доказывать что я дурак подумали бы оба что вы пишете и внимательно почитали что я пишу. int a[5]; - а как указатель на int -> в вычислениях указателя a + sizeof(int) int *aa - > в вычислениях aa + sizeof(int) где здесь будет тличие и разный результат???? Это твои фантазии особенно про перегрузку фантазии.... |
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: 9 Всего: 59 |
Мы уже этот вопрос обсуждали.
Нельзя напрямую передать инициализированный массив в функцию. Хоть имя массива и можно передать как двойной указатель, но хранение динамических массивов и статических отличается. Поэтому функции необходимо знать размерности и способ хранения. Если мы хотим создать функцию, которая бы принимала как статический так и динамический массив в качестве параметров придется делать дополнительную работу: так как способ хранения в памяти отличается. Мне кажется это возникло из-за совместимости снизу вверх - в первых версиях Си об этом не подумали, а дальше уже вроде как деваться не было. Когда я начал изучать этот вопрос для меня это тоже было загадкой: зачем два разных механизма сделали для реализации одной и той же вещи. Причем достаточно неудобную. С другой сторону, статические двухмерные массивы переменного размера вещь достаточно редко используемая, для этого существуют динамические массивы. Тут немного не так звучит моя фраза. Весь наш спор был об использовании имени массива. Не передачи его в функцию. В рамках функции это уже чисто двойной указатель и функция с ним работает уже по правилам двойного указателя (т.е. с базовым классом) и ничего не знает о статическом массиве (производном классе). Если мы хотим сделать функцию, куда мы можем передать как статический массив переменного размера так и динамический - без дополнительной работы не выйдет. Что предлагает Страуструп. Он предлагает преобразовывать статический двухмерный массив в одномерный, передавать в функцию его базовый адрес и размерности, а смещение элемента вычислять динамически по мере надобности. Достаточно странная рекомендация человека, разработавшего этот язык. Если матрица достаточно большая, а элементы нужны не по порядку а вразброс - то это будет накладка по времени и причем серьезная. И внутри функции этот массив уже даже не выглядит массивом - так как нельзя использовать операции извлечения элемента по индексу. Для меня это полная загадка - сделали бы инициализированный массив указателей как сами же написали в стандарте и все было бы замечательно (правда кроме этого спора - его не было бы). Вместо этого этой теме мало того, что посвящают достаточно большую главу в стандарте, еще и в книгах кто как горазд пишет. И ведь действительно, идиотская ситуация: один и тот же логический объект (двухмерный массив) по-разному храниться при статическом и при динамическом варианте создания. По меньшей мере странно. Лично я никогда не пользуюсь статическими двухмерными массивами - они мне видятся достаточно неудобными как раз по причине их передачи в функции. Я для передачи статического массива в универсальную функцию вручную привожу его к двойному указателю, чтобы функция работала как со статическим массивом любого размера так и с динамическим - т.е. для функции по сути это двойной указатель, к которому спокойно применима операция извлечения элемента из массива. Ну это все вода. К сожалению по сути вашего вопроса говорю, что имя двухмерного массива можно использовать как двойной указатель только в рамках блока, в котором он определен. Дальше уже хлопоты - хотите делать функцию, которая работает и со статическими массивами и с динамическими - без накладных расходов не выйдет. Так уж устроен язык. Либо теряем возможность удобной работы через квадратные скобки, либо перед передачей статического массива приводим его полностью через промежуточный массив указателей к двойному указателю. Можно конечно и наоборот сказать, что это двойной указатель ведет себя как статический массив. Но вот тут как раз и есть костяк моего мнения: для того, чтобы сделать работу хотя бы в рамках блока универсальной и перегружена указательная арифметика статического массива. Для чего так было наворачивать я не знаю - было бы все одинаково было бы проще. Всяк жизнь прграммисту наровит испротить Это сообщение отредактировал(а) Anikmar - 30.4.2007, 09:45 |
|||
|
||||
| MAKCim |
|
|||
![]() Воін дZэна ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5644 Регистрация: 10.12.2005 Где: Менск, РБ Репутация: 52 Всего: 207 |
<type> a[N] - массив размерности 1 - есть суть последовательность элементов одного типа
<type> a[N][N] - массив размерности 2 - есть суть последовательность массивов размерности 1 элементов одного типа <type> *a - указатель на элемент определенного типа - есть суть адрес элемента <type> **a - указатель на указатель элемента определенного типа - есть суть адрес элемента, содержащего адрес элемента <type> **a != <type> a[N][N] потому как <type> a[N][N] = {a11, a12, a13, ... ,a1N, a21, ..., a2N, ..., aN1, ..., aNN} если <type> **a содержит адрес элемента <type>* и, предположем, этот элемент первый элемент массива из N элементов <type>*, то <type> **a = <type> *a[N] = {a1*, a2*, ..., aN*}, из этого случая видно, что <type> a[N][N] != <type> **a, но т. к арифметика указателей гласит, что, <N раз *>a = a[0]...[0] (N раз), то получаем, что любой массив вида <type> a[A][B][C]... может быть представлен как int<A * B * C * ... раз *>, обратное (как уже показали) не верно Это сообщение отредактировал(а) MAKCim - 30.4.2007, 09:56 -------------------- Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі © |
|||
|
||||
| Anikmar |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: 9 Всего: 59 |
У меня сложилось впечатление, что я всем доказываю, что двухмерный массив является двойным указателем, а со мной спорят. Причем иногда мне самому уже так кажется (что я это доказываю)
Итак подвожу итого: Все участники спора прекрасно понимают как организованы в памяти массивы как статические так и динамические. Это на самом деле главное - никто не наворотит ошибок, связанных с непониманием вопроса. Пролистал ответы и что-то не увидел внятного примера передачи любого массива в функцию - сразу какой-то спор пошел, а тема именно с этого началась. Я влез в спор по другому поводу именно с примером - как можно имя двухмерного массива использовать как будто это был бы двойной указатель. Приведенные примеры опонента не устроили - и растянулся теоритический баян, когда в процессе спора уже забыли о чем начали. Да и ладно, в общем то. Не устроили и ладно - главное, что мои примеры рабочие, правильные и могут кому-нибудь пригодиться, а как конкретно это назвать - дело десятое. Я назову получение необходимой информации о статическом массиве - и не более. Исходя из этого, я подведу итого - так как окончательно точку в споре может поставить только самый свежий стандарт C++, его я не нашел, нашел только теоретические статьи, где про нашу тему скромно говориться "вопрос в стадии решения". Может где-то что-то и есть - просто я не нашел. Итак ИТОГО, что я собрал из всей темы: 1. Имя двухмерного статического массива двойным указателем не является. 2. Для передачи статически объявленного массива в функцию объявление такого массива в основной программе и в функции должно совпадать. Т.е. статический массив переменной размерности в функцию без дополнительных ухищрений и приведения типа не передать. По сути это означает, что в языке нет типа "двухмерный массив" - так как универсальное описание двухмерного массива переменного размера отсутствует. Это же относится к оличеству измерений больше 2. 3. Для получения информации об указателях на строки (или столбцы) статического двухмерного массива можно использовать его имя и синтаксис, аналогичный применяемому к двойным указателям. 4. Двойной указатель можно представить при надлежащей инициализации двухмерным массивом. 5. Физическая организация многомерного массива при статическом объвлении и динамическом создании отличается как минимум на дополнительный массив указателей для каждого измерения свыше 1. Всем спасибо за участие в споре, как минимум народ вокруг повеселили и ладно. Думаю надо переключаться на более продуктивные вещи. Еще раз всем спасибо. |
|||
|
||||
| Fazil6 |
|
||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1653 Регистрация: 3.5.2006 Где: Минск Репутация: 35 Всего: 60 |
ты сам себе противоречишь. В месте вызова функции массив определен и размерности его известны. То что будет дальше (внутри функции) нас вообще не интересует потому что такой код все равно не компилится. Значит нельзя использовать имя масива как двойной указатель. Ты утверждаешь, что если по стандарту имя int а[2] может использоваться как int* , то продолжая эту аналогию int aa[2][2] можно использовать как int**. У нас (несогласных с этой точкой зрения и считающих, что это заблуждение и необоснованые домыслы) возникает справедливый вопрос : почему тогда это не переносится на примеры кода?
Ничего не перегружено... Все работает как любой другой обычный указатель. Просто не нужно исходить из посыла, что имя двумерного массива двойной указатель. По поводу стандарта. Нет НИГДЕ в стандарте упоминаний того, что имя двумерного массива двойной указатель. Есть пункт 8.3.4.8, который здесь приводили. Есть еще 8.3.4.7
сказано совершенно четко, что имя многомерного массива конвертируется в указатель на массив меньшей размерности. Все! Больше никаких конвертаци дальше нет! Сказано, что если к нему применить *operator , то результат этой операции конвертируется тоже в указатель. Для того чтобы получить этот результат (к примеру для двумерного массива) имя массива используется как уазатель на массив, а не на int*. Т.е. уже все, он уже использовался не просто как указатель , а именно как указатель на массив и дальше разглогольствовать, что дескать там тоже конвертируется в указатель не имеет смысла потому, что к имени двумерного массива это уже отношения не имеет. вчем прав? если
Добавлено через 5 минут и 5 секунд
ох... неправда... я сразу тебе сказал, что это выглядит только так и поэтому меня не устроило... Ладно... Закончили и забыли PS но Dov неправ |
||||||||||
|
|||||||||||
| apook |
|
||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 794 Регистрация: 12.7.2006 Репутация: 9 Всего: 23 |
пошагам
что такое pa[ 0 ], pa[ 1 ], pa[ 2 ]- - это указатели которым надо присвоить адреса(т.к pa это массив из 3-х указателей ) напрашивается
т.е напрямую или косвенно имеется ввиду значок & теперь
абсолютно ненужный (int *) * и & означают ведь разные вещи не пример конечно работает.. Вот и все, а вообще просто было плохое настроение вот я и возмутился на такую совсем мелочь, смысл значил крайне мало, надеюсь не из-за этого так раздулась данная тема -------------------- Мои руки из дуба, голова из свинца ну и пусть ... |
||||||||||
|
|||||||||||
| Anikmar |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2513 Регистрация: 26.11.2006 Где: Санкт-Петербург Репутация: 9 Всего: 59 |
ЭТО МОЙ ПОСЛЕДНИЙ ПОСТ В ЭТОЙ ТЕМЕ - иначе мы ее на завершим.
Вот как советует приводить первый элемент двойного массива господин Страуструп:
Там много текста - это конкретно выражение у него используется для получения указателя на первую строку. m - двухмерный массив Самое смешное, в его примерах ничего несказано, что статический двухмерный массив передается в функцию с явным преобразованием к двойному указателю. ИМХО Код Страуструпа сомнителен с точки зрения быстродействия.
Ну не устроило - так не устроило, что я могу сказать. Автора темы - пусть галочку поставит "ТЕМА ЗАКРЫТА" Хоть как тут меня называйте и обзывайте - в этой теме больше нислова не скажу Это сообщение отредактировал(а) Anikmar - 30.4.2007, 16:07 |
||||
|
|||||
| Ln78 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: 13 Всего: 15 |
FiMa1 и все желающие – получите обещанное окончание. Там есть обращение и к apook. Likehood, threef – основное содержание вам вряд ли будет интересно, но последние 2 страницы, возможно, вам понравятся.
Fazil6. У меня недостаточно постов, чтобы поставить тебе +, поэтому скажу здесь - молодец. 10 раз объяснять одно и то же, когда и первое объяснение было простым и понятным, сохраняя при этом вежливость и видимое спокойствие, - я бы, наверное, так не смог. Хотя и у тебя уже динамические массивы начали нервно курить. В одном из соседних топиков обсуждался, в частности, вопрос выхода из вложенных циклов. Не знаю, какой вложенности здешний «цикл» обсуждений, но это – моя 4-я попытка вставить break. Хотел было обратиться к многоуважаемой Earnest с просьбой поставить здесь свой весомый return, да прочитал абзац про ничего не понимающего в массивах Страуструпа и передумал. Да… В общем, береги невры Fazil6, ты нам нужен живым и здоровым Присоединённый файл ( Кол-во скачиваний: 11 )
Comment2.rar 29,33 Kb |
|||
|
||||
| JackYF |
|
|||
![]() полуавантюрист ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 5814 Регистрация: 28.8.2004 Где: страна тысячи озё р Репутация: 18 Всего: 162 |
Подведу и я свой мини-итог.
Тип "двойного массива" != тип "двойной указатель". Внутренности двойного массива не тождественны внутренностям двойного указателя. Ни неявное, ни явное преобразования не приводят один тип к другому. То, что объединяет эти два типа - возможность обращения к элементу через двойную индексацию. Надеюсь, от меня в этой теме тоже все. |
|||
|
||||
| zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 26 Всего: 92 |
Fazil6, apook, Anikmar, JackYF, что это вы на 13-й странице остановились? Примета плохая, надо еще одну-другую накатать |
|||
|
||||
| FiMa1 |
|
||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 408 Регистрация: 23.9.2006 Репутация: 5 Всего: 6 |
Ln78, спасибо тебе огромное! Старался читать с особым пристрастием. Есть вопросы...
Ну с arA[0], допустим, понятно. Это имя переменной, значением которой м.б. только целое число. arA, насколько я понял - имя указателя, т.е, по-сути, тойже переменной, значением которой, однако, может быть только адрес (ну и другие, в данном контексте несущественные, отличия обычной переменной от указателя). Далее выполняем следующие действия:
Действия в обоих строках абсолютно одинаковые? Если да, то вопрос2 - как таки работает приведение, использованное в первой строке? Фактически берем адрес указателя arA, приводим его к указателю.. ну не понятно.. В противном случае, если arA - не указатель, а просто переменная, то почему нельзя записать:
Ну и в догонку - что за тип такой 'int (*__w64 )[10]' ? ДРУЗЬЯ, БОЛЬШАЯ БРОСЬБА В ДАННОМ ТОПИКЕ ДИСКУССИЙ НЕ РАЗВОДИТЬ! РЕЖИМ ВОПРОС-ОТВЕТ ЛИБО РИДОНЛИ ;) СПАСИБО! Это сообщение отредактировал(а) FiMa1 - 3.5.2007, 14:42 |
||||||||||
|
|||||||||||
| Ln78 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: 13 Всего: 15 |
FiMa1, как бы тебе ответить, чтобы не спугнуть здешнее затишье? Может, если у тебя ко мне появятся по этой теме ещё вопросы, лучше задавать их в личку? Хотя я на форуме новичок, не знаю, как лучше.
Собственно, ответ на вопрос. Тебе можно считать, что 'int (*__w64 )[10]’ это есть адрес массива из 10 элементов, т.е. собственно то, что написано буквально. Модификатор __w64 это специфическое для VS определение, связанное с вопросами портирования из 32-х в 64-х разрядный компилятор, для тебя, наверное, это неважно. Если его убрать, то получим просто указатель на массив из 10 элементов. Т.е. если мы напишем так: typedef int ArrayInt10[10]; ArrayInt10 *pAr = &arA; то никаких замечаний от компилятора, естественно, не получим. Как я там писал, единственная причина, зачем я написал эту строчку, показав, что и такое сработает: Только для того, чтобы продемонстрировать один нюанс: не следует считать, что для компилятора arA и &arA[0] абсолютно одно и то же. Т.е. здесь к arA мы можем применить операцию взятия адреса, а к &arA[0] – нет. Основное, что ты должен запомнить, когда делаешь явные приведения: существует только память под 10 элементов int, к этой памяти можно адресоваться. И на все три варианта будет получен только один ответ: адрес начального элемента массива. Ничего больше нет. Компилятор не выдумщик, ему просто нечего больше возвращать. Все примеры преобразований, которые я приводил, например, с «превращением» двумерного массива в трёхмерный, рисуя таблички, как оно находится в памяти, я приводил для демонстрации этого факта (ни один бит при этих преобразованиях даже не пошевелился, это просто указание компилятору воспринимать область памяти так или иначе). В примере с тем одномерным массивом: есть массив из 10 чисел. Адрес первого (нулевого) элемента этого массива мы в начале привели чёрт знает к чему (могли привезти к указателю на рыжую корову, это сути не меняет), а потом явно сказали, что это всё-таки указатель на целое число (или несколько чисел), т.е. к тому, как оно есть на самом деле. Ещё раз повторюсь, так как написано в первой строке – никогда не делай. «Просто переменная» может быть чем угодно и указателем, и указателем на указатель, да мало ли ещё чем. Но при присваивании типы операндов должны совпадать (или для них в языке должны быть определены правила преобразования), иначе компилятор выдаст ошибку. Силой компилятор можно заставить считать, что это другой тип, но дальнейшая ответственность на том, кто такое приведение написал. |
|||
|
||||
| FiMa1 |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 408 Регистрация: 23.9.2006 Репутация: 5 Всего: 6 |
Под "привели чёрт знает к чему" ты подразумеваешь то, что мы зачем-то взяли адрес указателя? В то время, как могли бы просто написать int *pArr = (int *)arr; или и подавно int *pArr = arr; вместо:
PS: Ln78, не серчай, если шибко надоедаю, заглядывай периодически в топик, вопросы, имхо, будут... Это сообщение отредактировал(а) FiMa1 - 3.5.2007, 15:04 |
||||
|
|||||
| Ln78 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: 13 Всего: 15 |
FiMa1, я совсем "не серчаю", что ты. Мы все не экспертами родились, вопросы задавать нормально. "Черт знает к чему" - не от "серчания", а просто, чтобы было понятнее. Я просто боюсь опять поднять волну в этом многострадальном топике. Именно это я и имел в виду. Единственное, всё-таки, нет там указателя (как такового, для которого компилятор отвёл место, для которого можно писать что-то типа int**), есть имя массива, о чём эти 13 страниц и говорили, и примерно столько же я написал тебе в комментариях.
|
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |