Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Многомерные массивы и указатели, Как получить адрес элемента массива 
V
    Опции темы
Anikmar
Дата 29.4.2007, 01:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 59



А что вы хотели? Мы не получим смещение 4 или 8. Мы получим следующий элемент массива. Для того, чтобы получить следующий элемент массива в случае объявления
int **p;
мы должны просто прибавить размер указателя
Так как у нас статический массив
int a[3][50];
то чтобы получить следующий элемент согласно правилам работы с двойными указателями компилятор высчитывает значение исходя из размерностей - так как статический массив занимает единый блок памяти. И прибавляет к нему 50 * sizeof(int).

Где нарущение правил работы с указателями???? Мы получили следующий элемент массива, согласно правилам языка Си.

В языке Си ( в стандарте) нет понятия многомерных массивов. Там есть понятие МАССИВ, доступ к элементам которго обозначается квадратными скобками. Если вы попытаетесь найти там операцию [][] - вы ее не найдете, потому, что ее там нет. Там есть понятие только массива. И понятие имени массива, которое приводится к указателя на тип данных массива.
Соответственно, если у нас есть объявление:
int a[3][12];
то с точки зрения станлдарта мы имеем массив из 3элеинтов, каждый из которых имеет тип int a[12]. Надеюсь с этим утверждением никто не спорит?

Далее читаем стандарт. Имя массива приводится к указателю на тип массива. (то же стандарт, а не мое мнение).
Значит наш пример показывает, что  мы имееем массив из 3элементов типа int[12], и что его имя приводится к указателюю на типа массива - т.е. на int[12]. При увеличении значения указателя на 1 мы должны получить следующий элемент массива. Так как у нас массив из 3элементов, каждый из которых имеет тип int[12] - то мы должны после инкрементирования укзателя получить следующий элемент массива, т.е. очереной int[12] пропуская все предыдущиие. Так как массив объявлен статически, то компилятор переставляет значение указателя так, чтобы он соответствовал правилам языка - т.е. на следующий элемент. Что мы и получаем в результате.

Если и эти доводы вас не убедили, тогда уже надо обращаться в артибтраж к Страуструпу - дескать какую-то хрень ты написал...

Иллюстрация к моим доводам на примере кода:
Код

    int b[2][3] = {{1,2,3},{4,5,6}};
    int i,j;
    
    for (i=0;i<2;i++)
        {
            for(j=0;j<3;j++) printf("%d\t",b[i][j]);
            printf("\n");
        }
    printf("**b = %d\n",**b);
    printf("**b = %d\n",**(b+1));


Если бы на месте b был бы инициализированный массив на базе двойного указателя, мы бы получили аналогичный результат. Т.е. имя массива и указатель ведут себя одинаково, логично и предсказуемо.
Если нужен пример - я его набросаю, просто немного лень стало.

А если разницу, в поведении указателей вы усмотрели в различном смещении, то опять направляемся к стандарту:

При инкрементировании указателя, он увеличивается на значение, равное типу его хранения.
указатель
int **P
p хранит массив указателей, который размещен в памяти единым блоком. Последний по измерению массив по правилам языка Си всегда размещается единым блоком (стандарт)
При увеличении на единицу - он показывает следующий указатель - так как именно указатели он хранит. На какое конкретно число он увеличивается - стандартом не прописано (так как это программиста не касается). Нам гарантировано стандартом одно: при увеличении на 1 указатель устанавливается на следующий элемент (ну можно, конечно, и на 2 и на большее количество)
Операция sizeof в таких случаях никого никогда колыхать не должна - у нас есть указатель на конкретный тип данных и его инкрементирование указывает на следующий элемент.

При объявлении массива
p[3][nnnn]
Если мы инкрементируем значение p, то мы должны получить очередной элемент - т.е. указатель - т.к. p - приводится к массиву указателей по стандарту. На сколько пришлось реально инкрементировать (или декрементировать - уже стебусь  smile ) указатель программиста никак не касается. Прямая арияметика с указателями запрещена. нам гарантируется только следующий элемент. И мы его получаем - это следующий указатель.


В чем разница в поведении?

