Урок №99. Передача по адресу
Обновл. 21 Сен 2020 |
Есть еще один способ передачи переменных в функцию в языке C++ — по адресу.
Передача по адресу
Передача аргументов по адресу — это передача адреса переменной-аргумента (а не исходной переменной). Поскольку аргумент является адресом, то параметром функции должен быть указатель. Затем функция сможет разыменовать этот указатель для доступа или изменения исходного значения. Вот пример функции, которая принимает параметр, передаваемый по адресу:
Результат выполнения программы:
Вот пример программы, которая вызывает эту функцию:
Помните, что фиксированные массивы распадаются в указатели при передаче в функцию, поэтому их длину нужно передавать в виде отдельного параметра. Перед разыменованием параметров, передаваемых по адресу, не лишним будет проверить — не являются ли они нулевыми указателями. Разыменование нулевого указателя приведет к сбою в программе. Вот функция printArray() с проверкой (обнаружением) нулевых указателей:
Передача по константному адресу
Поскольку printArray() все равно не изменяет значения получаемых аргументов, то хорошей идеей будет сделать параметр array константным:
Обратите внимание, хотя сам адрес передается по значению, вы все равно можете разыменовать его для изменения значения исходного аргумента. Запутано? Давайте проясним:
При передаче аргумента по адресу в переменную-параметр функции копируется адрес из аргумента. В этот момент параметр функции и аргумент указывают на одно и то же значение.
Если параметр функции затем разыменовать для изменения исходного значения, то это приведет к изменению значения, на которое указывает аргумент, поскольку параметр функции и аргумент указывают на одно и то же значение!
Если параметру функции присвоить другой адрес, то это никак не повлияет на аргумент, поскольку параметр функции является копией, а изменение копии не приводит к изменению оригинала. После изменения адреса параметра функции, параметр функции и аргумент будут указывать на разные значения, поэтому разыменование параметра и дальнейшее его изменение никак не повлияют на значение, на которое указывает аргумент.
В следующей программе это всё хорошо проиллюстрировано:
Передача в функцию указателя или ссылки [дубликат]
В чем будет разница, если в функцию передать указатель и ссылку? например
Программы выведут одно и то же? Ведь и так, и так мы обращаемся к существующему элементу, а не создаем новый.
3 ответа 3
В принципе, технически разница между указателем и ссылкой лишь в том, что саму ссылку нельзя изменить (а указатель можно). [Вот тут бóльший список отличий.] Кроме этого, разница ещё синтаксическая: с ссылкой вы обращаетесь как будто это переменная, а с указателем нужно его правильно получать/разыменовывать:
Других технических отличий нет, и результат будет одинаковый.
Но разница на самом деле не в синтаксисе, а в смысле, в семантике.
Указатель может означать всё, что угодно. Он в C и C++ означает строку, ассив, адрес переменной, передачу переменной по ссылке и ещё кучу всяких вещей. А смысл ссылки ровно один — это как бы альтернативное имя (alias) существующей переменной.
Поэтому для случаев наподобие того, который вы описали, в C++ уместно использовать ссылку, а не указатель. Хотя, как вы сами видите, с указателем тоже прекрасно работает.
И ещё: в чистом C ссылок нет, так что у вас нет другого варианта кроме указателей.
Золотое правило с++ программиста: используй ссылки где можешь, а указатели где должен.
Если вы исправите опечатки и включите заголовок
То вывод будет идентичен.
Когда используются указатели, то вы можете передать null-указатель. Например,
И функция может быть вызвана как
Когда же используются ссылки, то ссылка должна указывать на существующий объект.
Всё ещё ищете ответ? Посмотрите другие вопросы с метками c++ указатели ссылки или задайте свой вопрос.
Связанные
Похожие
дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.9.9.40167
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
C Урок 29. Указатели в аргументах функций. Часть 1
В трёх последних уроках мы плотно занимаемся адресацией данных в языке C, изучили указатели, взятие адреса, разыменование, доступ к адресам массивов, поработали также с указателями на структуры и их поля.
Теперь нам предстоит познакомиться с применением указателей на различные данные в памяти в аргументах функций. Мы узнаем, какую огромную пользу это может принести в проектировании программ.
Как устроена функция, как она объявляется и вызывается, мы уже знакомы, только до сих пор мы применяли в качестве её аргументов обычные типы данных. Оказывается, аргументами могут быть и указатели на данные.
Главная польза указателей в аргументах следующая.
Когда мы пользуемся аргументами, переданными в функцию, в её теле, то на самом деле мы используем в качестве операндов не сами данные, а их копии. Это не влияет никак на результат. Немного только тратится больше памяти. Есть в этом и плюс. Наши данные, переданные в качестве аргументов, защищены от изменения. Но представьте, что нам нужно передать в функцию огромный массив данных или переменную структуры. Тут уже затраты памяти будут очень серьёзными. Поэтому, когда нам нужно было получить доступ к таким данным в теле функций, мы их не передавали, а объявляли их глобально и просто использовали. Порой такой подход тоже не оправдан и не приветствуется. Например, нам нужно в одной функции объявить большой массив и вызвать в теле этой функции другую функцию, в которой тоже нужно воспользоваться данным массивом. Глобально объявлять такой массив мы не хотим, так как наша первая функция когда-то тоже закончит свою работу и нам хотелось бы, чтобы память, затраченная на данный массив, была очищена. Передавать такой огромный массив мы также не хотим в качестве параметра, так как это породит ещё больший расход памяти и то, что создаётся копия массива, породит также затраты процессорного времени. Тогда нам и приходит на помощь передача в качестве параметра указателя на массив. В данном случае копия массива не создаётся и с помощью этого указателя в теле вызванной функции мы получаем полный доступ к его элементам.
Вторая польза указателей в аргументах функций та, что, не создавая копию, а пользуясь самими данными в памяти, мы получаем доступ ещё на их изменение. Хотя, если нам нужно будет защитить данные от изменения, мы можем применить ключевое слово const в указателе на данные и данные также будут доступны только на чтение, при этом копия создаваться также не будет и мы сэкономим и память и время выполнения.
Указатели в аргументах функций выглядят примерно вот так, как и обычное их объявление
Вот пример объявления такой функции
void print_str( const char *c_str)
Здесь мы передаём функции в качестве аргумента указатель на строчный массив, который потом выводим в консоль. Функции printf того и нужно, чтобы вывести строку. Ей нужен как раз указатель на неё.
А передаём мы указатель на массив, например, следующим образом.
Создаём и инициализируем строчный массив, воспользовавшись, к примеру, функцией копирования из стандартной библиотеки
strcpy (str1, «Hello, World. » );
А затем мы вызываем нашу функцию, передавая ей в качестве параметра имя массива, который, как мы помним, является указателем на массив
print_str(str1);
Так же мы можем пользоваться не обязательно указателями на массив, а указателями на любые типы данных, причём мы можем не создавать переменную-указатель на тип и не привязывать её к данным, а использовать при вызове функции, имеющих указатель в параметре, адрес переменной, хранящей данные, с помощью операции взятия адреса
Думаю, теперь мы, познакомившись с тем, как именно предаются указатели на данные в аргументах функций, можем приступить к практической части.
Проект мы также создадим из проекта прошлого урока с именем MYPROG28 и присвоим ему имя MYPROG29.
Откроем наш проект в Eclipse, произведём его первоначальную настройку и удалим весь наш код из функции main() за исключением возврата. Функция main() приобретёт вот такой вид
int main()
return 0; //Return an integer from a function
Давайте пока немного разомнёмся, прежде чем применять указатели в функциях. У нас в проекте (это моя промашка) существует модуль из пары файлов ariph.h и ariph.c. Здесь есть грамматическая ошибка, хотя это никак не сказывается на работоспособности модуля. Данное имя модуля произошло от слова арифметика, что на английском пишется как Arithmetic, а не Ariphmetic. Поэтому давайте изменим букву p на t в имени модуля. Дело в том, что порой нам иногда хочется изменить имя модуля и для этого мы должны знать, как это проделать более безболезненно и быстро.
Первым делом в дереве проекта вызываем контекстное меню на имени файла и выбираем в нём пункт Rename
В открывшемся диалоге меняем имя, снимаем галку (мы сами перепишем подключения, а то как-то не совсем корректно они получаются) и соглашаемся
В файлах main.c и arith.c изменим имя в подключении заголовочного файла
#include «arith.h»
Осталось открыть Makefile и там также везде изменить ariph на arith.
Вот и всё. Попробуем собрать наш проект, если он собрался, то мы всё сделали правильно.
Ну и теперь после такой небольшой разминки начнём работать с нашим проектом.
Сначала поработаем со строковым массивом.
У нас уже есть глобальный строковый массив. перенесём его в функцию main, таким образом сделав его локальным, и проинициализируем его строкой с помощью специально-обученной функции стандартной библиотеки
Указатели, ссылки и массивы в C и C++: точки над i
В этом посте я постараюсь окончательно разобрать такие тонкие понятия в C и C++, как указатели, ссылки и массивы. В частности, я отвечу на вопрос, так являются массивы C указателями или нет.
Обозначения и предположения
Указатели и ссылки
Указатели. Что такое указатели, я рассказывать не буду. 🙂 Будем считать, что вы это знаете. Напомню лишь следующие вещи (все примеры кода предполагаются находящимися внутри какой-нибудь функции, например, main):
Ссылки. Теперь по поводу ссылок. Ссылки — это то же самое, что и указатели, но с другим синтаксисом и некоторыми другими важными отличиями, о которых речь пойдёт дальше. Следующий код ничем не отличается от предыдущего, за исключением того, что в нём фигурируют ссылки вместо указателей:
Если слева от знака присваивания стоит ссылка, то нет никакого способа понять, хотим мы присвоить самой ссылке или объекту, на который она ссылается. Поэтому такое присваивание всегда присваивает объекту, а не ссылке. Но это не относится к инициализации ссылки: инициализируется, разумеется, сама ссылка. Поэтому после инициализации ссылки нет никакого способа изменить её саму, т. е. ссылка всегда постоянна (но не её объект).
Удивительный факт состоит в том, что ссылки и lvalue — это в каком-то смысле одно и то же. Давайте порассуждаем. Что такое lvalue? Это нечто, чему можно присвоить. Т. е. это некое фиксированное место в памяти, куда можно что-то положить. Т. е. адрес. Т. е. указатель или ссылка (как мы уже знаем, указатели и ссылки — это два синтаксически разных способа в C++ выразить понятие адреса). Причём скорее ссылка, чем указатель, т. к. ссылку можно поместить слева от знака равенства и это будет означать присваивание объекту, на который указывает ссылка. Значит, lvalue — это ссылка.
А что такое ссылка? Это один из синтаксисов для адреса, т. е., опять-таки, чего-то, куда можно класть. И ссылку можно ставить слева от знака равенства. Значит, ссылка — это lvalue.
Окей, но ведь (почти любая) переменная тоже может быть слева от знака равенства. Значит, (такая) переменная — ссылка? Почти. Выражение, представляющее собой переменную — ссылка.
Этот принцип («выражение, являющееся переменной — ссылка») — моя выдумка. Т. е. ни в каком учебнике, стандарте и т. д. я этот принцип не видел. Тем не менее, он многое упрощает и его удобно считать верным. Если бы я реализовывал компилятор, я бы просто считал там переменные в выражениях ссылками, и, вполне возможно, именно так и предполагается в реальных компиляторах.
Более того, удобно считать, что особый тип данных для lvalue (т. е. ссылка) существует даже и в C. Именно так мы и будет дальше предполагать. Просто понятие ссылки нельзя выразить синтаксически в C, ссылку нельзя объявить.
Принцип «любое lvalue — ссылка» — тоже моя выдумка. А вот принцип «любая ссылка — lvalue» — вполне законный, общепризнанный принцип (разумеется, ссылка должна быть ссылкой на изменяемый объект, и этот объект должен допускать присваивание).
Операции * и &. Наши соглашения позволяют по-новому взглянуть на операции * и &. Теперь становится понятно следующее: операция * может применяться только к указателю (конкретно это было всегда известно) и она возвращает ссылку на тот же тип. & применяется всегда к ссылке и возвращает указатель того же типа. Таким образом, * и & превращают указатели и ссылки друг в друга. Т. е. по сути они вообще ничего не делают и лишь заменяют сущности одного синтаксиса на сущности другого! Таким образом, & вообще-то не совсем правильно называть операцией взятия адреса: она может быть применена лишь к уже существующему адресу, просто она меняет синтаксическое воплощение этого адреса.
Также замечу, что &*EXPR (здесь EXPR — это произвольное выражение, не обязательно один идентификатор) эквивалентно EXPR всегда, когда имеет смысл (т. е. всегда, когда EXPR — указатель), а *&EXPR тоже эквивалентно EXPR всегда, когда имеет смысл (т. е. когда EXPR — ссылка).
Массивы
Итак, есть такой тип данных — массив. Определяются массивы, например, так:
Выражение в квадратных скобках должно быть непременно константой времени компиляции в C89 и C++98. При этом в квадратных скобках должно стоять число, пустые квадратные скобки не допускаются.
то, опять-таки, место для массива будет целиком выделяться прямо внутри структуры, и sizeof от этой структуры будет это подтверждать.
Хорошо, будем считать, я вас убедил, что массив — это именно массив, а не что-нибудь ещё. Откуда тогда берётся вся эта путаница между указателями и массивами? Дело в том, что имя массива почти при любых операциях преобразуется в указатель на его нулевой элемент.
Конвертирование имени массива в void * или применение к нему == тоже приводит к предварительному преобразованию этого имени в указатель на первый элемент, поэтому:
Типы у участвовавших выражений следующие:
Массив нельзя передать как аргумент в функцию. Если вы напишите int x[2] или int x[] в заголовке функции, то это будет эквивалентно int *x и в функцию всегда будет передаваться указатель (sizeof от переданной переменной будет таким, как у указателя). При этом размер массива, указанный в заголовке будет игнорироваться. Вы запросто можете указать в заголовке int x[2] и передать туда массив длины 3.
Однако, в C++ существует способ передать в функцию ссылку на массив:
При такой передаче вы всё равно передаёте лишь ссылку, а не массив, т. е. массив не копируется. Но всё же вы получаете несколько отличий по сравнению с обычной передачей указателя. Передаётся ссылка на массив. Вместо неё нельзя передать указатель. Нужно передать именно массив указанного размера. Внутри функции ссылка на массив будет вести себя именно как ссылка на массив, например, у неё будет sizeof как у массива.
И что самое интересное, эту передачу можно использовать так:
Похожим образом реализована функция std::end в C++11 для массивов.
«Указатель на массив». Строго говоря, «указатель на массив» — это именно указатель на массив и ничто другое. Иными словами:
Однако, иногда под фразой «указатель на массив» неформально понимают указатель на область памяти, в которой размещён массив, даже если тип у этого указателя неподходящий. В соответствии с таким неформальным пониманием c и d (и b + 0 ) — это указатели на массивы.
А теперь посмотрим на такую ситуацию:
Два способа передачи параметров в функцию: по значению и по адресу
Помощь в написании контрольных, курсовых и дипломных работ здесь.

