Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Адреса, адресные операторы

Ответить
Настройки темы
C/C++ - Адреса, адресные операторы

Аватара для Medic84

$AutoITer


Автор проектов


Сообщения: 446
Благодарности: 44

Профиль | Отправить PM | Цитировать


Читаю книгу по С++. Дошел до главы "Первое знакомство с указателями в С++", прочитал, и не понял для чего они нужны? Дальше в книге посмотрел листинги программ и эти операторы там активно используются.

Прошу помощи в объяснении. И во всех ли программах нужно это?

-------

AutoIT Русское сообщество| Моя лаборатория


Отправлено: 21:04, 20-04-2010

 

Аватара для Drongo

Будем жить, Маэстро...


Сообщения: 6694
Благодарности: 1393

Профиль | Сайт | Отправить PM | Цитировать


Это делается для экономии памяти, т.к. легче хранить и передавать адрес ячейки в которой хранится число или значение, чем использовать несколько копий этого значения. В простых программах можно и без них.

Ну вот как скажем, у тебя есть пять складов по 100 кв. метров каждый, тебе ведь не будет удобно каждый раз все эти пять складов с содержимым перевозить на машине по городу для торговли? Нет. А проще дать адрес этих складов, написаный на бумажке.

-------
Правильная постановка вопроса свидетельствует о некотором знакомстве с делом.
3нание бывает двух видов. Мы сами знаем предмет — или же знаем, где найти о нём сведения.
[Quick Killer 3.0 Final [OSZone.net]] | [Quick Killer 3.0 Final [SafeZone.cc]] | [Парсер логов Gmer] | [Парсер логов AVZ]

http://tools.oszone.net/Drongo/Userbar/SafeZone_cc.gif

Это сообщение посчитали полезным следующие участники:

Отправлено: 21:51, 20-04-2010 | #2



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

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Аватара для lxa85

Необычный


Contributor


Сообщения: 4458
Благодарности: 994

Профиль | Сайт | Отправить PM | Цитировать


Технически, при вызове процедуры и передачи ей в качестве параметра некой переменной, допустим массива, будет передан весь массив. Если эта процедура рекурсивная, то массив будет передаваться каждый раз при вызове. Соотв потребление памяти будет расти прямо пропорционально числу вызов.
Для небольших величин затраты не существенны. Но если задействован баааальшой массив, то эффективнее, с т.з. быстродействия(меньше передаваемый объем) и экономии памяти(отсутствие необходимости дублирования), передать указатель на этот массив.
Указатель говорит, что по такому адресу, в памяти хранится массив необходимых данных.

В качестве другого примера, мы можем(с использованием соотв. структур) строить любые структуры. (коломбурчик ) Это хорошо иллюстрируется графом или деревом.
Практическим примером может служить создание дерева арифметического выражения и создание каким-то там обходом Польской обратной записи. (как обходить знаю, название не помню )
Можно попробовать организовать список, двунаправленный список, стек.

-------
- Я не разрешаю тебе быть плохой! Потому что плохие люди совершают плохие поступки. А это нехорошо!
(Из наставлений 5 летней девочки своей младшей сестре)

Это сообщение посчитали полезным следующие участники:

Отправлено: 22:34, 20-04-2010 | #3


Аватара для EvgeniyQQQ

Пользователь


Сообщения: 133
Благодарности: 21

Профиль | Сайт | Отправить PM | Цитировать


Цитата lxa85:
Технически, при вызове процедуры и передачи ей в качестве параметра некой переменной »
Правильнее писать функции. Так как в C++, на сколько я знаю , процедур нет.

Цитата lxa85:
передачи ей в качестве параметра некой переменной, допустим массива, будет передан весь массив »
Несколько лет занимаюсь программированием, а вот как передать в функцию весь массив не знаю. Знаю как можно передать через указатель. Знаю как по средствам передачи ссылки. Например, в Java методу всегда передаётся ссылка на массив, это точно. То, что в C++ не так, для меня открытие Прям аж стыдно стало

Подскажите пожалуйста как это сделать, желательно с примером

-------
"Не соглашайся ни на что, кроме совершенства!" - Анонимный автор.
"Совершенство достигается только к моменту полного краха." - К.Н.Паркинсон.


Отправлено: 10:20, 21-04-2010 | #4


Аватара для lxa85

Необычный


Contributor


Сообщения: 4458
Благодарности: 994

Профиль | Сайт | Отправить PM | Цитировать


EvgeniyQQQ, я честно сознаюсь в том, что я не знаю С++. И предыдущий пост базируется на знаниях языка Pascal. (Да и то, надо будет в отладчик залезть, уточнить).
Так что извините, примеров не будет

-------
- Я не разрешаю тебе быть плохой! Потому что плохие люди совершают плохие поступки. А это нехорошо!
(Из наставлений 5 летней девочки своей младшей сестре)


Отправлено: 10:46, 21-04-2010 | #5


