LINUX.ORG.RU

Указатели в С и вообще

 ,


2

5

В чем принципиальная необходимость использования указателей? Почему нельзя обращаться к переменной в динамической памяти по ее имени, а не по адресу?

Для меня единственный пример, когда использование указателей естественно и неизбежно - это динамические структуры данных. Связанный список в принципе без указателей не сделать.

Это действительно так, С переиспользует указатели, там где без них можно было бы обойтись? Или есть какие-то детали работы с памятью, которые я упускаю?

★★★★

В чем принципиальная необходимость использования указателей?

Это быстро.

Почему нельзя обращаться к переменной в динамической памяти по ее имени

Можно. Для этого есть хэштаблицы.

Bad_ptr ★★★★★
()
Ответ на: комментарий от tailgunner

Ссылка - это совершенно не указатель. Хотя транслироваться в указатель она может, и в большинстве случаев будет.

А меняет это ответ на поставленный вопрос. x - обращение по имени, *p - нет.

anonymous
()
Ответ на: комментарий от anonymous

не поддерживается для динамических

Что такое «динамические»? память от alloca тоже динамическая?

int test(int foo)
{
int bar[foo]; //bar динамическая?
}
legolegs ★★★★★
()
Ответ на: комментарий от conalex

ссылка - это такой же указатель, но обсыпанный «синтаксическим сахаром».

Это если лезть глубоко в дебри. На уровне языка ссылка и указатель — это разные вещи.

Bad_ptr ★★★★★
()
Ответ на: комментарий от legolegs

Нет. Динамический - значит, в произвольной части кода можно создать, и в произвольной - удалить (или само удалится когда-нибудь).

anonymous
()
Ответ на: комментарий от anonymous

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

Таким образом, можно, в принципе, выделять динамический массив в стеке. И это реализовано в С99.

hotpil ★★★★
() автор топика
Ответ на: комментарий от legolegs

bar будет размещен в стеке в момент вызова функции test. И стерт из стека, когда выйдешь из функции.

hotpil ★★★★
() автор топика
Ответ на: комментарий от Bad_ptr

У Страуструпа, если не путаю, написано: «Ссылка - альтернативное имя объекта». Чтобы это не значило.

hotpil ★★★★
() автор топика
Ответ на: комментарий от VladimirMalyk

Указатели и ссылки - принципиально разные сущности.

Указатель - адрес в памяти, да. Ссылка - нечто, указывающее на объект. Как указывающая - деталь реализации. В C++ - как правило указатель (не обязательно), в питоне, емнип, - ключ в хеш-таблице. Да что угодно.

Отсюда уже следует, что для ссылок не имеет смысла арифметика: байты всегда образуют массив, а объекты не всегда. А будут ли они nullable - деталь языка (в C++ - нет).

anonymous
()
Ответ на: комментарий от hotpil

О весёлом

Некоторые ссылаются на отрывок с интервью с Страуструпом:

Очевидной реализацией ссылки является (константный) указатель, при каждом использовании которого происходит разыменование. В некоторых случаях компилятор может оптимизировать ссылку таким образом, что во время исполнения вообще не будет существовать объекта, представляющего ссылку.

conalex ★★★
()
Ответ на: комментарий от anonymous

А меняет это ответ на поставленный вопрос

На вопрос «В чем принципиальная необходимость использования указателей?» - не меняет.

x - обращение по имени, *p - нет.

Просто для протокола: и то, и другое - это обращение по указателю.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Мы говорим об одном и том же, разными языками.

Указатели - термин из си. Такие штуки со звездочками. Так вот, указатели для обращения к объектам принципиально ненужны, ибо любому объекту можно назначить имя. В си - гипотетически любому. Прямое имя, без косвенности указателя.

x - это объект. Не адрес, по которому лежит объект. Не надо говорить что это одно и то же.

То что под капотом всё это - все переменные и указатели - скомпилируется в обращения по адресам - очевидно и нерелевантно.

anonymous
()
Ответ на: комментарий от anonymous

x - это объект. Не адрес, по которому лежит объект.

x - это именно адрес, по которому лежит объект.