Это сообщение отредактировал(а) Anikmar - 29.4.2007, 03:39
PM MAIL ICQ   Вверх
Mayk
Дата 29.4.2007, 01:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 45
Всего: 134



Цитата(Anikmar @  29.4.2007,  05:32 Найти цитируемый пост)
int a[3][12];
то с точки зрения станлдарта мы имеем массив из 12 элеинтов, каждый из которых имеет тип int a[3]. Надеюсь с этим утверждением никто не спорит?

занудутствую: Наоборот. a - это массив из трёх элементов, каждый из которых является массивом из двенадцати элементов, каждый из которых является int'ом. 

зы. 6 последних страниц не читал. 2 и 3 тоже. 


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
Anikmar
Дата 29.4.2007, 01:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 59



Цитата(Mayk @  29.4.2007,  01:43 Найти цитируемый пост)
Наоборот. a - это массив из трёх элементов, каждый из которых является массивом из двенадцати элементов, каждый из которых является int'ом

Эх.... Все-таки подсадили.  smile 

Как правильно пишется ЗоНУДА и ЗаНУДА?  smile 

Фраза из анекдота:
Цитата

Мужик, ну ты меня понял?


ПРОШУ СЧИТАТЬ ОЧЕПЯТКОЙ  smile

Добавлено @ 01:47
P.S.

И ваще - в 2 часа ночи что угодно перепутать можно, а не только порядок измерений.

Mayk - абсолютно прав, но смысл от этого никак не меняется

P.P.S.
Очепятка исправлена.

Это сообщение отредактировал(а) Anikmar - 29.4.2007, 03:41
PM MAIL ICQ   Вверх
Fazil6
Дата 29.4.2007, 10:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
то чтобы получить следующий элемент согласно правилам работы с двойными указателями компилятор высчитывает значение исходя из размерностей - так как статический массив занимает единый блок памяти. И прибавляет к нему 50 * sizeof(int).

вообще-то sizeof(int[50]) потому что элементом, на который указывает указатель а является int[50]. И никаких правил работы с двойными или тройными или еще какими указателями нет. Есть арифметика указателей и важно в ней только на что указывает указатель. Для двойного указателя он указывает на int*, а для массива на int[50]. Вот их размер в байтах и важен

Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
А что вы хотели? Мы не получим смещение 4 или 8. Мы получим следующий элемент массива.
. Причем здесь массив? Указателю прибавляется 1 и в результате получаем некое значение адреса. а + 1
Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
Где нарущение правил работы с указателями???? Мы получили следующий элемент массива, согласно правилам языка Си.

ох.... Я разве сказал, что правила нарушены? Я разве говорил, что пример не работает? Я сразу сказал, что правила по которым этот пример работает разные в случаях двойного указателя и массива.
Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
Далее читаем стандарт. Имя массива приводится к указателю на тип массива. (то же стандарт, а не мое мнение).Значит наш пример показывает, что  мы имееем массив из 3элементов типа int[12], и что его имя приводится к указателюю на типа массива - т.е. на int[12].

как солнце из-за туч!!!! Только непонятно что ты читал в топике предыдущие 10 страниц....

Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
Если и эти доводы вас не убедили, тогда уже надо обращаться в артибтраж к Страуструпу - дескать какую-то хрень ты написал...

доводы чего? того что я тебе первым делом сказал? Теперь ты мне объясняешь как по стандарту... Именно потому что так по стандарту меня твои примеры и не устроили. Я тебе так сразу и сказал.


Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
При инкрементировании указателя, он увеличивается на значение, равное типу его хранения.указатель
int **P
p хранит массив указателей, который размещен в памяти единым блоком. Последний по измерению массив по правилам языка Си всегда размещается единым блоком (стандарт)
 хранит он указатель на указатель. Все. Никаких массивов здесь нет.

Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
Если мы инкрементируем значение p, то мы должны получить очередной элемент - т.е. указатель - т.к. p - приводится к массиву указателей по стандарту.
 по какому стандарту????? К какому массиву указателей????  единственное к чему он приводится - указатель на массив

Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
Если мы инкрементируем значение p, то мы должны получить очередной элемент - т.е. указатель


Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
В чем разница в поведении?


в том как компиллятор получает этот очередной элемент

PM MAIL   Вверх
Anikmar
Дата 29.4.2007, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 59



Цитата(Fazil6 @  29.4.2007,  10:08 Найти цитируемый пост)
И никаких правил работы с двойными или тройными или еще какими указателями нет. Есть арифметика указателей

С этого момента по подробнее.
Итак имеем арифметику указателей.
Имеем 
char *s;  При операции s+1 указатель увеличивается так, чтобы указать на следующий элемент массива. По сути
Имеем 
char * *s; Теперь s указывает на указатель. s+1 прибавляет так же 1 адрес, чтобы указать на следующий элемент
Имеем
char s[3][30]; При операции s+1 он должен указать на следующий указатель. Именно для того, чтобы имя двухмерного массива соответствовало двойному указателю компилятор прибавляет к значению указателя сразу целую строку. Именно для того, чтобы арифметика указателей была одинаковой в поведении со статическими массивами и двойными указателями. А так как значение адреса статического массива по сути "только для чтения", то компилятор нне рискует тем, что если обратиться к имени массива как к указателю и попытаться что-нибудь ему присвоить, то естественно вылезет ошибка - так как указатели на подмассивы нигде не хранятся, а вычисляются по мере обращения. Это как раз и есть то отличие, почему имя двухмерного массива не является двойным указателем в чистом виде.

Цитата(Fazil6 @  29.4.2007,  10:08 Найти цитируемый пост)
Я разве сказал, что правила нарушены? Я разве говорил, что пример не работает? Я сразу сказал, что правила по которым этот пример работает разные в случаях двойного указателя и массива.

Никаких разных! Статический массив инициализирован! Поэтому прибавление к имени массива 1 позволяет сразу указать на след. элемент!
char a[3][30];
a - приводится к двойному указателю на 1-й элемент массива.
При прибавлении 1 а увеличивается на размер элемента хранения, в данном случае char[30] так как a имеет явный тип 3 указателя на массивы из 30 элементов
Вы же не будете спорить, что
void *p; - является указателем?
Будьте добры, приведите арифметику указателей примениму к типу void? 
Арифметика указателей обязательно будет работать по-разному в зависимости от типа указателя. Кто с этим спорит?
Я утверждаю, что двухмерные массивы С++ приводятся к двойному указателю согласно правилам стандарта.

Цитата(Fazil6 @  29.4.2007,  10:08 Найти цитируемый пост)
Теперь ты мне объясняешь как по стандарту... Именно потому что так по стандарту меня твои примеры и не устроили. Я тебе так сразу и сказал.

Я не увидел ни одного вашего встречного примера - как должно быть. Я спокойно взял имя массива, произвел с ним согласно правила языка операции разыменования и доступа к элементу, а вы говорите, что согласно стандарта мои примеры не устроили. Приведите, пожалуйста главу стандарта, согласно которой вас не устроили мои примеры?

Цитата(Fazil6 @  29.4.2007,  10:08 Найти цитируемый пост)
ранит он указатель на указатель. Все. Никаких массивов здесь нет.

Откуда такая уверенность? Вы видели как выделилась память? Это указатель на двухмерный динамический массив. 
Посмотрите на объявление функции.
void PrintMas(int**P,int a, int b)
Скажите с такой же уверенностью: что храниться в переменной P?
Возьмем одномерный массив.
char *s;
Это указатель или массив? Пока мы непроинициализировали указатель - это неизвестно. В зависимости от того, что мы присвоим это может быть адрес переменной и адрес первого элемента массива.

Цитата(Fazil6 @  29.4.2007,  10:08 Найти цитируемый пост)
по какому стандарту????? К какому массиву указателей????  единственное к чему он приводится - указатель на массив

Т.е. вы говорите, что приведенное мной объявление
int **p; 
приводится к указателю на массив? У нас всего лишь двойной указатель - вы же сами говорили:
Цитата(Fazil6 @  29.4.2007,  10:08 Найти цитируемый пост)
хранит он указатель на указатель. Все. Никаких массивов здесь нет.


К какому массиву указателей? 
Он может содержать адрес конкретной переменной типа "Указатель на int" или адрес первого элемента массива таких указателей. По аналогии с одномерными массивами, согласно стандарта языка Си.
int p; - одиночное значение int
int *p; - указатель на int или на массив из таких int-ов
int **p - указатель на указатель на int или на массив таких указателей

Приведите пример, как вы объявляете динамический массив? Давайте посмотрим и обсудим ваш код.



Цитата(Fazil6 @  29.4.2007,  10:08 Найти цитируемый пост)
Цитата(Anikmar @  29.4.2007,  01:32 )
В чем разница в поведении?

в том как компиллятор получает этот очередной элемент

Разница поведения компилятора - это не разница поведения указателей. Именно для того, чтобы привести имя двухмерного массива к двойному указателю компилятор и ведет себя по-разному. Как же иначе? Зато указатели ведут себя адекватно.
PM MAIL ICQ   Вверх
Fazil6
Дата 29.4.2007, 15:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
char s[3][30]; При операции s+1 он должен указать на следующий указатель. Именно для того, чтобы имя двухмерного массива соответствовало двойному указателю компилятор прибавляет к значению указателя сразу целую строку.

С чего ты взял, что компиллятор стремится чтобы 
Цитата

 имя двухмерного массива соответствовало двойному указателю 

???? Ему до лямпочки ваши инсинуации по поводу того как массив или его имя представить как двойной указатель. Ему говорят "прибавь к указателю", он вычисляет размер того на что он указывает и прибавляет нужное количество байт. Он совершенно не стремится , чтобы это было как с двойным указателем. Зачем ему это? Он работает с указателем на массив , а это не указатель на указатель. 


Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
 Именно для того, чтобы арифметика указателей была одинаковой в поведении со статическими массивами и двойными указателями.

хм... она и так везде одинаковая... Повторяю, что компилятор четко разделяет статические массивы и  двойными указателями.

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Никаких разных! Статический массив инициализирован! Поэтому прибавление к имени массива 1 позволяет сразу указать на след. элемент!
 ТЫ читаешь что я пишу? То что мы получаем указатель на следующий элемент - это результат. Я говорю о том как получается этот результат. Ты же сам пишешь

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Именно для того, чтобы имя двухмерного массива соответствовало двойному указателю компилятор прибавляет к значению указателя сразу целую строку

Вот я и говорю, какого художника вы утверждаете что **(a + 1) работает с int**,  если a + 1 дает смещение не на размер int* , а на размер подмассива? Только не надо говорить , что смещение на размер подмассива для того чтобы  соответствовало двойному указателю.

 

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Я утверждаю, что двухмерные массивы С++ приводятся к двойному указателю согласно правилам стандарта.

нет. Нет такого правила в стандарте... Есть правило по поводу просто массива, но это правило не рекурсивно и переносить его на многомерные массивы нельзя.

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Я не увидел ни одного вашего встречного примера - как должно быть.

Дискуссия с тобой началась с моих примеров.... 

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Я спокойно взял имя массива, произвел с ним согласно правила языка операции разыменования и доступа к элементу, а вы говорите, что согласно стандарта мои примеры не устроили. Приведите, пожалуйста главу стандарта, согласно которой вас не устроили мои примеры?

ну применил ты разыменовывание, ну получил ты в итоге int. По твоему это доказывет, что тип разыменовываемого int**? Я говорю, что тип того, что ты разымновывал int (*)[n] (указатель на массив из n элементов). Если его имя разыменовать 2 раза получим int. Вот  меня и не устраивает твой пример в котором двойным указателем и не пахнет.


Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Откуда такая уверенность? Вы видели как выделилась память? Это указатель на двухмерный динамический массив.

я вижу объявление и этого достаточно, чтобы однозначно определить тип. Нет такого типа указатель на двухмерный динамический массив и в арифметике указателей твое p будет использоваться как указатель на int* и никак подругому.  Вообще причем здесьэти экскурсы в динамическое выделение. Твой двухмерный динамический массив совершенно подругому расположен в памяти и то, что тут именно двойной указатель я не спорю

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
void PrintMas(int**P,int a, int b)
Скажите с такой же уверенностью: что храниться в переменной P?
 Ну точно ведь не int[2][2]. Уверен на 100%

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Возьмем одномерный массив.char *s;Это указатель или массив? Пока мы непроинициализировали указатель - это неизвестно. В зависимости от того, что мы присвоим это может быть адрес переменной и адрес первого элемента массива.