Аватара для ganselo

Старожил


Сообщения: 232
Благодарности: 90

Профиль | Сайт | Отправить PM | Цитировать


Цитата EvgeniyQQQ:
а вот как передать в функцию весь массив не знаю. »
Если правильно понял, то так
Код: Выделить весь код
void func(int array[100]) //передаётся копия
{
}

void func2(int array[100][100])
{
}

int main()
{
 int ar1[100], ar2[100][100];
func(ar1);
func2(ar2);
return 0;
}

-------
К величайшему сожалению "история учит нас тому, что она ничему не учит".


Отправлено: 13:36, 21-04-2010 | #6


Аватара для EvgeniyQQQ

Пользователь


Сообщения: 133
Благодарности: 21

Профиль | Сайт | Отправить PM | Цитировать


ganselo, спасибо за ответ. Но таким образом мы передаём массив по ссылке, т.е. саму ссылку на массив, а не копию всего массива.
Меня же интересует передача в функцию массива по значению. Что в принципе, на сколько мне известно, не возможно.
Цитата EvgeniyQQQ:
а вот как передать в функцию весь массив не знаю »
Это была скорее скрытая ирония, а не вопрос. Прошу прощения за это

Вот код, который подтверждает то, что в приведённом вами способе передаётся массив по ссылке, а не по значению:
Код: Выделить весь код
void func(int array[100]) //передаётся ссылка
{
        array[0] = 5;
}

int main()
{
	int ar1[100];
	
	ar1[0] = 17;

	printf("ar1[0] = %d\n", ar1[0]);
	
	func(ar1);

	printf("ar1[0] = %d\n", ar1[0]);

	return 0;
}

-------
"Не соглашайся ни на что, кроме совершенства!" - Анонимный автор.
"Совершенство достигается только к моменту полного краха." - К.Н.Паркинсон.


Отправлено: 15:02, 21-04-2010 | #7


ИО Капитана Очевидности


Contributor


Сообщения: 5380
Благодарности: 1105

Профиль | Отправить PM | Цитировать


Medic84,
Цитата Medic84:
Дошел до главы "Первое знакомство с указателями в С++", прочитал, и не понял для чего они нужны? »
Объясняю на пальцах.
При выполнении программ процессор напрямую может работать только с двумя типами данных - это "локальные" и "глобальные" переменные.
Для хранения локальных переменных текущей функции в стеке программы выделяется область памяти, где каждая переменная размещается на определённом растоянии (смещении) от вершины стека. Адрес вершины хранится в соответствующем регистре (ячейка памяти) процессора.
То есть, допустим пользователь описал в программе переменные "A", "B" и "C" целочисленного типа. Компилятор, при создании машинного кода программы, преобразует имя переменных в записи вида [Стек+16], [Стек+20] и [Стек+24]. Соответственно команда "C = A + B" будет выглядеть, как в ячейку памяти [Стек+24] записать [Стек+16] + [Стек+20].
Глобальные переменные аналогично размещаются в определённой области памяти вне стека, и начальный адрес этой области также известен процессору.

Но стек и глобальная область имеют очень небольшой размер. Как же программе использовать остальную область памяти (она же "куча")? Через эти самые "указатели".
Сначала в стеке создаётся переменная типа "указатель" - её размер обычно составляет 32 бита (4 байта), реже - 64 (для работы в соответствующем режиме на 64-хразрядных процессорах). Потом, по мере выполнения функции, в этот указатель помещается адрес объекта - порядковый номер первой ячейки памяти.
Адрес может быть любым - переменной из используемой области стека (текущей фукнции), переменной старших функций (из которой была вызвана текущая), глобальной переменной. Но чаще всего в указатель записывается адрес объекта, для которого особыми командами в "куче" был выделен участок памяти.

Соответственно команда " *pC = A + B" означает "в ячейку памяти по адресу ячейки [Стек+24] записать результат [Стек+16] + [Стек+20]".

При работе с указателями в С++ используются две команды - & (получение адреса) и * (обращение по адресу). Конечно, официально они называются иначе, вот только официальные названия звучат очень заумно и совершенно непонятно
*pA = B . Значение переменной B помещается в ячейку памяти, адрес которой содержится в указателе pA
pA = &B . Адрес ячейки памяти переменной B записывается в указатель pA (теперь, записывая что-то в *pA, мы изменим значение B)
Можно даже так - *pA = *pB - значение ячейки памяти, адрес которой содержится в указателе pB, записывается в ячейку памяти, адрес которой содержится в указателе pA
А вот если сделать pA = pB, то оба этих указателя станут указывать на одну и ту же переменную

-------
Самое совершенное оружие, которым забиты арсеналы богатых и процветающих наций, может легко уничтожить необразованного, больного, бедного и голодного. Но оно не может уничтожить невежество, болезнь, нищету и голод. (Фидель Кастро)