То что под капотом всё это - все переменные и указатели - скомпилируется в обращения по адресам - очевидно и нерелевантно.

Судя по вопросам ТС, ему это не очевидно.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

А зачем передавать переменные в функцию или процедуру по значению? В чём преимущества, ведь под копию выделяется дополнительная память?

grem ★★★★★
()
Ответ на: комментарий от metawishmaster

Вы, видимо, не сталкивались с необходимостью пользоваться указателями на указатели?

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

anonymous
()
Ответ на: комментарий от tailgunner

x - это именно адрес, по которому лежит объект.

В ассемблере будет адрес, в си - все еще объект. ТС-то про си спрашивал, зачем все кинулись в ассемблер?

anonymous
()
Ответ на: комментарий от grem

А зачем передавать переменные в функцию или процедуру по значению?

В cpp core guidelines рекомендуется передавать по значению POD-структуры размером до двух-трех слов. Обращение по указателю тоже несет накладные расходы.

anonymous
()
Ответ на: комментарий от hotpil

По-моему, ты путаешь static storage duration и automatic storage duration.

fluorite ★★★★★
()
Ответ на: комментарий от hotpil

Но это не правда! Все локальные переменные размещаются в стеке

Это называется «автоматические переменные».

в принципе, выделять динамический массив в стеке. И это реализовано в С99

alloca вроде как существует с незапамятных времён.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от hotpil

«Ссылка - альтернативное имя объекта». Чтобы это не значило.

Что б ты понял. Ссылки в крестах появились именно потому, что при массовом использовании объектов не очень удобно хранить и передавать их в функции, т.к. в си не было «передачи по ссылке», для этого использовались указатели.

no-such-file ★★★★★
()

Вот что бывает, когда программирование учат не с ассемблера, а с какого-нибудь PHP.

Deleted
()
Ответ на: комментарий от Deleted

Каждому кусочку памяти уже дали имя. Называется это имя «адрес». Записывается цифрами. И именно такое «имя» храниться в указателе ;-)

trex6 ★★★★★
()
Ответ на: комментарий от anonymous

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

grem ★★★★★
()

в мире существует только один нормальный язык, и это - PHP

раз в PHP нет указателей, значит они не нужны

One life, One Love, One PHP

PS а все сишники отстали от жизни, скоро PHP будет написан на PHP и вы станете не нужны. Придурки.

anonymous
()
Ответ на: комментарий от Deleted

Вот что бывает, когда программирование учат не с ассемблера

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

ТС в общем-то правильно интересуется, т.к. из-за отсутствия ссылок в си приходится пердолиться с указателями на структуры - не забывать писать some_foo(&struct_var).

а с какого-нибудь PHP

Кстати забавно, что илита когда-то обкакивала пых именно за такой синтаксис, во времена 4 версии.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Ссылка — это синтаксический сахар для указателя, а указатель — это синтаксический сахар для адресов памяти (впрочем, как и весь Си — сахар над машкодами). Это банальщина, чего тут нового...

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

Нет, дело не в этом. Программисты программируют фоннеймановские машины. Это машины, занимающие не свёткой РЕФАЛ-выражений или еще какой-нибудь великолепной чертовщиной, а скучно перемалывающие байты в регистрах. Знать, как они устроены, необходимо. Это фундамент. Это как матанализ, необходимый для понимания физики. Хотя бы в общих чертах его необходимо знать, если имеешь дело с физическими теориями, а то вон в толксах некоторые с амперами и кулонами разобраться мне могут. Так же и тут. Можно писать на PHP, но писать на PHP без понимания работы компьютера — скучно и грустно.

Deleted
()
Ответ на: комментарий от Deleted

Программисты программируют фоннеймановские машины

Ассемблерщики программируют машины. В случае ЯВУ хороший программист пишет под абстрактную машину языка. На какое железо она отобразится - должно быть пофиг, пока не работаешь с железом, или доходишь до текущих абстракций (которых в си вообще-то довольно). Иначе получишь непортируемый код, который может сломаться (и таки ломается, случаев было достаточно) даже при обновлении компилятора.

