Перейти к содержимому

Как инициализировать указатель c

  • автор:

Как правильно инициализировать указатель?

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

guest *temp = (guest*)malloc(sizeof(guest)); tesst->next = temp; temp->name = cur_guest->name; temp->adris = cur_guest->adris; temp->birthyear = cur_guest->birthyear; temp->next = NULL; 

введите сюда описание изображения

что не так делаю? При сборке ошибку не выдает. Ошибка вылезает непосредственно при отладке. Пишет вот так:

Отслеживать
123k 24 24 золотых знака 126 126 серебряных знаков 303 303 бронзовых знака
задан 19 мар 2021 в 10:42
135 8 8 бронзовых знаков

«Только не это, шеф! Только не это!» Не выделяйте память сложному классу с конструктором через malloc ! Только через new ! И вообще, в С++ — забудьте о malloc вообще!!

19 мар 2021 в 10:47

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

При выделении через malloc вы просто получаете неинициализированную память. Конструктор не вызывается, все ваши string на самом деле никакие не строки, а просто кусок памяти того же размера с мусором.

В С++ используйте new , только new ! Никаких malloc — по крайней мере пока не научитесь точно понимать, что и как работает (это для тех, кто сейчас начнет рассказывать о placement new).

Вся инициализация полей должна идти через конструктор, который автоматически вызывается при использовании new . И вообще, делая поля открытыми, вы фактически отвергаете одного из китов ООП — инкапсуляцию.

Указатели и ссылки в языке C++

Указатели представляют собой объекты, значением которых служат адреса других объектов:

  • переменных
  • констант
  • функций
  • других указателей
Объявление указателей

<тип> *<имя_переменной>[,*<имя_переменной>].

Синтаксис объявления указателей аналогичен объявлению переменных, за исключением того, что между типом данных и именем переменной должен быть указан символ «*» («звездочка»).

Инициализация указателей

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

Указателю нельзя присвоить адрес переменной другого типа. То есть нельзя указателю типа int* присвоить адрес переменной типа double.

Также указателю можно присвоить значение другого указателя.

Указатель также может быть проинициализирован пустым значением. Это можно сделать несколькими способами:

  • использовать значение 0 или макроопределение NULL
  • использовать значение nullptr
  • использовать значение std::nullptr_t (C++ 11)

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

Тип std::nullptr_t может иметь только одно значение — nullptr. Использование этого типа поможет в тех редких случаях, когда существуют перегруженные функции и требуется передать нулевой указатель. В этом случае непонятно какую именно функцию нужно будет вызвать. Поэтому в таком случае в функции можно задать аргумент с типом std::nullptr_t.

Напрямую записать адрес в указатель можно только с помощью операций преобразования типов, либо операции reinterpret_cast.

int a = 0; int *p = &a; double v = 0.1; double *pv = &v; char *pc = nullptr;
Разыменование указателей

Для получения значения переменной, на которую ссылается указатель, используется операция разыменования указателя. Эта операция записывается как символ * (звездочка), написанный перед указателем.

int a = 123; int *p = &a; int b = *p; // b присваивается значение 123
Арифметические действия с указателями

С указателем можно производить следующие арифметические действия:

  • сложение и вычитание с целым числом
  • операции инкремента/декремента

При использовании арифметических операций, указатель изменяется на величину кратную размеру типа указателя. Например, если указатель имеет тип 32-разрядного int, то увеличение указателя на 1 приведет к увеличению значения адреса в указателе на 4.

Указатель на указатель

В языке C++ можно объявить указатель, который будет указывать на другой указатель.

Синтаксис объявления такой же, как и у объявления указателя, за исключением того, что ставится два символа * (звездочка).

<тип> **<имя_переменной>[,**<имя_переменной>].

Указатель на указатель работает подобно обычному указателю: его можно разыменовать для получения значения, на которое он указывает. И, поскольку этим значением является другой указатель, для получения исходного значения потребуется выполнить разыменование еще раз. Разыменования можно выполнять последовательно:

int value = 1234; int *p = &value; int **pp = &p; int val = **pp; // 1234

Использовать указатели на указатели может потребоваться, например для создания массива из массивов, и в частности массива из строк.

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

Неконстантный указатель на неконстантное значение

int val1 = 10; int val2 = 20; int* ptr = &val1; std::cout 

В этом случае можно изменять как сам указатель, так и значение, на которое он указывает.

Неконстантный указатель на константное значение

const int val1 = 10; const int val2 = 20; const int* ptr = &val1; std::cout 

В этом случае указатель можно изменять. Но само значение, на которое он указывает изменять нельзя.

То же самое поведение можно получить, даже если переменные указаны как неконстантные. Для этого достаточно сам указатель объявить таким образом, чтобы он якобы указывал на константное значение:

int val1 = 10; int val2 = 20; const int* ptr = &val1; std::cout 

Константный указатель на неконстантное значение

int val1 = 10; int val2 = 20; int* const ptr = &val1; std::cout 

В этом случае можно изменять значение, на которое указывает указатель. Но нельзя изменять сам указатель.

Кроме того указатель при объявлении нужно сразу инициализировать.

Константный указатель на константное значение

int val1 = 10; int val2 = 20; const int* const ptr = &val1; std::cout 

