Alexey Boyko wrote to "Harry Zhurov" <Harry Zhurov on Thu, 25 Sep 2003 13:04:12
+0400:
AB>>> По индексу в массиве. Одномерные массивы не есть чем-то очень AB>>> сложным и тяжелым для понимания. HZ>> А они в С/С++ только одномерными и бывают. int A[5][4] - это тоже HZ>> одномерный массив размером [5]*[4].
AB> ??? чего-то тебя не в ту степь понесло.
Может и не в ту, это ты потом еще раз реши. Давай разберемся.
Да, слово "многомерный" массив часто употребляют, имея в виду массивы вида:
int A[n][m];
Это бывает удобно, и чаще всего функциональность такого массива соответствует функциональности двумерного массива - поясню: возможно, тут есть некоторая неразбериха в терминах, что понимать под двумерным массивом?!
Двумерный массив - это массив из элементов, каждый из которых определяется двумя координатами (аргументами). Это как значения функции двух переменных, вернее, табличное задание такой функции. Соответственно, любой элемент должен быть задан двумя координатами, и попытка задания только одной координаты (аргумента) должно приводить к ошибке вида: "Ошибка: попытка получить элемент по одной координате. Массив не содержит таких элементов, каждый элемент определяется двумя аргументами". Т.е. если есть _двумерный_ массив:
int A[n][m];
то любой элемент этого массива описывается как
A[i][j];
а выражение:
A[i];
просто не имеет смысла! Вообще!!
Теперь рассмотрим массивы языков С/С++. Что означает объявление:
int A[n][m];
Оно означает массив _массивов_ элементов типа int. И, соответственно, выражение:
A[i];
означает _указатель_ _на_ _массив_ _элементов_ _типа_ _int_. Т.е. это выражение, в отличие от предыдущего случая, уже имеет вполне определенный смысл, хотя ошибки, обычно, это не устраняет - если написать так:
int x = A[2];
то получишь ошибку вида: "Невозможно преобразовать int* в int".
Зато можно обращаться с этим массивом, например, так:
int x = **A; // извлечение первого элемента из А
int y = **(A + 1); // извлечение первого элемента из второго // подмассива массива А
int x = *(*A + 2); // извлечение третьего элемента из первого // подмассива массива А
Согласись, что довольно странный синтаксис для работы с двумерным массивом!? Но зато вполне соответствующий массиву массивов.
Кстати, еще момент: вот второй пример из приведенных выше:
int y = **(A + 1); // извлечение первого элемента из второго // подмассива массива А
Будь А полноценным двумерным массивом - т.е. законченным, целостным объектом, то выражение:
А + 1
означало бы адрес следующего такого двумерного массива, первый элемент которого вычислялся бы по адресу:
&A + sizeof(A)
Но реально это не так, и выражение:
А + 1
указывает на второй подмассив, адрес которого вычисляется как:
&A + sizeof(*A)
Это происходит потому, что А - это не двумерный массив, а массив массивов, и имя массива при операциях адресной арифметики (а также при передаче в качестве аргумента функции) неявно преобразовывается в указатель на первый элемент этого массива. Таким образом, в выражении:
А + 1
А имеет тип int (*)[m], т.е. указатель на _массив_ из m интов - указатель на первый элемент массива. А этот первый элемент, в свою очередь, является тоже массивом, что и подтверждает то, что A[n][m] - это массив массивов.
Надеюсь, ты не будешь спорить с тем, что двумерный массив и массив массивов - это разные вещи? Причем, "разность" их не терминологическая (тогда можно было бы называть и так, и так безо всяких последствий), а принципиальная, проявляющаяся в разном поведении, которое подробно рассмотрено на примере выше.
Ну, и, наконец, массив массивов - это _ОДНОМЕРНЫЙ_ массив из элементов, которые также являются массивами (а могут быть элементами любого другого типа - целые, структуры, объекты классов и т.д.). И никаких многомерных массивов в С/С++ не было и нет.
Вот теперь ты снова реши, в ту ли степь меня понесло или нет?! :)
AB>>> А так руками нужно описывать разные классы. Если в программу с AB>>> массивами нужно добавить еще одно значение, нужно просто удлиннить AB>>> массивы, HZ>> Hе, не все так безоблачно. Придется объявить функцию и поместить HZ>> указатель на нее в _строго_ _определенное_ место в массиве, и не дай HZ>> Бог ошибиться. А еще учти, что функция не одна, их несколько - в нашем HZ>> небольшом примере их было три. Т.е. нужно создать три функции и HZ>> поместить указатели на них в три разных массива по одинаковому HZ>> индексу. Все это руками. И не ошибиться, т.к. компилятор это не сможет HZ>> проверить. Короче, куча манипуляций, требующая предельного внимания.
AB> Вижу, ты очень сильно заплюсовался. Hикаких функций писать я не предлагал. AB> В массивах max, min, delta я предлагал хранить числа, а не адреса функций.
Ну, тогда я вообще ничего не понял - как ты собираешься реализовать ту функциональность, которая была приведена в том примере:
// ---------------------------------- ... if( keySelect.IsClick() ) CurrentParameter++; if( keyPlus.IsClick() ) CurrentParameter->Increase(); if( keyMinus.IsClick() ) CurrentParameter->Decrease(); ... // ----------------------------------
Как ты предлагаешь достичь того же без функций, а только с помощью какого-то массива?
AB>>> а на С++ - создать новый класс. Сколько еще строк понадобится? HZ>> А ты что, трудоемкость в строках измеряешь?
AB> В конце концов все сводится к количеству строк.
:) Ну хорошо, что хоть не к ж..почасам! :))
AB>>> с которыми АВРу не очень удобно работать. HZ>> А это еще почему? И кому тогда удобно?
AB> ldd ZL, Y+N AB> ldd ZH, Y+N+1 AB> icall
AB> (это если Y свободный)
А и не обязательно его использовать для загрузки адреса в Z. Есть еще много подходящих способов.
AB> против:
AB> rcall
Во-первых, первый и второй варианы предоставляют весьма различную функциональность, поэтому говорить, что первый вариант отстойный, и надо пользоваться вторым, т.к. он эффективнее, не слишком разумно. Они не лучше или хуже друг друга, они просто разные.
Во-вторых, много команд в первом варианте берется из-за того, что процессор-то 8-разрядный, а адреса-то 16-разрядные. И во втором случае у тебя размер "прыжка" всего +-4 килобайта, в отличие от первого, где адрес полноценный. Если сравнивать честно, то нужно использовать не rcall, а call, который тоже тащит полный адрес и занимает места соответственно. Т.ч. по эффективности оно, в этом случае, отличается всего в полтора раза.
...so long!
### На экзамене по теории вероятностей: "Девушка, какова вероятность того, что выйдя сейчас на улицу, вы встретите зеленого бегемота? - 0.5! - Почему же??? - Ну, либо встречу, либо нет!"