писать на PHP без понимания работы компьютера — скучно и грустно

Так это тебе. Не всех прикалывает байтоложство.

anonymous
()
Ответ на: комментарий от grem

Это для случая когда нужно иметь переменную для указателя или вообще?

Не понял вопроса. Это для случая, когда объект передается в функцию in-параметром.

void f(const big &a1, small a2);

anonymous
()
Ответ на: комментарий от anonymous

Дебил ты! Хуже пыхпыха разве что си-диез или жабка…

anonymous
()
Ответ на: комментарий от anonymous

пишет под абстрактную машину языка

Это верно. Модель исполнителя программист должен знать «от и до». Но эта «абстрактная машина языка» будет исполняться на конкретной железке с традиционным CPU, потому что других человечество пока не изобрело. На том уровне, на котором нет разницы между конкретными железками (x86 там или MIPS...), программист должен иметь представление о работе железа. Не требуется знать конкретно MIPS, если нет задачи низкоуровнещину писать под MIPS; но знать принципы работы — нужно.

То есть, он, конечно, не «должен»... Никто ему не прикажет. Но это как профессиональному водителю не иметь представлений о том, что у машины под капотом.

Deleted
()
Ответ на: комментарий от hotpil

Память же, выделенная в «куче», остается выделенной на все время исполнения программы.

Нет. Размер кучи увеличивается и уменьшается системным вызовом brk (man 2 brk). Вот, кстати, есть хорошая статья которая разъясняет особенности стека, кучи и зеркалированной памяти (memory mappings) и как они работают: http://marek.vavrusa.com/c/memory/2015/02/20/memory/

Deleted
()

Их и надо использовать там, где без них не обойтись.

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

evilface ★★
()
Ответ на: комментарий от crutch_master

Тебе надо поместить в eax 32 бита.

Вообще-то, под переменную можно выделять место на стеке. И это либо одно слово, либо блок слов известного объема.

iVS ★★★★★
()
Ответ на: комментарий от hotpil

Его (параметра) адрес известен на этапе компиляции? В принципе нет, потому что число параметров неизвестно.

По-моему, это никак не связано с количеством параметров, число которых может быть известно.

Но к нему же обращаются по имени.

Имя? Может регистр или адрес на стеке?

iVS ★★★★★
()

принципиальная необходимость использования указателей в том, что в эпоху К&R памяти и вычислительных мощностей у кампутеров было мало, а времени у разработчиков - много.

Теперь все наоборот: три, два, раз - и в продакшен. Отсюда столько холиваров.

zudwa
()
Ответ на: комментарий от Deleted

Программисты программируют фоннеймановские машины. Это машины, занимающие не свёткой РЕФАЛ-выражений или еще какой-нибудь великолепной чертовщиной, а скучно перемалывающие байты в регистрах.

Простите, но откуда в «фоннеймановских машинах» регистры?

evilface ★★
()
Ответ на: комментарий от anonymous

В ассемблере будет адрес, в си - все еще объект.

Какой нахрен объект? В каком си? Это в голове у тебя объект и всё, что угодно. На деле это всё - куча сраных адресов, которые ссылаются на какие-то данные, которые, в свою очередь, тоже могут являются адресами. Обращение по имени подразумевает хранение где-то этого имени в рантайме. В случае T &x = *new T; x является именем экземпляра структуры T только для кодера. По факту - это адрес.

Указатели - термин из си. Такие штуки со звездочками.

После такого даже *я* могу чувствовать себя царём си.

ТС-то про си спрашивал, зачем все кинулись в ассемблер?

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

crutch_master ★★★★★
()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от hotpil

На самом деле мой вопрос возник скорее из-за не правильного понимания

Твой вопрос возник из-за того, что ты не смог в T &x = *new T;

crutch_master ★★★★★
()

Пиши на Java, там всё как ты хочешь

stevejobs ★★★★☆
()
Ответ на: комментарий от crutch_master

Кодер на си должен точно понимать что он кодит и во что оно превращается.

