Что является значением переменной указателя

Что является значением переменной указателя

Указатель (англ. pointer ) — переменная, диапазон значений которой состоит из адресов ячеек памяти или специального значения — нулевого адреса. Последнее используется для указания того, что в данный момент указатель не ссылается ни на одну из допустимых ячеек.

Содержание

Область применения [ править | править код ]

Указатели применяются в двух сферах:

  • Работа в системе косвенной адресации (как в языках ассемблера). Одним из её преимуществ можно назвать экономию памяти. Делая указатель на файл, мы читаем его с диска, а не загружаем в ОЗУ. Передавая указатель на переменную в функцию мы не делаем копию этой переменной, а редактируем её напрямую [1] . Указатели используют для хранения адресов точек входа для так называемых подпрограмм в процедурном программировании и для подключения динамических подключаемых библиотек.
  • Динамическое управление памятью. В таком случае выделяется место в так называемой куче (динамической памяти), а переменные, для которых память выделена таким образом, называются динамическими [2] . В языке Си нет понятия строковой переменной, так что для строк часто используют указатель на массив символов.

Действия над указателями [ править | править код ]

Языки программирования, в которых предусмотрен тип указателей, содержат, как правило, две основные операции над ними: присваивание и разыменование. Первая присваивает указателю некоторый адрес. Вторая служит для обращения к значению в памяти, на которое указывает указатель. Разыменование может быть явным и неявным; в большинстве современных языков программирования разыменование происходит только при явном указании [ чего? ] [ источник не указан 1200 дней ] .

Пример работы с указателями в языке Си:

Унарный оператор & возвращает адрес переменной, а оператор * используется для разыменования:

В случае, если указатель хранит адрес какого-либо объекта, то говорят, что указатель ссылается или указывает на этот объект.

Языки, предусматривающие использование указателей для динамического распределения памяти, должны содержать оператор явного размещения переменных в памяти. В некоторых языках помимо этого оператора предусмотрен ещё и оператор явного удаления переменных из памяти. Обе эти операции часто принимают форму встроенных подпрограмм (функции malloc и free в Си, операторы new и delete в C++ и т. п.). При использовании простого, а не умного указателя следует всегда своевременно удалять переменную из памяти, дабы избежать утечки памяти.

Указатель на void [ править | править код ]

Указатель на тип void позволяет сослаться на любой тип данных, в том числе класс. Эта технология лежит в основе типа any библиотеки Boost.

Указатель на указатель [ править | править код ]

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

Читайте также:  Работа с портами в linux

Нулевой указатель [ править | править код ]

Нулевой указатель — это указатель, хранящий специальное значение, показывающее, что данная переменная-указатель не ссылается (не указывает) ни на какой объект. В языках программирования он представлен особой константой [3] :

  • в C# и Java: null;
  • в Visual Basic .NET: Nothing;
  • в Си и C++: 0 или макрос NULL; в стандарте C++11 для обозначения нулевого указателя предложено новое ключевое слово nullptr [4] ;
  • в Паскале и Ruby: nil;
  • в Компонентном Паскале:NIL;

Основные проблемы применения [ править | править код ]

Указателями сложно управлять. Достаточно легко записать в указатель неправильное значение, что может вызвать трудновоспроизводимую ошибку. Например, вы случайно поменяли адрес указателя в памяти, или неправильно выделили под информацию память и тут вас может ожидать сюрприз: другая очень важная переменная, которая используется только внутри программы будет перезаписана. Понять, где именно находится ошибка и воспроизвести её будет нелегко, а устранение таких ошибок — не всегда тривиальная задача, иногда приходится переписывать существенную часть программы [5] .

Для решения части проблем есть методы предохранения и страховки:

Инициализируйте указатели [ править | править код ]

Пример ошибки с неинициализированным указателем:

В такой маленькой программе проблема может остаться незамеченной. Но, когда программа разрастется, то внезапно может выясниться, что переменная записана между других блоков данных, важных для программы. Чтобы избежать такой ситуации, просто инициализируйте указатель [5] .

Используйте указатели правильно [ править | править код ]

Неправильное использование указателя:

Вызов printf() не выводит значения х , которое равно 10, на экран. Вместо этого выводится некоторое неизвестное значение — это результат неправильного использования оператора присваивания ( р = х; ). Этот оператор присваивает значение 10 указателю р , который должен содержать адрес, а не значение. К счастью, ошибка в данной программе обнаруживается компилятором — он выдаёт предупреждение о необычном преобразовании указателя. Для устранения ошибки следует написать p = &х; [5] .