Привет! Помогите, пожалуйста, исправить ошибку. Конкретного задания нет, это пример передачи.
Способы передачи параметров в функцию
#include using namespace std; void swap1(int x, int y) < int z; z=x; x=y; y=z;.
всё так, только по моему
Решение
это код товарища, задавшего вопрос. совсем не доглядел, понадеялся на сознательность. изменил только шапку функции.
Добавлено через 2 минуты
В данной задаче смысла особого нет, я не искал логики в этой задаче, думал нужно просто показать каким образом передаются параметры по адресу.
Добавлено через 3 минуты
В коде товарища все переменные глобальные. можно вообще ничего не передавать.
Добавлено через 5 минут
Может я не прав, как мне кажется, всегда нужно передавать параметры по ссылке( ну или по адресу) дабы не создавать копий, в случае если переменная не должна модифицироваться просто добавлять const.
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Способ передачи параметров в функцию
Попалось мне на глаза утверждение, что первые Х параметров передаются через регистры, остальные на.

Всем добрый вечер. Никак не могу разобраться с темой передачи в функцию параметров. Знаю, что все.
Нужны два примера по вызову параметров по значению и по ссылке
Здравствуйте! Помогите мне пожалуйста! Препод задала задание, которое мы не проходили. я весь.
Передача параметров в функцию по значению, по ссылке и по указателю
Доброе время суток товарищи программисты. Столкнулся с кучей ошибок в написании простой программы.
Передача параметров в функцию по значению, по ссылке или по указателю
Передача параметров в функцию по значению, по ссылке или по указателю. Чем отличаются эти 3.