можно написать Си на каком-нибудь современном средстве написания DSL, тогда пройдя через цепочку DSL VM -> Low Level VM (JVM/.NET CLR) -> код, уже никаким разумным образом нельзя будет понять, в какой машкод это превратится =) Более того, в ходе агрессивных оптимизаций результирующий код будет вообще никак не связан с исходным =)

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от hotpil

Вот в функции есть параметр. Где он храниться? В стеке. Его (параметра) адрес известен на этапе компиляции? В принципе нет, потому что число параметров неизвестно. Но к нему же обращаются по имени.

К нему обращаются по адресу.

Адрес фрейма стека хранится в регистре ESP. (Примечание: про различие ESP и EBP и практическую ненужность второго распространяться не будем в целях простоты изложения.)

Код функции обращается к аргументу функции по адресу «ESP + смещение», где смещение — константное значение: вычисленное компилятором смещение для данного аргумента.

Нет никаких имён в машкоде.

Deleted
()
Ответ на: комментарий от Deleted

я так понял, чувак спросил, в чем теоретическое обоснование необходимости указателей в Си. Ответ - теоретической необходимости нет. Просто когда си делали в далеком 1972, у людей были несколько другие проблемы, как упарывать по хипстоте и замедлять компилятор в 1000 раз такими фокусами. Сейчас уже наплевать на скорость компиляции, но Си уже никто изменять не станет. Берешь какой-нибудь golang и упарываешься по жести (по нему даже Керниган из Керниган-и-Ричи книжку выпустил)

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от hotpil

В принципе нет, потому что число параметров неизвестно.

число параметров более чем известно. Сишка не динамическая, не умеет в горячую подгрузку кода, неоткуда взяться функциям с неопределенным числом именованых параметров. На этапе компиляции компилятор тебе уже может весь memory layout нарисовать хоть в картинках.

(интересно, а есть какие-нибудь такие визуализаторы? просто чтобы попыриться в них и подрочить на киношку с изменяющимися красивыми картинками)

stevejobs ★★★★☆
()
Ответ на: комментарий от Deleted

где смещение — константное значение: вычисленное компилятором смещение для данного аргумента

кстати вот оцени глубину, в которой погрязла современность. Мы сейчас делаем язык, и в качестве значения параметров функции он может принимать XML. И потом в коде функции можно ссылаться на значения в этом XML простым способом, как если бы они были переменными. Типа круто, удобно. А теперь внимание вопрос: сколько операций нужно сделать процессору чтобы вычислить адрес значения, лежащего в XML? Ооооопс, here goes the тормоза!

stevejobs ★★★★☆
()
Ответ на: комментарий от stevejobs

O_O

Мы сейчас делаем язык, и в качестве значения параметров функции он может принимать XML. И потом в коде функции можно ссылаться на значения в этом XML простым способом, как если бы они были переменными.

Где ваша организация травой закупается?

Deleted
()
Ответ на: O_O от Deleted

это не организация, а один из пет-проектов :) Хотя если получится, продадим организации

ну сейчас же основные методы передачи данных - это XML и JSON (причем JSON куда хуже, т.к. у него нет схемы, читай «черт знает что прилетело). И код современного микросервиса начинает на 60% быть заполнен всяким говном типа - прилетел JSON сконвертим его в объект, объект чуточку поправим сконвертим в JSON отправим соседнему микросервису чтобы он сконвертил его снова в объект... и так туда сюда обратно до бесконечности. Скоро разработчик начинает чувствовать себя машинкой по написанию JSON/XML и CRUDов =) Поэтому можно сразу смириться с неизбежным и сделать этот парсинг частью языка (но не как в XSLT, а по-нормальному, в императивной манере)

на самом деле можно это оптимизировать. Обычно метод выполняется с XML/JSON примерно одинаковой структуры. Эту структуру можно считать „анонимным временным типом“. Когда выполняется первый вызов метода, профилировщик изменяет AST так, что вместо вызова универсальной функции там проставляется этот „временный тип“, и адреса на „переменные“ все кэшируются. При последующих запросах проверяется (не спрашивай как), не изменилась ли структура, и дальше используются кэшированные значения. Это сильно всё ускоряет. Надо на Швабр запилить статью об этой оптимизации.

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.