Правильное использование указателя [ править | править код ]

  • старайтесь инициализировать переменные сразу при объявлении ( int x = 10; );
  • не смешивайте указатели с обычными переменными (например, int x, *p, y, *y_ptr; );

Утечка памяти [ править | править код ]

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

Читайте также:  Insomnia the ark лагает

Сравнение указателей [ править | править код ]

Адреса в памяти, присвоенные указателям, можно сравнивать. Сравнения вида pNum1 и pNum1 > pNum2 часто используются для последовательного перебора элементов массива в цикле: pNum1 соответствует текущему положению в памяти, а pNum2 — концу массива. pNum1 == pNum2 вернёт истину в том случае, если оба указателя указывают на одну ячейку памяти.

Адресная арифметика [ править | править код ]

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

Типичные операции адресной арифметики:

Умный указатель [ править | править код ]

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

Указатель в биологии человека [ править | править код ]

Мозг использует группы клеток, похожие на указатели, для решения некоторых задач, связанных с запоминанием новой информации [6] .

Указатель — переменная, содержащая адрес объекта. Указатель не несет информации о содержимом объекта, а содержит сведения о том, где размещен объект.

Указатели широко используются в программировании на языке Си.
Указатели часто используются при работе с массивами.

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

Каждая переменная в памяти имеет свой адрес — номер первой ячейки, где она расположена, а также свое значение. Указатель — это тоже переменная, которая размещается в памяти. Она тоже имеет адрес, а ее значение является адресом некоторой другой переменной. Переменная, объявленная как указатель, занимает 4 байта в оперативной памяти (в случае 32-битной версии компилятора).

Указатель, как и любая переменная, должен быть объявлен.
Общая форма объявления указателя

Тип указателя — это тип переменной, адрес которой он содержит.

Для работы с указателями в Си определены две операции:

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


Для указанного примера обращение к одним и тем же значениям переменной и адреса представлено в таблице

Переменная Указатель
Адрес &c p
Значение c *p

Расположение в памяти переменной a и указателя b:

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

/Рабочий стол/CodeC$ gcc pointers.c -o pointers.exe pointers.c: In function ‘main’: pointers.c:12:62: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=] printf("
Адрес переменной a равен %x шестн.", &a);

Читайте также:  Водительские права по временной регистрации

%ls pointers.c:14:66: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int *’ [-Wformat=] printf("
Значение указателя 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("
Адрес расположения указателя b равен %x шестн.", &b);

#include
#include
#include

void helloWorld (GtkWidget *wid, GtkWidget *win)
<
GtkW >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[])
<
GtkW >NULL ;
GtkW >NULL ;
GtkW >NULL ;

/* Initialize GTK+ */
g_log_set_handler ( "Gtk" , G_LOG_LEVEL_WARNING, (GLogFunc) gtk_false, NULL );
gtk_init (&argc, &argv);
g_log_set_handler ( "Gtk" , G_LOG_LEVEL_WARNING, g_log_default_handler, NULL );

/* Create the main window */
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width (GTK_CONTAINER (win), 8);
gtk_window_set_default_size (GTK_WINDOW (win), 400, 200);
gtk_window_set_title (GTK_WINDOW (win), "Hello World" );
gtk_window_set_position (GTK_WINDOW (win), GTK_WIN_POS_CENTER);
gtk_widget_realize (win);
g_signal_connect (win, "destroy" , gtk_main_quit, NULL );

/* Create a vertical box with buttons */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_container_add (GTK_CONTAINER (win), vbox);

button = gtk_button_new_from_stock (GTK_STOCK_DIALOG_INFO);
g_signal_connect (G_OBJECT (button), "clicked" , G_CALLBACK (helloWorld), (gpointer) win);
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);

button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
g_signal_connect (button, "clicked" , gtk_main_quit, NULL );
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);

/* Enter the main loop */
gtk_widget_show_all (win);
gtk_main ();
return 0;
>

Оперативная память состоит из ячеек имя—>значение, и можно представить так (все значения идут в hex):

Когда ты пишешь к примеру:
int a = 10;
То в программе это будет выглядеть например как:
адрес (0000 0001) = значение (0A);

Конечно по хорошему int содержит 4 байта и выглядит так: первый_адрес (0000 0001) = значение (0A 00 00 00); Но для наглядности я этим пренебрегу.

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

int a = 5, b; // создали две переменные.. .
int * ptr; // . и указатель
ptr = &a; // взяли адрес переменной a
b = *ptr; // занесли в переменную b, данные по указателю ptr
// теперь a и b равны, а по указателю ptr хранится только адрес первого байта переменной a

Ссылка на основную публикацию
Adblock detector