как его не инициализируй, но тип его не изменится. Это указатель на char. Даже new[] не сделает из него массива и его арифментика будет основываться на размере char. Мы говорим о нормальных класических статических массивах и динамические массивы идут в сад... 

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Приведите пример, как вы объявляете динамический массив? Давайте посмотрим и обсудим ваш код.

повторяю, динамические массивы нервно курят в саду... Речь не о них.

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Т.е. вы говорите, что приведенное мной объявлениеint **p; приводится к указателю на массив? У нас всего лишь двойной указатель - вы же сами говорили

ну не надо передергивать... 
было ведь так
Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
При объявлении массива
p[3][nnnn]
Если мы инкрементируем значение p, то мы должны получить очередной элемент - т.е. указатель - т.к. p - приводится к массиву указателей по стандарту.
 ни по какому стандарту он к массиву указателей не приводится.

Цитата(Anikmar @  29.4.2007,  11:08 Найти цитируемый пост)
Именно для того, чтобы привести имя двухмерного массива к двойному указателю компилятор и ведет себя по-разному.
 Компилятор ведет себя поразному потому что это разные типы, а не потому что ему нужно чтобы они привелись один другому
PM MAIL   Вверх
Xenon
Дата 29.4.2007, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1529
Регистрация: 12.4.2006

Репутация: 11
Всего: 50



Anikmar
Цитата(Anikmar @  29.4.2007,  01:32 Найти цитируемый пост)
p[3][nnnn]Если мы инкрементируем значение p

Код

p[3][nnnn];
++p;

Это что, работать должно? p - не l-value, к нему не может быть применем инкремент.


--------------------
user posted image  
PM MAIL   Вверх
Anikmar
Дата 29.4.2007, 17:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 59



Цитата(Xenon @  29.4.2007,  16:15 Найти цитируемый пост)
Это что, работать должно? p - не l-value, к нему не может быть применем инкремент. 

В моем примере p был указан как **p

Инкремент я имел саму операцию увеличения указателя на 1 без его изменения в таком смысле:
int p[3][4];

*(p+1).... Так мы же можем делать и никто нас не убьет за это


Fazil6, Я честно говоря тольо отвечаю на ваши вопросы, никак не получив одного единственного ответа: Каких действий вы ждете от работы с именем массива как с двойным указателем, которые вас не устраивают.

Поэтому дальнейшее обсуждение возможно только по приведению вашего кода с двойным указателем, которых вы не можете добиться от имени двойного массива. Если вас интересует именно инкремент в чистом виде, чтобы он прибавлялся именно на 1 - это конечно очень интересно, но  как выше уже обсуждалось числовое значение адреса никого особо не трогает - так как не нужно.

Я просил вас привести некоторые примеры - вы настойчиво заняли позицию нет это не то. Понимаете, у меня нет цели вам продать какой-либо продукт, а вы как придирчивый покупатель не хотите его покупать.

Я прошу вас, показать пример объявления функции, которая получает на вход статический двухмерный массив, размерности которого заранее неизвестны. Если делать это по рекомендациям Страуструпа вы все равно его приведете именно к двойному указателю.

Изначально ваш вопрос звучал так: Покажите мне примеры, где с именем массива работают так же как с двойным указателем.
Я вам показал рабочие примеры, которые не просто показывали что это работает, но и несли смысловую нагрузку - доступ к строке матрицы и к конкретному элементу.

Сейчас я уже начинаю себя ловить на мысли, что мне надо доказать вам, что имя двойного массива ЯВЛЯЕТСЯ двойным указателем. Нет. Двухмерный массвив не является двойным указателем. Его лишь можно так рассматривать по одной причине:

В языке Си имя одномерного массива можно рассматривать как указатель на его первый элемент. Т.е. как указатель на тип данных массива:
Утверждение 1
<type> Ar[NNN] - т.е. имя такого массива можно рассматривать как тип <type> *

Переходим к второму измерению
<type>Ar[MMM][NNN] Теперь Ar имеет тип Массив из MMM элементов, каждый из которых является массивоим из NNN элементов типа type.
Согласно утверждению  1, имя массива можно рассматривать как указатель на его первый элемент. Т.е. в нашем случае имя массива это указатель на 1-й массив (ну вернее нулевой) из NNN Элементов. Т.е. указатель на <type>[NNN]

