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

Поиск:

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


Опытный
**


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

Репутация: 5
Всего: 6



Очередной вопрос..
Цитата
Код
int main()
{
    int arr[10] = { 0, 1, 2 };
    int *pArr[5];

    pArr[0] = arr;

    pArr[0][1] = 4;

Строку инициализации указателя pArr[0] компилятор приводит к виду *(*(pArr + 0) + 1) = 4; ?
Нагло воспользовавшись твоими знаниями попытаюсь удовлетворить свою любознательность..
Цитата
Для трёх других вариантов – мы обязаны были это сделать, иначе компилятор сильно бы удивился: как же ты собираешься использовать эти константы, когда ты не дал им значений, ведь другого шанса определить их у тебя не будет?

Почему компилятор MS VS.NET 2003 разрешает создать такую структуру, ведь обратиться к ее члену будет невозможно, т.к. имя создаваемому структурой типу не дано?
Код
struct {
    int a;
};

Если верить codelord, то не рулит компилятор MS.. ?

Это сообщение отредактировал(а) FiMa1 - 3.5.2007, 16:38
PM   Вверх
codelord
Дата 3.5.2007, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 1
Всего: 39



gcc 
Цитата

 ошибка: абстрактный декларатор ‘<anonymous struct>’ использован в качестве декларатора


Это сообщение отредактировал(а) codelord - 3.5.2007, 16:30


--------------------
Доступен поиск по исходным кодам в GOOGLE.
http://www.google.com/codesearch
PM MAIL   Вверх
Ln78
Дата 3.5.2007, 16:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



На первый вопрос - да.
На второй (несколько выходит за тему топика) строгого формального ответа не знаю, но как бы я это объяснил для себя: это объявление сродни описанию неиспользованной переменной: пользы от неё никакой, но и вреда тоже. В случае с константами ситуация другая: если компилятор обработал такое определение переменной, то предполагается, что к ней можно обращаться за значением, а поскольку у неё значения нет - воспринимается как ошибка. 
Формально правильнее, наверное, можно было бы сказать: синтаксис такой, то нельзя, а это можно. Но, учитывая, что синтаксис создавался предварительно подумав, логика какая-то быть должна. А поскольку не я определял синтаксис, точного объяснения дать не могу. Можешь создать ещё один топик по этой теме, возможно, получишь много интересных вариантов в ответ.
PM MAIL   Вверх
FiMa1
Дата 4.5.2007, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 5
Всего: 6



Имя одномерного массива - это константа, представляющая собой указатель на 0-ой элемент массива. Этот указатель отличается от обычных тем, что его нельзя изменить (установить на другую переменную), поскольку он сам хранится не в переменной, а  является  просто некоторым постоянным адресом. Андрей Богатырев. Хрестоматия по программированию на Си в Unix
Как таки будет выглядеть определение для МНОГОМЕРНОГО массива?
PM   Вверх
Dov
Дата 4.5.2007, 10:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата(FiMa1 @  4.5.2007,  10:32 Найти цитируемый пост)
Как таки будет выглядеть определение для МНОГОМЕРНОГО массива?

FiMa1, а сам-то ты как думаешь?

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



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


Опытный
**


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

Репутация: 5
Всего: 6



Цитата(Dov @ 4.5.2007,  10:41)
Цитата(FiMa1 @  4.5.2007,  10:32 Найти цитируемый пост)
Как таки будет выглядеть определение для МНОГОМЕРНОГО массива?

FiMa1, а сам-то ты как думаешь? Намёк: многомерный массив представляет собой одномерный массив массивов.

Имя многомерного массива - это константный указатель на 0-ой элемент данного многомерного массива (здесь одномерный массив - константный указатель на 0-ой элемент данного одномерного массива).

Это сообщение отредактировал(а) FiMa1 - 4.5.2007, 11:18
PM   Вверх
Fazil6
Дата 4.5.2007, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата(FiMa1 @  4.5.2007,  11:05 Найти цитируемый пост)
Ок, что такое 0 в последней строке?

какой 0 в последней строке?
Вся предыдущая дискуссия была о том, что представлять
Цитата(FiMa1 @  4.5.2007,  11:05 Найти цитируемый пост)
здесь одномерный массив - константный указатель на 0-ой элемент данного одномерного массива

неправильно. Правильно сказать
Имя многомерного массива - это константный указатель на 0-ой элемент данного многомерного массива (здесь одномерный массив)
поэтому и не будет работать
Код

 int **p2 = (int **)ma;
    p = *p2;
    p[1*5+3]=200;//пытаемся поместить значение в ячейку с адресом 32 (= 0 + (1*5+3)*4). 


PM MAIL   Вверх
FiMa1
Дата 4.5.2007, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 5
Всего: 6



Ок, если ma – обычный указатель, то зачем нужно явное его приведение к int*: int *p = (int *)ma; ?
Код

int ma[3][5];

for( int i = 0; i < 3; i++ )
    for( int j = 0; j < 5; j++ )
        ma[i][j] = 10 * i + j;

int *p = (int *)ma;
p[1 * 5 + 3] = 100;

В общем-то всё понятно. Не очевидным кажется только то, что имя массива ma - по определению указатель, но мы не можем использовать его как указатель без предварительного приведения к *int. Вот это прокомментируйте. пожалуйста.

Это сообщение отредактировал(а) FiMa1 - 4.5.2007, 14:11
PM   Вверх
Fazil6
Дата 4.5.2007, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

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



Цитата(FiMa1 @  4.5.2007,  13:17 Найти цитируемый пост)
В общем-то всё понятно. Не очевидным кажется только то, что имя массива ma - по определению указатель, но мы не можем использовать его как указатель без предварительного приведения к *int. Вот это прокомментируйте. пожалуйста.

ma - это не указатель по определению. Это имя массива можно использовать как указатель. В Твоем примере ma можно использовать как указатель на массив int[5] и поэтому 
Код

int *p = ma;

компилироваться не будет, но с приведением к int* работать будет потому, что адрес, с которым асоциировано имя ma - это, кроме всего прочего, и адрес первого элемента первого массива в твоем многомерном массиве, и через этот адрес посредством указателя int *p можно  получить дотуп. 
PM MAIL   Вверх
FiMa1
Дата 4.5.2007, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 5
Всего: 6



Почему когда мы пишем 
Код
int **p2 = (int **)ma;
 указатель p2 инициализируется нулем? Как в этом ошибочном случае инициализации происходит вычисление адреса памяти?
Код
int ma[3][5];

for( int i = 0; i < 3; i++ )
    for( int j = 0; j < 5; j++ )
        ma[i][j] = 10 * i + j;

int *p = (int *)ma;
p[1 * 5 + 3] = 100;
int **p2 = (int **)ma;//ошибка!
...

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


Эксперт
***


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

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



Цитата(FiMa1 @  4.5.2007,  15:44 Найти цитируемый пост)
указатель p2 инициализируется нулем?

он не инициализируется нулем. Он инициализируется адресом, асоциированным с ma, а по этому адресу лежит значение ma[0][0] , а так как ma[0][0] равно нулю и поэтому *p2 равно 0 , и поэтому **p2 - это попытка разыменовать нулевой адрес.




Это сообщение отредактировал(а) Fazil6 - 4.5.2007, 15:54
PM MAIL   Вверх
FiMa1
Дата 4.5.2007, 16:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 5
Всего: 6



С этим разобрался, спасибо! Далее Ln78 пишет (комменты мои):
Код
typedef int ArD3_2_2_3[2][2][3];//тип 'ArD3_2_2_3[2][2][3]' - синоним 'int[2][2][3]'
ArD3_2_2_3& mb = (ArD3_2_2_3&)ma;//Здесь мне вообще не понятно что делается
mb[1][1][1] = 111;


Это сообщение отредактировал(а) FiMa1 - 4.5.2007, 16:14
PM   Вверх
Ln78
Дата 4.5.2007, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



FiMa1, я рисовал таблички, чтобы пояснить, что там делается, посмотри на них внимательнее. Здесь мы указываем транслятору, чтобы он мог ту область памяти (3*5*4 байт) адресовать другим способом, как будто там расположен трёхмерный массив.





PM MAIL   Вверх
FiMa1
Дата 10.5.2007, 10:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 5
Всего: 6



Надеюсь, что во всем разобрался... Сделал для себя ряд очевидных, для взгляда со стороны, выводов.

После объявления int arr[SIZE], получить доступ к элементам массива arr можно посредством имени переменной arr[0] и имени переменной-указателя arr. Такое многообразие дополнительных имен переменных дает просто больше возможностей для "общения" с компилятором. С другой стороны, важно знать, что ни для хранения самого имени arr[0], ни для имени arr никакой памяти не выделяется!!! С точки зрения компилятора, имя переменной - это синоним имени определенной ячейки памяти, ее символический адрес. Эта ячейка памяти может хранить данные — значение переменной.

В то время, как сам объявленный массив arr имеет тип ТИП[SIZE], имя массива может быть использовано в качестве переменной типа КОНСТАНТНЫЙ_УКАЗАТЕЛЬ, который, по умолчанию проинициализирован нулевым элементом данного массива.

Рассмотрим определение двумерного массива - int ma[3][3]; После данного определения вводится три имени переменных - ma, ma[0], ma[0][0]. Соответственно типов int[3][3], int[3] и int. Теперь имя массива ma может быть использовано в качестве указателя на его нулевой элемент, вместе с этим на разработчика ложится отвественность четко понимать, что, в данном случае, нулевым элементом массива ma является также массив, только одномерный – int ma[3], имя которого также может быть использовано в качестве указателя... Поэтому для доступа к нулевому элементу двумерного массива через указатель необходимо предварительное приведение к типу указатель: int *pa = (int *)ma;

В общем, ОГРОМНОЕ всем спасибо за участие! Отдельная благодарность Ln78 за потраченное время и усилия на составление документов!

Это сообщение отредактировал(а) FiMa1 - 10.5.2007, 10:59
PM   Вверх
unicuum
Дата 20.4.2008, 04:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 1
Всего: 8



Простой код без каких-либо фишек и хитростей языка:
Код

#include <iostream>
using namespace std;

const int size_i = 3;
const int size_j = 2;

int _tmain(int argc, _TCHAR* argv[])
{
    int a[size_i][size_j] = {1, 2, 3, 4, 5, 6};

    // Вывод двумерного массива
    cout << "2D Array" << '\n';
    for (int i = 0; i < size_i; i++)
    {
        for (int j = 0; j < size_j; j++)
            cout << a[i][j] << ' ';
        cout << '\n';
    }

    // Вывод двумерного массива через указатель
    cout << "2D Array (pointer)" << '\n';
    int* pa = reinterpret_cast<int*>(a);
    for (int i = 0; i < size_i; i++)
    {
        for (int j = 0; j < size_j; j++)
            cout << *pa++ << ' ';
        cout << '\n';
    }

    return 0;
}


Распечатка:
Код

2D Array
0 1
2 3
4 5
2D Array (pointer)
0 1
2 3
4 5
Для продолжения нажмите любую клавишу . . .


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

int** является указателем на указатель, следующая картинка схематически изображает память и нарисована мною чтобы разъяснить данный момент.
user posted image

1. указатель на указатель содержит адрес указателя на целочисленное значение
2. указатель содержит адрес целочисленного значения
3. внутри самого первого элемента массива содержится конкретное значение, а не адрес

Это сообщение отредактировал(а) unicuum - 20.4.2008, 05:57


--------------------
user posted image
обычный день на винграде
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
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.0677 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


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

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