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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Инкрементация указателя, Непонятна логика 
:(
    Опции темы
AlanG
Дата 15.5.2006, 09:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



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

int *p, h=100;
p=&h;   //к примеру адрес =2000
p++;     //адрес станет = 2002


 
PM MAIL   Вверх
Daevaorn
Дата 15.5.2006, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 51
Всего: 70



AlanG,
В твоём случае значит sizeof(int)==2, а поскольку p у тебя указатель именно на int, то и ++p и --p будет добавлять и убавлять от адреса 2. Вот если указатель был бы void*, то его нельзя ++/--, т.к. не определен тип. Арифметика указателей очень удобна при реализации сложных алгоритмов работы с памятью. 
PM MAIL WWW   Вверх
AlanG
Дата 15.5.2006, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата

В твоём случае значит sizeof(int)==2, а поскольку p у тебя указатель именно на int, то и ++p и --p будет добавлять и убавлять от адреса 2. Вот если указатель был бы void*, то его нельзя ++/--, т.к. не определен тип. Арифметика указателей очень удобна при реализации сложных алгоритмов работы с памятью.  

Да это я знаю smile , мне бы все о связь между длиной в байтах и адресом ячейки? 
 
PM MAIL   Вверх
likehood
Дата 15.5.2006, 10:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


666
**


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

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



удобно работать с массивами: ++p переходит к следующему элементу массива. 
PM MAIL   Вверх
LuckLess
Дата 15.5.2006, 10:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



++ и -- заставляют указатель указывать на следующий(++) или предыдущий(--) элемент ТАКОГО же типа, что и элемент на который он указывает.
логично предположить, что раз элемент занимает 2 байта, то следующий элемент будет через 2 байта после этого 
PM MAIL   Вверх
MAKCim
Дата 15.5.2006, 16:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



если
Код

int* p;

то
++p эквивалентно p+=sizeof(int);
--p ... p-=sizeof(int)
p+i ... p+i*sizeof(int)
p-i ... p-i*sizeof(int)
... 


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

PM MAIL   Вверх
bsa
Дата 15.5.2006, 19:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 63
Всего: 196



Цитата(MAKCim @ 15.5.2006,  16:11)
если
Код

int* p;

то
++p эквивалентно p+=sizeof(int);
--p ... p-=sizeof(int)
p+i ... p+i*sizeof(int)
p-i ... p-i*sizeof(int)
...

++p эквивалентно p += 1!!!
Не надо путать!
Код
char * pc;
int * &pi = (int*)pc;
...
++pi; // эквивалентно: pc += sizeof(int)
 
PM   Вверх
MAKCim
Дата 15.5.2006, 21:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



Цитата

++p эквивалентно p += 1!!!

ну да - sizeof неявно добавляется
спасибо что заметил 


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

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


Шустрый
*


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

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



Народ smile,  давайте разберем строение байта и разряды. Как вообще устроены разряды и байты? 
Я, если чесно совсем не разбираюсь в строении ячеек памяти. Я знаю что такое байт, но я не знаю как он храница в ячейках. На данный момент в голове  складывается следующая картина:
Одна ячейка хранит в себе 1 байт. Если да, то инкремент адреса увеличивая на еденицу, прибавляет 2 байта, если тип данных имеет размер 2 байта. Получается что, инкрементируя адрес который несет в себе 1 байт, невольно перемещается на 2 байта, т.е. на две яцейка памяти? 
PM MAIL   Вверх
UnrealMan
Дата 16.5.2006, 09:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

Репутация: 27
Всего: 32



Адресация памяти побайтовая. Запись
p = p+1 для указателя будет делать примерно то же, что и следующая:
p = (T *)((char *)p+sizeof(T));
если p имеет тип T *

Если тип int занимает 4 байта, то это значит, что под каждую переменную типа int будет отводиться чётверка байт. Записав
p++;
мы увеличиваем p таким образом, что он указывает теперь на начало следующей четвёрки байт, составляющей единое целое значение типа int. 
PM MAIL   Вверх
likehood
Дата 16.5.2006, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


666
**


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

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



надо определится, что называть ячейкой памяти. Чтобы не путать байты с ячейками будем считать, что ячейка - это область памяти, где храниться конкретная переменная. Для типа long ячейка состоит из четырех байт, идущих в памяти друг за другом. При этом адресом переменной (ячейки) называют адрес самого младшего ее байта (т.е. имеющего наименьший адрес). Выглядит это так:
Код

| байт1 | байт2 | байт3 | байт4 | байт5 | байт 6 |...
..^<---указатель на 1-ю ячейку   ^<---а здесь начинается следующая ячейка

если long *p указывает на 1-ю ячейку, то ++p увеличится на 4 байта и будет указывать на следующую ячейку. Такое поведение указателей сильно упрощает обработку массивов данных, но если нужно сдвинуть указатель только на один байт, надо сделать приведение к типу (byte*). 
PM MAIL   Вверх
AlanG
Дата 16.5.2006, 11:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата

Чтобы не путать байты с ячейками будем считать, что ячейка - это область памяти, где храниться конкретная переменная. 

Тогда лоника мне совсем не понятна. Ведь если переменная храница в одной ячейке, и если к примеру ячейка хранит в себе тип int  размером в 2 байта, то зачем перескакивать через одну ячейку? Ведь мы инкрементируем адрес (ячейку).

Код

int *p, h=100; //Адрес ячейки переменной h = 2000, переменная типа int имеет длину в 2 байта
p=&h;   //адрес ячейки =2000
p++;     //адрес станет = 2002

 
P.S. Про байты и размеры байтов мне все понятно, пока не могу вкурить логику и само строение ячеек. 

Это сообщение отредактировал(а) AlanG - 16.5.2006, 11:41
PM MAIL   Вверх
threef
Дата 16.5.2006, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Тогда так
адрес                        байт(биты)         переменные                     массив

0x00000000         76543210                      long z;                      int x[4],    x[0]
0x00000001         76543210 
0x00000002         76543210                                                       x[1]
0x00000003         76543210
0x00000004         76543210                      long y;                      x[2]
0x00000005         76543210
0x00000006         76543210                                                       x[3]
0x00000007         76543210

если у тебя переменная типа long находится по адресу 0x00000000 и занимает 4 байта, то адрес следующей - 0x00000004. 
&z+1 == &y
Если размер int 2 байта и у тебя массив int , то каждый следующий элемент находится через 2 байта
&x[0]+1==&x[1]
&x[0]+2==&x[2] и т.д.

В С /C++ адресная арифметика выполняется для типизированных указателей, бывает только целочисленной и прибавление целого числа к указателю дает новый адрес, смещенный на
число * размер типа 
PM MAIL   Вверх
bsa
Дата 16.5.2006, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 63
Всего: 196



baronp, про тип long ты не совсем прав. У меня он занимает в памяти 8 байт (у меня и машина 64-х битная, и ОС). А вот int у всех машин с разрядностью не менее 32-х бит - 4 байта.
AlanG
Ты сам подумай, что легче написать: a += sizeof(*a) или a += 1? Естественно второй вариант. Случаи, когда нужно методом изменения указателя получить доступ к каждой ячейке очень редки и для этого используются всякие ухищрения, например p = (char*)a + 1, здесь p - это char*. Кстати, разница типизированных указателей равна расстоянию в элементах, а не байтах:
Код
int a[100];
int *p = & a[10];     // эту строку можно записать по-другому: int *p = a + 10;
cout << ( p - a ) << endl;

Результат будет 10. Это очень хорошая особенность C/C++. Без нее, было бы намного сложнее писать программы, оперирующие массивами структур. Да и они были бы менее читабельными.
Но, повторяю, это особенность C/C++. Машинный код, который генерируется компилятором, прибавляет уже нужное количество байт:
Код
int *a;
...
a += 10;

Будет транслированно во что-то типа:
Код
add  [ebp+08h],028h

Здесь [bp+08h] - это адрес переменной a в стеке приложения, а 028h - это 40 в десятичной системе счисления.
Если ассемблер для тебя не очень понятен, то объясню проще - работу по умножению 10 на размер элемента (т.е. 4) возьмет на себя компилятор. И процессор уже выполнить увеличение на 40, а не на 10. Но с точки зрения человека, запись 10 легче воспринимается, чем 40 - не надо делить, чтобы узнать, на какой элемент массива будет указывать указатель после выполнения данной операции.
 
PM   Вверх
AlanG
Дата 16.5.2006, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Ребят, здорого расписали, спасибо smile 
(Жаль немогу репутацию повысить, но попрошу модераторов smile )
И еще мне кажется что пора книгу менять по C++.
Что посоветуйте? 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

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

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

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

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


 




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


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

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