<type>.[NNN] в первой части нашего утверждения ужы была рссмотрено как <type>*. Значит мы можем рассматривать имя двухмерного массива как указатель на <type>* что является <type>**

Если эти же рассуждения перевести к другой логике, то можно рассмотреть ее так:
typedef a10 int[10];

a10 a;             // Если взять отдельно a, то она может рассматривать как указатель на int и может вести себя именно так. 
                       //Имя одномерного   массива является указателем на его первый элемент, значит int*
a10 aa[10];    // Имя массива является указателем на 1-й элемент. Т.е. имеет тип *int[10]. 
                       // Последний в свою очередь может быть рассмотрен как int* Следовательно aa можно рассмотреть как int**

Еще раз повторю, фразы : "может быть рассмотрен", "с ним можно работать как" не синонимамы фраз "является"

Что собственно я вам показал и доказал примерами своего кода. А варианты, "А покажите мне код где с именем массива работают как с двойным указателем, и чтобы еще его значения соответсвовали двойному указателю" совершенно нелогичны.
Вообще, тип *int[40] не является стандартным  типом языка C. Это уже инициализированный тип. Поэтому всегда можно сказать, что операции с ними отличаются от опреаций int **.
Ну так int [][45] будут отличаться от int [][50]. Это что, тоже разные типы? Или все-таки частные случаи? Общия то базовый подоход операции [][] - это именно двойной указатель. И Именно к этому базовому подходу и подгоняет компилятор свои действия. 
Конкретно операция [][], применяемая к двойному указателю является аналогом разыменования. В случае со статтическим массив (но это является как раз именно частным случаем общего подхода) арифметика несколько упрощается, но не более. Опять таки пока мы не попробовали передать статический двухмерный массив произвольного размера в функцию. Там экономия на отсутствии реально хранящихся указателей вылиывается в проблему рассчета смещения. За все надо платить.
Но общий подход всегда базируется на каком-либо базовом типе, а базовый тип - это двойной указатель, так как нету в языке си типа [][].




PM MAIL ICQ   Вверх
nickless
Дата 29.4.2007, 17:25 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Гентозавр
****


Профиль
Группа: Участник Клуба
Сообщений: 2976
Регистрация: 29.8.2005
Где: Germany

Репутация: 19
Всего: 181



 smile Народ, вам не надоело еще спорить, а? smile 

Немного статистики для сравнения:
"Win vs. Lin": 122 дня, 453 поста = 3,71 поста/день
"Собираем поклонников висты": 12 дней, 147 постов = 12,25 поста/день (это при активном участии тролля)
Эта тема: 9 дней, 172 поста = 19,11 поста/день  smile 

Вывод: религиозные войны отдыхают smile  smile 

Ладно, больше не буду вам мешать smile 


--------------------
user posted image

Real men don't use backups, they post their stuff on a public ftp server and let the rest of the world make copies
- Linus Torvalds
PM MAIL   Вверх
Fazil6
Дата 29.4.2007, 18:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Fazil6, Я честно говоря тольо отвечаю на ваши вопросы, никак не получив одного единственного ответа: Каких действий вы ждете от работы с именем массива как с двойным указателем, которые вас не устраивают.

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

int a[2][2];
int **pa = a;

доказывает, что a может использоваться как int**, и если бы такое выражение было корректно в С++ , то этого хватило бы для доказательства моей НЕПРАВОТЫ и безграмотности.
Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Я просил вас привести некоторые примеры - вы настойчиво заняли позицию нет это не то. Понимаете, у меня нет цели вам продать какой-либо продукт, а вы как придирчивый покупатель не хотите его покупать.

какие еще конкретные примеры??? С чего твои наезды на меня начались??? Посмотри внимательно.... 
http://forum.vingrad.ru/index.php?showtopi...t&p=1114163
там полно примеров.

Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Изначально ваш вопрос звучал так: Покажите мне примеры, где с именем массива работают так же как с двойным указателем.