Почему всех осужденных за измену Родине при Сталине реабилитировали при Горбачёве по отсутствию состава преступления? Потому что при Горбачёве измену Родине перестали считать преступлением.


Последний раз редактировалось El Scorpio, 22-04-2010 в 07:51.

Это сообщение посчитали полезным следующие участники:

Отправлено: 06:55, 22-04-2010 | #8


ИО Капитана Очевидности


Contributor


Сообщения: 5380
Благодарности: 1105

Профиль | Отправить PM | Цитировать


Зачем это всё вообще надо
1. Для работы с большими объёмами данных
То есть, в "куче" создаётся "тяжёлый" объект (например, изображение), а в стеке программа хранит только маленький указатель на этот объект.
2. Чтобы избежать лишнего копирования больших объёмов данных
То есть, можно написать функцию как void ShowPicture (TPicture Picture), а можно как void ShowPicture (TPicture *Picture). В первом случае в области стека функции будет создана копия картинки (размером в пару-тройку мегабайт ), а во втором будет передан лишь маленький указатель. Очень актуально для всех программ сложнее "Hello, World!"
3. Чтобы изменить объект данных в вызываемой функции
Если передать в функцию копию объекта, то после выполнения функции стек сократится обратно,*и все внесённые изменения будут утеряны. А*если передать указатель на объект, то функция будет изменять именно этот объект.
4. Чтобы получить несколько результатов в одной функции (частный случай п.3)
К примеру, функция SinCos (long double Angle, long double *Sinus, long double *Cosinus) будет записывать синус и косинус угла в ячейки памяти, указатели на которые программист укажет в качестве второго и третьего параметров.
Пример вызова - SinCos (Alpha, &SinA, &CosA)


Частным случаем указателей являются "ссылки", у которых при объявлении вместо знака * ставится &
Код: Выделить весь код
int A, B; // объявляются две переменные
int *pA = &A; // Указатель на переменную А
int &rA = A; // ссылка на переменную А

rA = B; // Значение B записывается в ячейку памяти по адресу, который содержится в ссылке rA
*pA = B; // Значение B записывается в ячейку памяти по адресу, который содержится в указателе pA
Ссылки от указателей отличаются тем, что
- при их использовании сразу производится обращение к значению по адресу ссылки (для указателей нужно ставить символ * )
- нельзя переназначить ссылку на другой объект
- при объявлении ссылки нужно сразу указывать объект

Пример использования ссылки
Код: Выделить весь код
int Array [100];
for (i = 0; i < 100; i++)
{
   int &Item = Array [i];
   // а дальше идут 10 строк кода, где используется ссылка Item
}
Кроме того, если ту же функцию SinCos записать с параметрами (long double Angle, long double &Sinus, long double &Cosinus), то её вызов будет выглядеть так SinCos (Alpha, SinA, CosA)

Обычно указатели используют для работы с объектами больших размеров (строки, массивы, объекты классов), а ссылки - для объектов поменьше (переменные простых типов, структуры). Просто потому,*что для указателей в отладчике отображаются их адреса, а для ссылок - значения по адресу.

-------
Самое совершенное оружие, которым забиты арсеналы богатых и процветающих наций, может легко уничтожить необразованного, больного, бедного и голодного. Но оно не может уничтожить невежество, болезнь, нищету и голод. (Фидель Кастро)

Почему всех осужденных за измену Родине при Сталине реабилитировали при Горбачёве по отсутствию состава преступления? Потому что при Горбачёве измену Родине перестали считать преступлением.

Это сообщение посчитали полезным следующие участники:

Отправлено: 07:47, 22-04-2010 | #9


Аватара для Delirium

Ветеран


Сообщения: 5624
Благодарности: 936

Профиль | Отправить PM | Цитировать


El Scorpio, тебе в преподаватели пора по C++

-------

Пройденные курсы:
[Microsoft №10174 Sharepoint], [SharePoint]
Мои проекты:[CheckAdmins], [NetSend7], [System Uptime], [Remote RAdmin LogViewer],[Netdom GDI], [Holidays - напоминалка о днях рождения]

А я офис-гуру :)


Отправлено: 07:54, 22-04-2010 | #10



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Адреса, адресные операторы

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Мобильные операторы 2.0 OSZone Software Новости программного обеспечения 0 04-04-2010 14:30
PowerShell - [блог] Регулярные выражения – Операторы -replace и -split Xaegr Скриптовые языки администрирования Windows 0 18-12-2009 19:30
Операторы мобильной связи и тарифы Ser6720 Мобильные ОС, смартфоны и планшеты 17 10-09-2009 16:07
Операторы сотовых телефонов! wolf Мобильные ОС, смартфоны и планшеты 71 29-05-2004 18:00
Есть ли в России операторы стандарта CDMA? Yustus Мобильные ОС, смартфоны и планшеты 17 07-02-2003 09:42




 
Переход