popov . dev

Главная

Библиотека

Статьи

Указатели в язык...

Указатели в языке программирования Си

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

Что такое указатели?

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

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

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

Структура объявления указателей в C напоминает синтаксис объявления переменных. Однако в объявлениях указателей мы используем оператор разыменования *.

datatype *ptr;
  • ptr - это выбранное имя для указателя.
  • datatype определяет тип данных, на которые указывает указатель.

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

Давайте разберем ключевые аспекты использования указателей в C:

1. Объявление указателей:

В процессе объявления указателя мы указываем сам указатель, не присваивая ему начального значения. При объявлении используется оператор разыменования * перед именем указателя.

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

Чтобы объявить указатель, используется символ *. Пример:

int *ptr;

При этом объявляется указатель с именем ptr, который может указывать на целое число.

Примечание: существует два способа объявления переменных-указателей в C:

int* ptr;
int *ptr;

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

Инициализация указателя включает в себя присвоение начального значения переменной-указателю. Обычно мы используем оператор address-of & для получения адреса переменной в памяти и последующего сохранения его в переменной-указателе.

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

int x = 10;
int *ptr = &x; // в ptr теперь содержится адрес x

Доступ к значению по адресу (разыменование):

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

int value = *ptr; // значение теперь содержит значение x

3. Арифметика указателей:

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

int arr[5] = {1, 2, 3, 4, 5};
int *arrPtr = arr; // указывает на первый элемент массива

int element = *arrPtr; // доступ к первому элементу
arrPtr++; // переход к следующему элементу

4. Нулевые указатели:

Указателям также может быть присвоено специальное значение NULL, указывающее на то, что они не указывают на какую-либо допустимую ячейку памяти.

int *ptr = NULL; // ptr - это нулевой указатель

5. Указатели и массивы:

Массивы и указатели имеют тесную взаимосвязь в C. Имя массива может использоваться как указатель на его первый элемент.

int arr[3] = {10, 20, 30};
int *arrPtr = arr; // arr и arrPtr эквивалентны

6. Динамическое распределение памяти:

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

int *dynamicArr = (int *)malloc(5 * sizeof(int)); // компьютер резервирует место для массива

Типы указателей

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

1. Указатели на целое число:

Указатели, предназначенные для хранения адресов памяти целочисленных переменных.

int *intPtr;

2. Символьные указатели:

Указатели, специально предназначенные для символьных данных.

char *charPtr;

3. Указатели на значения с плавающей запятой:

Указатели, предназначенные для данных с плавающей запятой (десятичных чисел).

float *floatPtr;

4. Пустые указатели:

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

void *genericPtr;

5. Указатель на указатель (двойной указатель):

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

int **doubleIntPtr;

6. Указатели на массивы:

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

int arr[5];
int *arrPtr = arr;

7. Указатели на функции:

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

int (*functionPtr)(int, int);

8. Нулевые указатели:

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

int *nullPtr = NULL;

9. Дикие (Wild) указатели:

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

data_type * const pointer_name;

10. Постоянные указатели

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

const data_type * pointer_name;

Размер указателей в C

Размер указателей в C остается неизменным для разных типов указателей. На него не влияет тип данных, на которые они указывают; вместо этого он определяется характеристиками операционной системы и архитектуры процессора.

  • 8 байт для 64-разрядной системы
  • 4 байта для 32-разрядной системы

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

Определение размера указателей в C

Чтобы определить размер указателей в C, можно использовать оператор sizeof, как показано в следующей программе:

#include <stdio.h>

int main() {
    int *intPtr;
    char *charPtr;
    float *floatPtr;

    printf("Размер указателя на int: %zu байт\n", sizeof(intPtr));
    printf("Размер указателя на char: %zu байт\n", sizeof(charPtr));
    printf("Размер указателя на float: %zu байт\n", sizeof(floatPtr));

    return 0;
}

Результат работы программы будет зависеть от используемой вами системы и компилятора. Однако, основываясь на распространенных сценариях:

Если вы работаете в 32-разрядной системе:

Размер указателя на int: 4 байт
Размер указателя на char: 4 байт
Размер указателя на float: 4 байт

Если вы работаете в 64-разрядной системе:

Размер указателя на int: 8 байт
Размер указателя на char: 8 байт
Размер указателя на float: 8 байт

Важно отметить, что знак * может быть источником путаницы в нашем коде, поскольку он служит двум различным целям:

  • В объявлениях (например, int* ptr) он обозначает создание переменной-указателя.
  • Помимо объявлений, он функционирует как оператор разыменования

Комментарии

Для того чтобы оставить свое мнение, необходимо зарегистрироваться на сайте