Неправда. Вот как он прозвучал.
Цитата(Fazil6 @  27.4.2007,  10:09 Найти цитируемый пост)
с удовольствием ознакомлюсь с примером использования двумерного массива или его имени в качестве int**



Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Я вам показал рабочие примеры, которые не просто показывали что это работает, но и несли смысловую нагрузку - доступ к строке матрицы и к конкретному элементу.

ты показал как двойной указатель использовать в качестве двумерного массива. Я не это спрашивал.

Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Сейчас я уже начинаю себя ловить на мысли, что мне надо доказать вам, что имя двойного массива ЯВЛЯЕТСЯ двойным указателем.

ну вобщем смысл был таким. Если вы утверждаете что int[2][2] и int** както связаны (имя или еще что-то) то приведите примеры из которых это будет видно.

Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
В языке Си имя одномерного массива можно рассматривать как указатель на его первый элемент. 
Т.е. как указатель на тип данных массива:
Утверждение 1<type> Ar[NNN] - т.е. имя такого массива можно рассматривать как тип <type> *
да. Только не рассматривать а использовать где это нужно.

Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Переходим к второму измерению<type>Ar[MMM][NNN] Теперь Ar имеет тип Массив из MMM элементов, каждый из которых является массивоим из NNN элементов типа type.Согласно утверждению  1, имя массива можно рассматривать как указатель на его первый элемент. Т.е. в нашем случае имя массива это указатель на 1-й массив (ну вернее нулевой) из NNN Элементов. Т.е. указатель на <type>[NNN]

вот здесь стоило остановиться ибо на этом рассуждения заканчиваются и дальнейшие умозаключения неправильны

Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
<type>.[NNN] в первой части нашего утверждения ужы была рссмотрено как <type>*. Значит мы можем рассматривать имя двухмерного массива как указатель на <type>* что является <type>**

ну вот это и неправильно. Это заблуждение. Я уже раз пять повторил!!!! Правило относящееся к одномерному массиву нерекурсивно!!!! Если мы можем рассматривать имя двумерного массива, то приведите мне пример где оно рассматривается компилятором как int**. Не надо хвататься за клаву. Нет таких примеров...
Ты говоришь, что в примере **a - это работа с двойным указателем потому что получили int. Я говорю, что это работа с указателем на int[n] , а двойным указателем здесь не пахнет. 


Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Ну так int [][45] будут отличаться от int [][50]. Это что, тоже разные типы? Или все-таки частные случаи?

конечно это разные типы.

Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Общия то базовый подоход операции [][] - это именно двойной указатель. И Именно к этому базовому подходу и подгоняет компилятор свои действия. 

Бред.... Ничего компилятор никуда не подгоняет.

Цитата(Anikmar @  29.4.2007,  17:00 Найти цитируемый пост)
Но общий подход всегда базируется на каком-либо базовом типе, а базовый тип - это двойной указатель, так как нету в языке си типа [][]

ну договорились... Получается есть в языке си тип "двойной указатель"...

PM MAIL   Вверх
Anikmar
Дата 29.4.2007, 19:57 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 59



Цитата(Fazil6 @  29.4.2007,  18:04 Найти цитируемый пост)
Цитата(Anikmar @  29.4.2007,  17:00 )
<type>.[NNN] в первой части нашего утверждения ужы была рссмотрено как <type>*. Значит мы можем рассматривать имя двухмерного массива как указатель на <type>* что является <type>**

ну вот это и неправильно. Это заблуждение. Я уже раз пять повторил!!!! Правило относящееся к одномерному массиву нерекурсивно!!!! Если мы можем рассматривать имя двумерного массива, то приведите мне пример где оно рассматривается компилятором как int**. Не надо хвататься за клаву. Нет таких примеров...
Ты говоришь, что в примере **a - это работа с двойным указателем потому что получили int. Я говорю, что это работа с указателем на int[n] , а двойным указателем здесь не пахнет. 


Наконец то из нашего баяна только один пост более мнее выделить можно.

Откуда такая уверенность в этом: 
Правило относящееся к одномерному массиву нерекурсивно!!!! Это вы прочитали в стандарте?