В этом случае нельзя менять ни указатель, ни значение, на которое он указывает.

Ссылки

Ссылка - это тип переменной в языке C++, который работает как псевдоним другого объекта или значения. При объявлении ссылки перед её именем ставится символ амперсанда &. Сама же ссылка не может быть пустой, и должна быть обязательно проинициализирована именем переменной, на которую она ссылается. Изменить значение ссылки после инициализации невозможно.

<тип> &<имя_ссылки> = <имя_переменной>[, &<имя_ссылки> = <имя_переменной>].

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

Любые действия со ссылкой трактуются компилятором как действия, которые будут выполняться над объектом, на который она ссылается.

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

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

int value = 123; int &refval = value; refval = 12345; std::cout 
Ссылки r-value

В стандарте C++11 ввели новый тип ссылок - ссылки r-value. Ссылки r-value - это ссылки, которые инициализируются только значениями r-values. Объявляются такие ссылки, в отличие от обычных, с помощью двух символов амперсанда &&.

<тип> &&<имя_ссылки> = <выражение r-value>[, &&<имя_ссылки> = <выражение r-value>].

Ссылки r-value, в отличие от обычных ссылок, ссылаются не на постоянный, а на временный объект, созданный при инициализации ссылки r-value.

Такие ссылки обладают двумя важными свойствами:

  • продолжительность жизни объекта, на который ссылается ссылка увеличивается до продолжительности жизни самой ссылки
  • неконстантные ссылки r-value позволяют менять значение r-values, на который они ссылаются
int &&ref = 10; ref = ref + 20; std::cout 

Ссылки r-value - позволяют избегать логически ненужного копирования и обеспечивать возможность идеальной передачи (perfect forwarding). Прежде всего они предназначены для использования в высокопроизводительных проектах и библиотеках.

  • Уголок в Вконтакте
  • Уголок в Телеграм
  • Уголок в YouTube

Инициализация указателей

Как и другие переменные, помимо объявления, указатели требуют инициализации, так как в противном случае они содержат непредсказуемые значения. Существуют следующие способы инициализации указателя:

  • присваивание указателю адреса существующего объекта (переменной, массива и др.) с помощью операции адреса (&):
  • присваивание указателю пустого значения:
  • с помощью значения другого инициализирующего указателя:
  • c помощью имени массива:
  • присваивание адреса динамической памяти:

Адресная арифметика

  1. Операция адреса
  1. Операция присваивания
  1. Операция разыменования
  1. Увеличение/уменьшение указателя
  1. Вычитание указателей
  1. Операции сравнения
  1. Операцияsizeof
  1. Недопустимые операции
  • сложение двух указателей;
  • вычитание двух указателей на данные различных типов;
  • сложение/вычитание указателей с числом с плавающей точкой;
  • умножение/деление указателей;
  • поразрядные операции и операции сдвига.

Как инициализировать указатель c

Указатели поддерживают ряд операций: присваивание, получение адреса указателя, получение значения по указателю, некоторые арифметические операции и операции сравнения.

Присваивание адреса

Указателю можно присвоить адрес объекта того же типа, либо значение другого указателя. Для получения адреса объекта используется операция & :

int a ; int *pa ; // указатель pa хранит адрес переменной a

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

Разыменование указателя

Операция разыменования указателя представляет выражение в виде *имя_указателя . Эта операция позволяет получить объект по адресу, который хранится в указателе.

#include int main() < int a ; int *pa ; // хранит адрес переменной a std::cout #include int main() < int a ; int b ; int *pa ; // указатель на переменную a int *pb ; // указатель на переменную b std::cout pa: address=0x56347ffc5c value=10 pb: address=0x56347ffc58 value=2 pa: address=0x56347ffc58 value=2 b value=125

Нулевые указатели

Нулевой указатель (null pointer) - это указатель, который не указывает ни на какой объект. Если мы не хотим, чтобы указатель указывал на какой-то конкретный адрес, то можно присвоить ему условное нулевое значение. Для определения нулевого указателя можно инициализировать указатель нулем или константой nullptr :

int *p1; int *p2<>;

Ссылки на указатели

Так как ссылка не является объектом, то нельзя определить указатель на ссылку, однако можно определить ссылку на указатель. Через подобную ссылку можно изменять значение, на которое указывает указатель или изменять адрес самого указателя:

#include int main() < int a ; int b ; int *p<>; // указатель int *&pRef

; // ссылка на указатель pRef = &a; // через ссылку указателю p присваивается адрес переменной a std::cout &:

int a ; int *pa ; std::cout >, >=, , ,==, !=. Операции сравнения применяются только к указателям одного типа. Для сравнения используются номера адресов:

#include int main() < int a ; int b ; int *pa ; int *pb ; if(pa > pb) std::cout

Консольный вывод в моем случае:

pa (0xa9da5ffdac) is greater than pb (0xa9da5ffda8)

Приведение типов

Иногда требуется присвоить указателю одного типа значение указателя другого типа. В этом случае следует выполнить операцию приведения типов с помощью операции (тип_указателя *) :

#include int main() < char c ; char *pc ; // указатель на символ int *pd <(int *)pc>; // указатель на int void *pv ; // указатель на void std::cout std::cout

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *