Я знаю, что это действительно простой вопрос, но я только начал с некоторого базового программирования на C++ после написания нескольких проектов на языках высокого уровня.
В основном у меня три вопроса:
Еще один указатель обсуждения здесь.
Обсуждалась ранее на этот вопрос Надеюсь, что это поможет!
Мы используем указатели, потому что легче дать кому-то адрес своего дома, чем дать всем копию своего дома.
@RishiDua Это единственное лучшее объяснение указателя, с которым я когда-либо сталкивался. Спасибо за это, это расширило мое понимание :)
Указатели также можно использовать, если вы хотите вернуть более одного значения / объекта.
Следуя Риши Дуа, ссылки в комментариях выше похожи на указатели. Представьте, если бы вместо этого они скопировали и вставили сюда целые статьи или обсуждения. У нас бы быстро "не хватало места" на странице





Указатели - это один из способов получить косвенную ссылку на другую переменную. Вместо того, чтобы хранить ценить переменной, они сообщают вам ее адрес. Это особенно полезно при работе с массивами, поскольку, используя указатель на первый элемент в массиве (его адрес), вы можете быстро найти следующий элемент, увеличивая указатель (до следующего местоположения адреса).
Лучшее объяснение указателей и арифметики указателей, которое я читал, находится в Язык программирования C K&R. Хорошая книга для начинающих изучать C++ - Учебник по C++.
благодарю вас! наконец, практическое объяснение преимуществ использования стека! указатель на позицию в массиве также улучшает производительность доступа к значениям @ и относительно указателя?
Это, наверное, лучшее объяснение, которое я читал. люди умеют "усложнять" вещи :)
По большей части указатели представляют собой массивы (в C / C++) - это адреса в памяти, и при желании к ним можно обращаться как к массиву (в «обычных» случаях).
Поскольку они являются адресом объекта, они маленькие: они занимают только место в адресе. Поскольку они маленькие, их отправка в функцию обходится недорого. И затем они позволяют этой функции работать с фактическим элементом, а не с копией.
Если вы хотите выполнить динамическое распределение памяти (например, для связанного списка), вы должны использовать указатели, потому что они единственный способ получить память из кучи.
Я считаю ошибочным утверждать, что указатели - это массивы. На самом деле имена массивов являются константными указателями на первый элемент массива. Просто потому, что вы можете получить доступ к произвольной точке, как будто это массив, не означает, что это так ... вы можете получить нарушение доступа :)
Указатели - это не массивы. Прочтите раздел 6 comp.lang.c FAQ.
Указатели на самом деле не массивы. Кроме того, необработанные массивы также не очень полезны - определенно не после C++ 11 и std::array.
@einpoklum - указатели достаточно близки к массивам, чтобы быть эквивалентными в ссылочных операциях и итерациях по массивам :) .... также - C++ 11 находился через 3 года до выпуска, когда этот ответ был написан в 2008 году
@warren: указатели - это не массивы и не близкие к массивам, они просто распадаются на массивы. С педагогической точки зрения неуместно говорить людям, что они похожи. Кроме того, вы, безусловно, можете иметь ссылки на массивы, которые не относятся к тому же типу, что и указатели, и сохраняют информацию о размере; см. здесь
@einpoklum - очевидно, что вы придерживаетесь другой точки зрения.
Потому что копирование больших объектов повсюду тратит время и память.
И как в этом помогают указатели? Я думаю, что человек, пришедший с Java или .Net, не знает разницы между стеком и кучей, поэтому этот ответ довольно бесполезен ..
Можно пройти по ссылке. Это предотвратит копирование.
@MatsFredriksson - Вместо того, чтобы передавать (копировать) большую структуру данных и снова копировать результат, вы просто указываете, где он находится в ОЗУ, а затем изменяете его напрямую.
Так что не копируйте большие объекты. Никто не сказал, что для этого нужны указатели.
Вот пример на C:
char hello[] = "hello";
char *p = hello;
while (*p)
{
*p += 1; // increase the character by one
p += 1; // move to the next spot
}
printf(hello);
отпечатки
ifmmp
потому что он берет значение для каждого символа и увеличивает его на единицу.
because it takes the value for each character and increments it by one. Есть в представлении ascii или как?
p=0; сбрасывает указатель?
Одна из причин использования указателей заключается в том, что переменная или объект могут быть изменены в вызываемой функции.
В C++ лучше использовать ссылки, чем указатели. Хотя ссылки по сути являются указателями, C++ до некоторой степени скрывает этот факт и создает впечатление, будто вы передаете по значению. Это позволяет легко изменить способ получения значения вызывающей функцией без изменения семантики его передачи.
Рассмотрим следующие примеры:
Использование ссылок:
public void doSomething()
{
int i = 10;
doSomethingElse(i); // passes i by references since doSomethingElse() receives it
// by reference, but the syntax makes it appear as if i is passed
// by value
}
public void doSomethingElse(int& i) // receives i as a reference
{
cout << i << endl;
}
Использование указателей:
public void doSomething()
{
int i = 10;
doSomethingElse(&i);
}
public void doSomethingElse(int* i)
{
cout << *i << endl;
}
Возможно, стоит упомянуть, что ссылки более безопасны, поскольку вы не можете передавать пустую ссылку.
Да, это, наверное, самое большое преимущество использования ссылок. Спасибо, что указали на это. Никакой каламбур :)
Вы наверняка может передаете нулевую ссылку. Это не так просто, как передать нулевой указатель.
согласен с @ n0rd. Если вы думаете, что не можете передать пустую ссылку, вы ошибаетесь. Легче передать висящую ссылку, чем нулевую, но в конечном итоге вы можете сделать и то, и другое достаточно просто. Ссылки - это не серебряная пуля, защищающая инженера от ранения себе в ногу. Смотрите вживую.
@ n0rd: Это явно неопределенное поведение.
Это не повод использовать указатель, это повод использовать ссылки. И, на самом деле, это плохая причина, и мы должны избегать использования аргументов, не являющихся константными ссылками, если это действительно не необходимо (а обычно это не так).
Указатели важны во многих структурах данных, дизайн которых требует способности эффективно связывать или связывать один «узел» с другим. Вы не стали бы «выбирать» указатель, скажем, над обычным типом данных, таким как float, у них просто разные цели.
Указатели полезны там, где требуется высокая производительность и / или компактный объем памяти.
Адрес первого элемента в вашем массиве может быть назначен указателю. Затем это позволяет вам напрямую обращаться к лежащим в основе выделенным байтам. Однако весь смысл массива заключается в том, чтобы вам не приходилось делать это.
Вот немного другой, но проницательный взгляд на то, почему многие функции C имеют смысл: http://steve.yegge.googlepages.com/tour-de-babel#C
По сути, стандартная архитектура ЦП - это архитектура фон Неймана, и чрезвычайно полезно иметь возможность ссылаться на расположение элемента данных в памяти и выполнять с ним арифметические операции на такой машине. Если вы знаете какой-либо вариант языка ассемблера, вы быстро поймете, насколько это важно на низком уровне.
C++ делает указатели немного запутанными, поскольку иногда управляет ими за вас и скрывает их эффект в виде «ссылок». Если вы используете прямой язык C, потребность в указателях гораздо более очевидна: нет другого способа выполнить вызов по ссылке, это лучший способ сохранить строку, это лучший способ перебрать массив и т. д.
Одно из способов использования указателей (я не буду упоминать о вещах, уже описанных в сообщениях других людей) - это доступ к памяти, которую вы не выделили. Это не очень полезно для программирования на ПК, но используется во встроенном программировании для доступа к устройствам с отображением памяти.
В старые времена DOS вы могли напрямую обращаться к видеопамяти видеокарты, объявляя указатель на:
unsigned char *pVideoMemory = (unsigned char *)0xA0000000;
Многие встроенные устройства до сих пор используют эту технику.
Нет причин использовать указатель - структура типа span, которая также содержит длину, гораздо более уместна. Сейчас это gsl::span, а скоро будет std::span.
Короткий ответ: не надо. ;-) Указатели следует использовать там, где больше ничего нельзя использовать. Это либо из-за отсутствия соответствующей функциональности, отсутствия типов данных, либо из-за чистой производительности. Подробнее ниже ...
Краткий ответ: там, где вы больше ничего не можете использовать. В C нет поддержки сложных типов данных, таких как строка. Также нет способа передать переменную «по ссылке» в функцию. Вот где вам нужно использовать указатели. Также вы можете заставить их указывать практически на что угодно, связанные списки, элементы структур и так далее. Но не будем здесь вдаваться в подробности.
Приложив немного усилий и много путаницы. ;-) Если мы говорим о простых типах данных, таких как int и char, разница между массивом и указателем небольшая.
Эти объявления очень похожи (но не одинаковы - например, sizeof вернет разные значения):
char* a = "Hello";
char a[] = "Hello";
Вы можете получить доступ к любому элементу в массиве следующим образом
printf("Second char is: %c", a[1]);
Индекс 1, поскольку массив начинается с элемента 0. :-)
Или вы могли бы сделать то же самое
printf("Second char is: %c", *(a+1));
Оператор указателя (*) необходим, поскольку мы сообщаем printf, что хотим напечатать символ. Без * было бы напечатано символьное представление самого адреса памяти. Теперь мы используем самого персонажа. Если бы мы использовали% s вместо% c, мы бы попросили printf распечатать содержимое адреса памяти, на который указывает 'a' плюс один (в этом примере выше), и нам бы не пришлось ставить * спереди:
printf("Second char is: %s", (a+1)); /* WRONG */
Но это не просто напечатало бы второй символ, а вместо этого все символы в следующих адресах памяти, пока не был бы найден нулевой символ (\ 0). И здесь все становится опасным. Что, если вы случайно попытаетесь напечатать переменную типа integer вместо указателя char с помощью программы форматирования% s?
char* a = "Hello";
int b = 120;
printf("Second char is: %s", b);
Это напечатает все, что найдено по адресу памяти 120, и продолжит печать, пока не будет найден нулевой символ. Выполнять этот оператор printf неправильно и незаконно, но он, вероятно, все равно будет работать, поскольку во многих средах указатель фактически имеет тип int. Представьте себе проблемы, которые вы могли бы вызвать, если бы вместо этого использовали sprintf () и назначили таким образом слишком длинный «массив символов» другой переменной, для которой было выделено только определенное ограниченное пространство. Скорее всего, вы закончите записывать что-то еще в памяти и вызвать сбой вашей программы (если вам повезет).
Да, и если вы не присваиваете строковое значение массиву / указателю char при его объявлении, вы ДОЛЖНЫ выделить ему достаточный объем памяти, прежде чем присвоить ему значение. Использование malloc, calloc или подобных. Это потому, что вы объявили только один элемент в своем массиве / один адрес памяти, на который нужно указывать. Итак, вот несколько примеров:
char* x;
/* Allocate 6 bytes of memory for me and point x to the first of them. */
x = (char*) malloc(6);
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* Delete the allocation (reservation) of the memory. */
/* The char pointer x is still pointing to this address in memory though! */
free(x);
/* Same as malloc but here the allocated space is filled with null characters!*/
x = (char *) calloc(6, sizeof(x));
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* And delete the allocation again... */
free(x);
/* We can set the size at declaration time as well */
char xx[6];
xx[0] = 'H';
xx[1] = 'e';
xx[2] = 'l';
xx[3] = 'l';
xx[4] = 'o';
xx[5] = '\0';
printf("String \"%s\" at address: %d\n", xx, xx);
Обратите внимание, что вы все еще можете использовать переменную x после того, как вы выполнили free () выделенной памяти, но вы не знаете, что там находится. Также обратите внимание, что два printf () могут дать вам разные адреса, поскольку нет гарантии, что второе выделение памяти будет выполнено в том же пространстве, что и первое.
Ваш пример со 120 ошибочен. Он использует% c, а не% s, поэтому ошибки нет; он просто печатает строчную букву x. Более того, ваше последующее утверждение, что указатель имеет тип int, неверно и очень плохой совет для программиста на C, не имеющего опыта работы с указателями.
@R ..% c был изменен на% s
-1 Вы начали хорошо, но первый пример неверный. Нет, это не то же самое. В первом случае a - это указатель, а во втором - a - это массив. Я уже упоминал об этом? Это не одно и то же! Убедитесь сами: сравните sizeof (a), попробуйте присвоить массиву новый адрес. Это не сработает.
«Выполнение этого оператора printf не является неправильным или незаконным». Это совершенно неправильно. Этот оператор printf имеет неопределенное поведение. Во многих реализациях это вызовет нарушение прав доступа. Указатели на самом деле не относятся к типу int, они на самом деле указатели (и ничего больше).
-1, Вы ошиблись здесь, и я просто скажу, что вы не заслуживаете количества голосов или принятого статуса ответа.
Раздел 6 comp.lang.c FAQ очень хорошо объясняет взаимосвязь между массивами и указателями в C. Это не ответ.
«Не надо» -1. Необязательные (нулевые) аргументы. Значения, «необязательно» возвращаемые функциями.
-1 Полиморфизм в C++ требует использование указателей.
@Sildoreth На самом деле это не так. void do_something(Base& x) { x.virtual_method(); } int main() { Derived d; DoSomething(d); } вызывает виртуальные функции без использования указателей. Указатели упрощают обмен, копирование и почти все остальное.
@milleniumbug: boost не является частью C++.
@SigTerm извините, тег C++ в вопросе меня смутил.
@milleniumbug: это необязательная сторонняя библиотека. Если они решат преобразовать :: optional в основной язык, ваш контраргумент может стать действительным.
@milleniumbug Собственно, в вашем примере задействованы указатели являются. '&' - это просто синтаксический сахар, который делает его Посмотрите, как будто вы не используете указатели.
@SigTerm Я читал на isocpp, что он будет частью C++ 14.
@Sildoreth, собственно, нигде не написано, что ссылки реализованы с помощью указателей.
@Jefffrey Если вы не нашли документацию, в которой говорится, что нет, как это работает, я поддерживаю то, что я сказал. Вот так просто работает имеет. Используя ссылки, вы имеете в виду значение, которое потенциально принадлежит другому уровню стека. И его изменение фактически изменяет значение в исходном месте. Именно так работают указатели. Кроме того, эта страница говорит, что значения не копируются при вызове функции. Указатели должен задействованы.
@Sildoreth, стандарт C++ 11 никогда не определяет, как будут реализованы ссылки должен. Это выбор компилятора и ты не должен полагаться на это. Тот факт, что большинство компиляторов реализует это с помощью указателей не имеет ничего общего с определенный, при использовании ссылок задействован указатель.
@ Джефффри Достаточно справедливо. Возможно, хотя и маловероятно, что существует неэффективный компилятор, который копирует значения в параметры, а затем копирует их обратно. В любом случае, суть в том, что вам нужно косвенное обращение к той или иной форме, чтобы использовать полиморфизм подтипов в C++. А переход по ссылке - это форма косвенного обращения.
-1: «Эти декларации одинаковы char* a = "Hello"; char a[] = "Hello";» - черт возьми, нет. Они НЕТ одинаковые.
Это был хороший ответ в 2008 году, но его действительно стоит обновить с помощью std::array и, возможно, строковых представлений.
В java и C# все ссылки на объекты являются указателями, а в C++ у вас больше контроля над тем, куда вы указываете. Помните, что великая сила влечет за собой большую ответственность.
Один из способов использования указателей над переменными - исключить необходимость дублирования памяти. Например, если у вас есть большой сложный объект, вы можете использовать указатель, чтобы указывать на эту переменную для каждой ссылки, которую вы делаете. С переменной нужно дублировать память для каждой копии.
Это причина использовать ссылки (или, самое большее, обертки ссылок), а не указатели.
Для указателей есть много причин. Изменение имен C особенно важно в библиотеках DLL, если вы хотите поддерживать межъязыковую совместимость.
Вот мой ответ, и я не обещаю быть экспертом, но я обнаружил, что указатели отлично подходят для одной из моих библиотек, которую я пытаюсь написать. В этой библиотеке (это графический API с OpenGL :-)) вы можете создать треугольник с переданными в него объектами вершин. Метод рисования берет эти треугольные объекты и ... рисует их на основе созданных мной вершинных объектов. Что ж, все в порядке.
Но что, если я изменю координату вершины? Переместите это или что-то с помощью moveX () в классе вершин? Хорошо, хорошо, теперь мне нужно обновить треугольник, добавление дополнительных методов и производительности тратится зря, потому что мне приходится обновлять треугольник каждый раз, когда перемещается вершина. Все еще не имеет большого значения, но не так уж и хорошо.
Теперь, что, если у меня есть сетка с множеством вершин и множеством треугольников, и эта сетка вращается, перемещается и тому подобное. Мне придется обновить каждый треугольник, который использует эти вершины, и, возможно, каждый треугольник в сцене, потому что я не знаю, какие из них используют какие вершины. Это очень требовательно к компьютеру, и если у меня есть несколько сеток поверх ландшафта, о боже! У меня проблемы, потому что я обновляю каждый треугольник почти в каждом кадре, потому что эти вершины меняются все время!
С указателями вам не нужно обновлять треугольники.
Если бы у меня было три * вершинных объекта на класс треугольника, я не только экономил бы место, потому что у миллиарда треугольников нет трех вершинных объектов, которые сами по себе большие, но также эти указатели всегда будут указывать на вершины, для которых они предназначены, независимо от того, для чего они нужны. как часто меняются вершины. Поскольку указатели по-прежнему указывают на одну и ту же вершину, треугольники не меняются, и процесс обновления легче обрабатывать. Если бы я запутал вас, я бы не сомневался, я не претендую на роль эксперта, просто вкладываю свои два цента в обсуждение.
Необходимость указателей на языке C описана здесь
Основная идея заключается в том, что многие ограничения в языке (например, использование массивов, строк и изменение нескольких переменных в функциях) могут быть сняты, манипулируя местоположением данных в памяти. Чтобы преодолеть эти ограничения, в C.
Кроме того, также видно, что с помощью указателей вы можете быстрее запускать свой код и экономить память в тех случаях, когда вы передаете в функцию большие типы данных (например, структуру с множеством полей). Создание копии таких типов данных перед передачей потребует времени и потребляет память. Это еще одна причина, по которой программисты предпочитают указатели для типов больших данных.
PS: Пожалуйста, обратитесь к ссылка предоставлена для подробного объяснения с образцом кода.
Вопрос о C++, этот ответ о C.
нет, вопрос помечен как c И C++. Возможно, тег c не имеет значения, но он здесь с самого начала.
В C++, если вы хотите использовать подтип полиморфизм, вы имеют используете указатели. Смотрите этот пост: Полиморфизм C++ без указателей.
На самом деле, если подумать, это имеет смысл. Когда вы используете полиморфизм подтипа, в конечном итоге вы не знаете заранее, реализация метода какого класса или подкласса будет вызвана, потому что вы не знаете, что это за класс на самом деле.
Идея наличия переменной, содержащей объект неизвестного класса, несовместима с режимом хранения объектов в стеке по умолчанию (без указателя) C++, где объем выделенного пространства напрямую соответствует классу. Примечание: если в классе 5 полей экземпляров вместо 3, потребуется выделить больше места.
Нет, вы не можете использовать имеют для использования указателей - вы можете использовать ссылки. А когда вы пишете «за кадром задействованы указатели» - это бессмысленно. Инструкции goto также используются негласно - в инструкциях целевой машины. Мы до сих пор не утверждаем, что используем их.
@ einpoklum-reinstateMonica Если у вас есть набор объектов, над которыми вы хотите действовать, присваивая каждый элемент по очереди временной переменной и вызывая полиморфный метод для этой переменной, тогда да, вам НУЖЕН указатель, потому что вы не можете повторно привязать ссылку.
Если у вас есть ссылка базового класса на производный класс и вы вызываете виртуальный метод для этой ссылки, то будет вызвано переопределение производного класса. Я ошибаюсь?
@ einpoklum-reinstateMonica Это верно. Но вы не можете изменить, на какой объект ссылаются. Поэтому, если вы перебираете список / набор / массив этих объектов, ссылочная переменная не будет работать.
Недавно у меня был подобный опыт, за исключением того, что в моем случае у меня был статический метод, подобный фальшивому конструктору, в абстрактном базовом классе, который должен был создавать и возвращать новый объект любого одного из нескольких типов дочерних классов. Не удалось использовать ссылки, потому что они должны быть привязаны к переменной в стеке, и я не могу вернуть ссылку на родительский тип, потому что тогда дочерние методы будут отрезаны (также я не могу передать ссылку на временный, когда все дело в создании объекта новый). Возвращающий указатель на базу это :)
Что касается вашего второго вопроса, обычно вам не нужно использовать указатели при программировании, однако есть одно исключение из этого, а именно, когда вы создаете общедоступный API.
Проблема с конструкциями C++, которые люди обычно используют для замены указателей, очень зависит от набора инструментов, который вы используете, что нормально, когда у вас есть весь необходимый контроль над исходным кодом, однако, если вы скомпилируете статическую библиотеку, например, с Visual Studio 2008 и попробуйте использовать его в Visual Studio 2010, вы получите массу ошибок компоновщика, потому что новый проект связан с более новой версией STL, которая не имеет обратной совместимости. Все становится еще хуже, если вы компилируете DLL и даете библиотеку импорта, которую люди используют в другом наборе инструментов, потому что в этом случае ваша программа рано или поздно выйдет из строя без видимой причины.
Итак, с целью перемещения больших наборов данных из одной библиотеки в другую вы можете рассмотреть возможность предоставления указателя на массив функции, которая должна копировать данные, если вы не хотите заставлять других использовать те же инструменты, которые вы используете. . Хорошая часть этого заключается в том, что это даже не обязательно должен быть массив в стиле C, вы можете использовать std :: vector и указать указатель, указав, например, адрес первого элемента & vector [0], и использовать std :: vector для внутреннего управления массивом.
Еще одна веская причина для использования указателей в C++ снова относится к библиотекам, подумайте о наличии библиотеки DLL, которая не может быть загружена при запуске вашей программы, поэтому, если вы используете библиотеку импорта, зависимость не удовлетворяется и программа дает сбой. Это имеет место, например, когда вы предоставляете публичный api в dll вместе со своим приложением и хотите получить к нему доступ из других приложений. В этом случае, чтобы использовать API, вам необходимо загрузить dll из ее местоположения (обычно это ключ реестра), а затем вам нужно использовать указатель на функцию, чтобы иметь возможность вызывать функции внутри DLL. Иногда люди, которые создают API, достаточно любезны, чтобы предоставить вам файл .h, содержащий вспомогательные функции для автоматизации этого процесса и предоставить вам все необходимые указатели функций, но если нет, вы можете использовать LoadLibrary и GetProcAddress в окнах и dlopen и dlsym в unix, чтобы получить их (учитывая, что вы знаете всю сигнатуру функции).
Позвольте мне попытаться ответить и на это.
Указатели похожи на ссылки. Другими словами, это не копии, а способ сослаться на исходное значение.
Прежде всего, одно место, где вам обычно придется использовать указатели много, - это когда вы имеете дело с со встроенным оборудованием. Возможно, вам нужно переключить состояние цифрового вывода IO. Возможно, вы обрабатываете прерывание и вам нужно сохранить значение в определенном месте. Вы уловили картину. Однако, если вы не имеете дело напрямую с оборудованием и просто задаетесь вопросом, какие типы использовать, читайте дальше.
Зачем использовать указатели вместо обычных переменных? Ответ становится яснее, когда вы имеете дело со сложными типами, такими как классы, структуры и массивы. Если бы вы использовали обычную переменную, вы могли бы сделать копию (компиляторы достаточно умны, чтобы предотвратить это в некоторых ситуациях, и C++ 11 тоже помогает, но мы пока воздержимся от этого обсуждения).
Что произойдет, если вы захотите изменить исходное значение? Вы можете использовать что-то вроде этого:
MyType a; //let's ignore what MyType actually is right now.
a = modify(a);
Это будет работать нормально, и если вы точно не знаете, для чего используете указатели, вам не следует их использовать. Остерегайтесь причины «они, наверное, быстрее». Запустите свои собственные тесты, и если они действительно быстрее, то используйте их.
Однако предположим, что вы решаете проблему, в которой вам нужно выделить память. Когда вы выделяете память, вам нужно освободить ее. Выделение памяти может быть успешным, а может и нет. Вот где пригодится указатели - они позволяют проверить наличие объекта, которые вы выделили, и они позволяют вам получить доступ к объекту, для которого была выделена память, путем отмены ссылки на указатель.
MyType *p = NULL; //empty pointer
if (p)
{
//we never reach here, because the pointer points to nothing
}
//now, let's allocate some memory
p = new MyType[50000];
if (p) //if the memory was allocated, this test will pass
{
//we can do something with our allocated array
for(size_t i=0; i!=50000; i++)
{
MyType &v = *(p+i); //get a reference to the ith object
//do something with it
//...
}
delete[] p; //we're done. de-allocate the memory
}
Это ключ к тому, почему вы должны использовать указатели - ссылки предполагают, что элемент, на который вы ссылаетесь, уже существует. Указатель - нет.
Другая причина, по которой вы должны использовать указатели (или, по крайней мере, в конечном итоге иметь с ними дело), заключается в том, что они являются типом данных, который существовал до ссылок. Поэтому, если вы в конечном итоге используете библиотеки для выполнения тех вещей, которые, как вы знаете, у них лучше, вы обнаружите, что многие из этих библиотек используют указатели повсюду просто из-за того, как долго они существуют (много из них были написаны до C++).
Если бы вы не использовали какие-либо библиотеки, вы могли бы разработать свой код таким образом, чтобы можно было избегать указателей, но, учитывая, что указатели являются одним из основных типов языка, чем быстрее вы освоите их, тем больше переносимы ваши навыки C++.
С точки зрения ремонтопригодности, я должен также упомянуть, что когда вы используете указатели, вам нужно либо проверить их действительность и обработать случай, когда они недействительны, либо просто предположить, что они действительны, и принять тот факт, что ваш программа выйдет из строя или хуже того, КОГДА это предположение нарушится. Другими словами, ваш выбор с указателями - либо усложнить код, либо увеличить усилия по обслуживанию, когда что-то ломается., и вы пытаетесь отследить ошибку, которая принадлежит к целому классу ошибок, которые вводят указатели, например, повреждение памяти.
Поэтому, если вы контролируете весь свой код, держитесь подальше от указателей и вместо этого используйте ссылки, сохраняя их константными, когда это возможно. Это заставит вас задуматься о времени жизни ваших объектов и упростит понимание вашего кода.
Просто запомните эту разницу: Ссылка - это, по сути, действительный указатель. Указатель не всегда действителен.
Я говорю, что создать недействительную ссылку невозможно? Нет. Это вполне возможно, потому что C++ позволяет делать почти все. Просто сделать это непреднамеренно сложнее, и вы удивитесь, сколько ошибок было непреднамеренно :)
Вы можете написать хорошие классы-оболочки для ввода-вывода с отображением в память, с помощью которых можно существенно избежать использования указателей.
Для списка книг см. stackoverflow.com/questions/388242/…. После Java я нашел Ускоренный C++ очень полезным.