Еще раз рассмотрим int[n]. Это массив целых чисел, который может быть приведен к указателю на int. Причем приведен имено по стандарту - без всяких приведений типа. По сути компилятор это делает неявно:
int a[45];
int *b=a;
Так что имя одномерного массива практически является указателм на тип - так как приводится неявно. И почему это правило должно быть нерекурсивно? И главное где это написано?

Цитата(Fazil6 @  29.4.2007,  18:04 Найти цитируемый пост)
Если мы можем рассматривать имя двумерного массива, то приведите мне пример где оно рассматривается компилятором как int**
 
Предлагаю остановиться на этом примере:
int a[3][4];
int b = **a;


PM MAIL ICQ   Вверх
MAKCim
Дата 29.4.2007, 20:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 52
Всего: 207



господа
посмотрите ассемблерный код и все станет понятно  smile 


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Fazil6
Дата 29.4.2007, 21:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата(Anikmar @  29.4.2007,  19:57 Найти цитируемый пост)
Предлагаю остановиться на этом примере:
int a[3][4];
int b = **a;

будем ходить по кругу? Нет здесь int**
Для наглядности 
Цитата

int b = **(a + 1);

если а используется как указатель на int* , то выражение (a + 1) должно дать адрес на sizeof(int*) больший чем a, но мы получаем адрес больший на sizeof(int[4]) поэтому делаем вывод, что a здесь используется как указатель на int[4] , который в свою очередь никак не приводится к int** ибо  тогда неправильно будет работать арифметика указателей и поэтому правило нерекурсивно


Это сообщение отредактировал(а) Fazil6 - 29.4.2007, 21:23
PM MAIL   Вверх
Dov
Дата 29.4.2007, 22:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


аСинизатор
***


Профиль
Группа: Завсегдатай
Сообщений: 1721
Регистрация: 10.5.2003
Где: Эрец-Исраэль

Репутация: 15
Всего: 88



Цитата(Fazil6 @  29.4.2007,  21:23 Найти цитируемый пост)
поэтому делаем вывод
Никакой такой вывод мы не делаем. А просто вспоминаем, что имя массива не обычный указатель, а особенный, имеющий несколько ограничений, по сравнению с обычным указателем. 
  Могу перечислить те, что знаю и помню. 
Код

int ar[4];
int* p;
int var;

ar = p; // нельзя так присваивать, потому что указатель ar - константный  
ar++;   // нельзя инкрементировать / декрементировать по той же причине
p = &ar;// нельзя, оператор '&' применим только к переменным, а не к именам массивов. Исключение 
        // составляет оператор вывода, например: cout << &ar << endl; но и в этом случае будет выведен
        // адрес первого элемента массива, а не адрес самого массива

И последнее. Оператор sizeof(ar), используя имя массива в качестве аргумента возвращает размер всего массива в байтах, а не размер указателя. То есть в данном примере вернёт 16, а не 4.




--------------------
Тут вечности запах томительный,
И свежие фрукты дешевые, 
А климат у нас – изумительный, 
И только соседи – #уевые. 
                           Игорь Губерман.
PM   Вверх
Anikmar
Дата 29.4.2007, 23:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: 9
Всего: 59



Цитата(Fazil6 @  29.4.2007,  21:23 Найти цитируемый пост)
будем ходить по кругу? Нет здесь int**

Если вам будет легче, то int** является базовым типом для массива. Массив это частный случай поведения, в том числе и рассчета указателя. Еще раз повторю, в связи с тем что массив не является int**, но должен вести себя как int  арифметика в нем естественно работает по-другому.
Если говорить о нерекурсивности (я вообще не особо понимаю при чем здесь этот термин, но в общем то понятно)
то:
int a[5];
int *aa = a;
Преобразование стандартное, все в порядке, но sizeof(a) и sizeof(aa) также будут отличаться. Однако это ведь вас не смущает? Тем не менее a ведет себя как указатель на int, тогда согласно вашей логике это не так - так как sizeof дают разные результаты? 
Еще раз повторяю:
Я не говорю, что имя двухмерного массива является двойным указателем. Можно сказать, что это производный тип двойного указателя с перегруженной арифметикой. Однако если работать с ним как с двойным указателем он выдает именно тот результат, который ожидается.

Этому посвящена отдельная глава стандарта (8.3) Там описана схема преобразования имени массива в указатель
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1210 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.