что делает амперсанд в с
Для чего нужен указатель в Си?
Jan 27 · 3 min read
Указатель в Си — это переменная, содержащая адрес другой переменной. Сложность указателей заключается в понимании где и для чего они могут пригодиться.
Перед тем, как я начну рассказывать об указателях и зачем они программистам, быстренько вспомним основы:
Указатель
В Си указателем называется переменная, содержащая адрес другой переменной. Его можно использовать с любым типом данных, написав:
Для чего нужен указатель в Си
Функции в Си п ринимают аргументы, передавая или копируя значения в стек функции. Такой метод иногда называется передачей по значению. Поскольку функции в Си и переменные, переданные им, в действительности не связываются, любые внесённые изменения в эти переменные не будут сохраняться за пределами действия функции. Это может вызвать сложности, потому что в некоторых функциях необходимо изменять текущие переменные. Здесь-то нам и пригодится указатель. С его помощью можно получить доступ к памяти, находящейся за пределами стекового кадра. Однако важно отметить, что с помощью указателя можно получить доступ лишь к переменным, расположенным ниже текущего кадра.
В примере выше простая функция с задачей — увеличить на единицу число, проходящее через параметры. Функция написана следующим образом:
Указатель в языке Си
Указатель — переменная, содержащая адрес объекта. Указатель не несет информации о содержимом объекта, а содержит сведения о том, где размещен объект.
Указатели широко используются в программировании на языке Си.
Указатели часто используются при работе с массивами.
Память компьютера можно представить в виде последовательности пронумерованных однобайтовых ячеек, с которыми можно работать по отдельности или блоками.
Каждая переменная в памяти имеет свой адрес — номер первой ячейки, где она расположена, а также свое значение. Указатель — это тоже переменная, которая размещается в памяти. Она тоже имеет адрес, а ее значение является адресом некоторой другой переменной. Переменная, объявленная как указатель, занимает 4 байта в оперативной памяти (в случае 32-битной версии компилятора).
Указатель, как и любая переменная, должен быть объявлен.
Общая форма объявления указателя
Тип указателя — это тип переменной, адрес которой он содержит.
Для работы с указателями в Си определены две операции:
Для указанного примера обращение к одним и тем же значениям переменной и адреса представлено в таблице
Расположение в памяти переменной a и указателя b:
Необходимо помнить, что компиляторы высокого уровня поддерживают прямой способ адресации: младший байт хранится в ячейке, имеющей младший адрес.
Комментариев к записи: 80
// Функция кодирования текста
uint32_t* encrypt(uint32_t* v, uint32_t* k)
<
uint32_t v0 = v[0];
uint32_t v1 = v[1];
uint32_t sum = 0;
/* a key schedule constant */
uint32_t delta = 0x9e3779b9;
/* cache key */
uint32_t k0 = k[0];
uint32_t k1 = k[1];
uint32_t k2 = k[2];
uint32_t k3 = k[3];
uint32_t i;
/* basic cycle start */
for (i = 0; i 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
>
/* end cycle */
return v; // Возвращаем указатель на нулевой элемент массива зашифрованного числа
// Функция декодирования текста
uint32_t* decrypt(uint32_t* v, uint32_t* k)
<
/* set up */
uint32_t v0 = v[0];
uint32_t v1 = v[1];
uint32_t sum = 0xC6EF3720;
uint32_t i;
/* a key schedule constant */
uint32_t delta = 0x9e3779b9;
/* cache key */
uint32_t k0 = k[0];
uint32_t k1 = k[1];
uint32_t k2 = k[2];
uint32_t k3 = k[3];
uint32_t* plain;
char shelf1[8]; // В массив записан текст из 8-символов
char shelf2[8];
plain = (uint32_t*)shelf1; // Загружаем текст в plain
uint32_t* encoded = encrypt(plain, key); // Шифруем текст
uint32_t* decoded = decrypt(plain, key); // Расшифровываем текст
uint32_t* decrypt(uint32_t* v, uint32_t* k)
<
/* set up */
uint32_t v0 = v[0];
uint32_t v1 = v[1];
%ls pointers.c:14:66: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=] printf(«\n Значение указателя b равно %x шестн.», b);
^ %ls pointers.c:15:85: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int **’ [-Wformat=] ntf(«\n Адрес расположения указателя b равен %x шестн.», &b);
#include
#include
#include
void helloWorld (GtkWidget *wid, GtkWidget *win)
<
GtkWidget *dialog = NULL ;
dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, sqlite3_libversion());
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
>
int main ( int argc, char *argv[])
<
GtkWidget *button = NULL ;
GtkWidget *win = NULL ;
GtkWidget *vbox = NULL ;
/* Create a vertical box with buttons */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (win), vbox);
/* Enter the main loop */
gtk_widget_show_all (win);
gtk_main ();
return 0;
>
Зачем в Go амперсанд и звёздочка (& и *)?
Указатели
Про то, что такое и как устроены указатели я писал в статье «Как не наступать на грабли в Go», которую рекомендую к прочтению даже не новичкам в Go. Краткий повтор про указатели:
по сути, это один блок памяти, который содержит адрес другого блока памяти, где лежат данные. Если вы слышите фразу «разыменовать указатель», то это означает «найти данные из блока памяти, на который указывает этот адрес».
Вот визуализация из статьи:
Здесь Point <10, 20>это «литерал» — новая переменная, объявленная на месте, «блок памяти», а & — это «адрес этого блока памяти».
Тот же код, но запишем тип b явно:
здесь звёздочка означает «тип указатель на число». Но, если она используется не перед типом, а перед самой переменной, то значение меняется на обратное — «значение по этому адресу»:
Это может запутывать и сбивать с толку, особенно людей, никогда, не работавших с указателями, которых нет, например, в таких популярных языках как JavaScript или Ruby. Причём в языках вроде C и С++ есть ещё масса применений указателям, например «арифметика указателей», позволяющая вам прямо смещениями по сырой памяти бегать и реализовывать невероятно быстрые по современным меркам структуры данных. Ещё очень удобно переполнение буфера получать благодаря этому, создавая баги, приносящие ущерб на миллиарды долларов. Есть даже целые книги по тому, как понимать указатели в С.
Но если механика работы с указателями в Go относительно простая, остаётся открытым вопрос — почему «амперсанд» и «звёздочка» — что это вообще должно означать? Возможно это потому что символы рядом на клавиатуре ( Shift-7 и Shift-8 )? Ну а чтобы понять любую тему, нет способа лучше, нежели копнуть её историю.
История
А история такова. Одним из авторов Go был легендарный Кен Томпсон, один из пионеров компьютерной науки, подаривший нам регулярные выражение, UTF-8 и язык программирования B, из которого появился C, на базе которого, 35 лет спустя, появился Go. Вообще, генеалогия Go немного сложнее, но С был взят за основу по той простой причине, что это язык, который десятилетиями был стандартом для изучения программирования в университетах, ну и о его популярности в своё время, думаю, не нужно говорить.
И хотя сейчас Кен Томпсон отошёл немного от Go и летает на своём частном самолёте, его решения проникли в Go ещё задолго до Go. В юности он развлекался тем, что писал на завтрак новые языки программирования (слегка утрирую), и одним из языков, который был им создан вместе с ещё одной легендой компьютерной науки Денисом Ритчи, являлся язык программирования B (Би).
В то время Кен Томпсон написал операционную систему на ассемблере для компьютера PDP-7, который стоил 72000 долларов — а это примерно полмиллиона долларов сегодня — обладал памятью в 9 КБ (расширялась до 144КБ) и выглядел вот так:
Собственно, эта операционная система называлась Unics, и затем была переименована в UNIX. И когда зашла речь о переписывании её для нового крутого компьютера PDP-11, было принято решение писать на каком-то более высокоуровневом языке программирования. BCPL, который был предшественником B был слишком многословен — много букв. B был более лаконичен, но имел другие проблемы, которые делали его плохим кандидатом для портирования UNIX на PDP-11. Именно тогда Денис Ритчи и начал работать над новым языком, во многом основанном на B, специально для написания UNIX под PDP-11. Имя C было выбрано, как следующая буква алфавита после B.
Но вернёмся к теме об амперсанде и звёздочке. Звёздочка ( * ) была ещё в языке BCPL, и в B попала с тем же смыслом обозначения указателя, просто потому что так было в BCPL. Ровно по этой же причине перекочевали в С.
А вот амперсанд (&), означающий «адрес переменной», появился в B (и также перекочевал в С просто потому что), и был выбран по нескольким причинам:
Если я вас запутал, то вот нагляднее:
И тут нужно посмотреть внимательно на клавиатуры того времени. Чуть выше на картинке PDP-7 можно рассмотреть вводное устройство, коим являлся Телетайп 33. Стоит посмотреть на его клавиатуру повнимательнее, чтобы понять реалии того времени, и понять, с какими ограничениями сталкивались программисты и дизайнеры языков программирования в то время:
Как можно увидеть, ни тачбара, ни эмоджи не было :), и символы приходилось выбирать только из того набора, который был в телетайпе. Также, примечательно, что амперсанд и звёздочка тогда были не рядом, а на целых 4 клавиши порознь, что опровергает идею выбора амперсанда из-за близости клавиш. Собственно, из всех доступных клавиш, Кену Томпсону на тот момент больше всего приглянулся «амперсанд», похожий на «адрес».
Ну а дальше вы знаете — С стал языком века (прошлого), повлиял на огромное количество других языков, а книги по С стали настольными библиями программистов на несколько десятилетий. В таком же виде указатели вместе со звёздочкой и амперсандом попали и в С++ — ещё один язык мейнстримовый язык, на котором до Go писалась большая часть сетевого и серверного софта.
Поэтому решение включить указатели (без арифметики указателей, к счастью) в Go с тем же синтаксисом — было вполне логичным и естественным. Для С/C++ программистов это такие же базовые и простые понятия, как скобочки < и >.
И всё таки это удивительно осознавать, какое сильное влияние имеют исторические решения, принятые пол столетия назад на современные технологии.
Заключение
Если вы всё ещё неуверенно себя чувствуете себя с указателями в Go, запомните два простых правила:
Надеюсь, кому то это немного поможет лучше понимать смысл указателей и символов, стоящими за ними в Go.
Амперсанд перед именем функции
Знак Указателя перед именем функции
Не могу понять с какой целью перед именами функций стоит знак указателя в книге? Скрин: <ссылка.
перед именем функции? И что он значит вообще?
Нюансы синтаксиса: почему при некоторых перегрузках перед operator пишут амперсанд (используют ссылку)?
Привет. Почему при некоторых перегрузках оператора используется, к примеру, такой синтаксис Array.
Итератор: for и амперсанд
В чем разница нового и старого for в переборе коллекций? vector
канешна не возвращает, чего ты хотел, этаж всего прототип
Добавлено через 8 минут
5 мин мазохизма и что получается
Это функция возвращающая ссылку. В C, в отличии от С++, ссылок нет.
Добавлено через 9 минут
лендер, и на что у тебя здесь,
не очень ясен вопрос
Хотя бы так. Память то кто будет выделять? Хотя смысла в этом вообще нет. +утечка памяти
Лучше пример все же будет полагаю:
Возвращаем ссылку на элемент класса std::ostream.
А если попытаться сделать так:
Решение
На самом деле это амперсанд НЕ перед именем функции, а после типа функции. Т.е. «более правильным» было бы отформатировать запись как
Добавлено через 33 минуты
Если в обоих случаях (в случае * перед именем функции, и & после типа) возвращается адрес переменной, тогда зачем это делается?)
Указатель и амперсанд
Всем здрасьте. У меня тут возник вопрос. Приведу простой примерчик двух функций(не смотрите на.
Вызов функции с неизвестным именем
Я знаю, что напрямую нельзя вызвать функцию по имени, которое хранится в char* но, может как-то.
Не пойму что означает амперсанд в инструкции if
Здравствуйте, объясните пожалуйса, что знчит амперсант в инструкции if ведь здесь он не выполняет.
Объявление функций. Амперсанд в сигнатуре метода
На днях начал изучать С++. Сам джавист. Вижу такую сигнатуру: void write_analysis(ostream& out.
Что означает значок & и зачем он нужен? Объясняем за 3 минуты
M&M’s, H&M. Откуда в английском появилась эта странная закорючка между буквами, как ее использовать и реально ли вообще нарисовать ее от руки. Рассказываем все самое интересное про & за три минуты.
Что означает & и как называется
Тогда эту закорючку и начали называть and per se and — то есть «непосредственно and». Постепенно and per se and превратилось в ampersand (амперсанд) — современное название.
Это правдивая версия происхождения. Но есть еще легенда: по слухам, символом злоупотреблял французский физик и математик Андре-Мари Ампер, отсюда и название Ampere’s and → ampersand.
Уже покорили английский алфавит и думаете, куда двигаться дальше? Ловите бесплатный личный план для новичков. Внутри советы и материалы, которые помогут вашему английскому перейти на новый уровень.
Откуда взялся амперсанд
Символ появился на полторы тысячи лет раньше своего названия — он встречается еще на древних граффити в Помпеях.
В латинском языке союз «и» звучит как et. Для удобства и экономии места буквы часто писали слитно, не отрывая руки, — в итоге получалось что-то похожее на &. В общепринятом типографском знаке трудно разглядеть «E» и «T», но посмотрите на другие варианты написания:
Как использовать амперсанд
Вы не встретите амперсанд в эссе, в статье The New York Times или в имейле. Сегодня он используется в основном в названиях компаний и брендов: H& M, Johnson & Johnson, Marks & Spencer, M& M’s.
В таких названиях and не проговаривается полностью, а теряет букву «D» — и превращается в [эн], например M& M’s читается [эм-эн-эмс].
Раз в год, 8 сентября, в National Ampersand Day, к символу отчасти возвращается былое величие. В этот день энтузиасты заменяют and в любых словах амперсандом: android — & roid, band — b&, grandma — gr& ma. Если настроены особо креативно, придумайте свой дизайн символа и запостите в инстаграм с хештегом #AmpersandDay.
Как написать амперсанд от руки
Амперсанд отлично смотрится на открытках, пригласительных и ярлычках для подарков — Новый год уже не за горами. Немного практики, и вы наловчитесь писать красивые & от руки.