Что такое указатель?
POINTER — это переменная, в которой хранится адрес другой переменной. Указатель также можно использовать для ссылки на другую функцию указателя. Указатель можно увеличивать / уменьшать, т. Е. Указывать на следующую / предыдущую ячейку памяти. Назначение указателя — сэкономить место в памяти и ускорить выполнение.
Как работает указатель?
Если мы объявим переменную v типа int, v фактически сохранит значение.
V теперь равен нулю.
Однако каждая переменная, кроме значения, также имеет свой адрес (или, проще говоря, там, где она находится в памяти). Адрес можно получить, поместив амперсанд (&) перед именем переменной.
Если вы напечатаете адрес переменной на экране, она будет выглядеть как абсолютно случайное число (более того, оно может отличаться от запуска к запуску).
Давайте попробуем это на практике.
Выход этой программы -480613588.
Теперь, что такое указатель? Вместо сохранения значения указатель будет хранить адрес переменной.
Int * y = & v;
ПЕРЕМЕННЫЕ |
УКАЗАТЕЛЬ |
Значение сохраняется в имени хранение / адрес памяти |
Переменная , что указывает на адрес хранения / памяти другой переменной |
Объявление указателя
Как и переменные, указатели должны быть объявлены до того, как они могут быть использованы в вашей программе. Указатели могут быть названы как угодно, если они подчиняются правилам именования Си. Объявление указателя имеет следующую форму.
data_type * pointer_variable_name;
Вот,
- data_type является базовым типом указателя типов переменных C и указывает тип переменной, на которую указывает указатель.
- Звездочка (*: та же, что и для умножения звездочка), являющаяся оператором косвенности, объявляет указатель.
Давайте посмотрим некоторые правильные объявления указателя
int *ptr_thing; /* pointer to an integer */ int *ptr1,thing;/* ptr1 is a pointer to type integer and thing is an integer variable */ double *ptr2; /* pointer to a double */ float *ptr3; /* pointer to a float */ char *ch1 ; /* pointer to a character */ float *ptr, variable;/*ptr is a pointer to type float and variable is an ordinary float variable */
Инициализировать указатель
После объявления указателя мы инициализируем его как стандартные переменные с адресом переменной. Если указатели не инициализированы и не используются в программе, результаты непредсказуемы и могут привести к катастрофическим последствиям.
Чтобы получить адрес переменной, мы используем оператор амперсанда (&), помещенный перед именем переменной, адрес которой нам нужен. Инициализация указателя выполняется с использованием следующего синтаксиса.
pointer = &variable;
Простая программа для иллюстрации указателя приведена ниже:
#include <stdio.h> int main() { int a=10; //variable declaration int *p; //pointer variable declaration p=&a; //store address of variable a in pointer p printf("Address stored in a variable p is:%x\n",p); //accessing the address printf("Value stored in a variable p is:%d\n",*p); //accessing the value return 0; }
Вывод:
Address stored in a variable p is:60ff08 Value stored in a variable p is:10
оператор | Смысл |
* | Служит 2 цели
|
& | Служит только 1 цели
|
Типы указателя
Нулевой указатель
Мы можем создать нулевой указатель, назначив нулевое значение во время объявления указателя. Этот метод полезен, когда у вас нет адреса, назначенного указателю. Пустой указатель всегда содержит значение 0.
Следующая программа иллюстрирует использование нулевого указателя:
#include <stdio.h> int main() { int *p = NULL; //null pointer printf(“The value inside variable p is:\n%x”,p); return 0; }
Вывод:
The value inside variable p is: 0
Пустой указатель
В C-программировании указатель void также называется универсальным указателем. У него нет стандартного типа данных. Указатель void создается с использованием ключевого слова void. Может использоваться для хранения адреса любой переменной.
Следующая программа иллюстрирует использование пустого указателя:
#include <stdio.h> int main() { void *p = NULL; //void pointer printf("The size of pointer is:%d\n",sizeof(p)); return 0; }
Вывод:
The size of pointer is:4
Дикий указатель
Указатель называется диким указателем, если он ни к чему не инициализируется. Эти типы указателей неэффективны, потому что они могут указывать на какое-то неизвестное место в памяти, которое может вызвать проблемы в нашей программе и может привести к сбою программы. Нужно всегда быть осторожным при работе с дикими указателями.
Следующая программа иллюстрирует использование дикого указателя:
#include <stdio.h> int main() { int *p; //wild pointer printf("\n%d",*p); return 0; }
Вывод
timeout: the monitored command dumped core sh: line 1: 95298 Segmentation fault timeout 10s main
Другие типы указателей в ‘c’ следующие:
- Свисающий указатель
- Сложный указатель
- Ближний указатель
- Дальний указатель
- Огромный указатель
Указатели прямого и косвенного доступа
В C есть два эквивалентных способа доступа и управления переменным содержимым
- Прямой доступ: мы используем непосредственно имя переменной
- Косвенный доступ: мы используем указатель на переменную
Давайте разберемся с помощью программы ниже
#include <stdio.h> /* Declare and initialize an int variable */ int var = 1; /* Declare a pointer to int */ int *ptr; int main( void ) { /* Initialize ptr to point to var */ ptr = &var; /* Access var directly and indirectly */ printf("\nDirect access, var = %d", var); printf("\nIndirect access, var = %d", *ptr); /* Display the address of var two ways */ printf("\n\nThe address of var = %d", &var); printf("\nThe address of var = %d\n", ptr); /*change the content of var through the pointer*/ *ptr=48; printf("\nIndirect access, var = %d", *ptr); return 0;}
После компиляции программы без каких-либо ошибок, результат:
Direct access, var = 1 Indirect access, var = 1 The address of var = 4202496 The address of var = 4202496 Indirect access, var = 48
Арифметика указателей
Операции с указателями сведены на следующем рисунке
Приоритетная операция (приоритет)
При работе с указателями мы должны соблюдать следующие правила приоритета:
- Операторы * и & имеют тот же приоритет, что и унарные операторы (отрицание !, увеличение ++, уменьшение—).
- В том же выражении унарные операторы *, &,!, ++, — оцениваются справа налево.
Если указатель P указывает на переменную X, тогда * P можно использовать везде, где можно записать X.
Следующие выражения эквивалентны:
int X = 10
int * P = & Y; Для приведенного выше кода ниже выражения являются истинными |
|
выражение | Эквивалентное выражение |
Y = * P + 1
* P = * P + 10 * P + = 2 ++ * P (* P) ++ |
Y = X + 1
X = X + 10 X + = 2 ++ X X ++ |
В последнем случае необходимы скобки: поскольку унарные операторы * и ++ вычисляются справа налево, без скобок будет увеличиваться указатель P, а не объект, на который указывает P.
В таблице ниже приведены основные арифметические операции, которые можно использовать при работе с указателями.
операция | объяснение |
присваивание | int * P1, * P2 P1 = P2; P1 и P2 указывают на одну и ту же целочисленную переменную |
Увеличение и уменьшение | Int * P1; P1 ++; P1—; |
Добавление смещения (константа) | Это позволяет указателю перемещать N элементов в таблице. Указатель будет увеличен или уменьшен в N раз на количество байтов типа переменной. P1 + 5; |
Указатели и массивы
Традиционно мы обращаемся к элементам массива, используя его индекс, но этот метод можно устранить с помощью указателей. Указатели облегчают доступ к каждому элементу массива.
#include <stdio.h> int main() { int a[5]={1,2,3,4,5}; //array initialization int *p; //pointer declaration /*the ptr points to the first element of the array*/ p=a; /*We can also type simply ptr==&a[0] */ printf("Printing the array elements using pointer\n"); for(int i=0;i<5;i++) //loop for traversing array elements { printf("\n%x",*p); //printing array elements p++; //incrementing to the next element, you can also write p=p+1 } return 0; }
Вывод
1 2 3 4 5
Добавление определенного числа к указателю переместит местоположение указателя на значение, полученное с помощью операции сложения. Предположим, что p является указателем, который в данный момент указывает на ячейку памяти 0, если мы выполним следующую операцию сложения, p + 1, то она будет выполняться следующим образом:
Поскольку p в настоящее время указывает на местоположение 0 после добавления 1, значение станет 1, и, следовательно, указатель будет указывать на ячейку памяти 1.
Указатели и Строки
Строка — это массив объектов char, заканчивающийся нулевым символом ‘\ 0’. Мы можем манипулировать строками, используя указатели. Вот пример, который объясняет этот раздел
#include <stdio.h> #include <string.h> int main() { char str[]="Hello Guru99!"; char *p; p=str; printf("First character is:%c\n",*p); p =p+1; printf("Next character is:%c\n",*p); printf("Printing all the characters in a string\n"); p=str; //reset the pointer for(int i=0;i<strlen(str);i++) { printf("%c\n",*p); p++; } return 0; }
Вывод
First character is:H Next character is:e Printing all the characters in a string H e l l o G u r u 9 9 !
Другой способ работы со строками — использовать массив указателей, как в следующей программе:
#include <stdio.h> int main(){ char *materials[ ] = { "iron", "copper", "gold"}; printf("Please remember these materials :\n"); int i ; for (i = 0; i < 3; i++) { printf("%s\n", materials[ i ]);} return 0;}
Вывод:
Please remember these materials: iron copper gold
Преимущества указателей
- Указатели полезны для доступа к ячейкам памяти.
- Указатели обеспечивают эффективный способ доступа к элементам структуры массива.
- Указатели используются для динамического выделения памяти, а также освобождения.
- Указатели используются для формирования сложных структур данных, таких как связанный список, график, дерево и т. Д.
Недостатки указателей
- Указатели немного сложны для понимания.
- Указатели могут привести к различным ошибкам, таким как ошибки сегментации, или могут получить доступ к области памяти, которая вообще не требуется.
- Если для указателя указано неверное значение, это может привести к повреждению памяти.
- Указатели также несут ответственность за утечку памяти.
- Указатели сравнительно медленнее, чем у переменных.
- Программистам очень трудно работать с указателями; поэтому программист обязан аккуратно манипулировать указателем.
Резюме
- Указатель — это не что иное, как область памяти, где хранятся данные.
- Указатель используется для доступа к ячейке памяти.
- Существуют различные типы указателей, такие как пустой указатель, дикий указатель, пустой указатель и другие типы указателей.
- Указатели могут использоваться с массивом и строкой для более эффективного доступа к элементам.
- Мы можем создать указатели на функции для динамического вызова функции.
- Арифметические операции могут быть выполнены с указателем, который известен как арифметика указателя.
- Указатели также могут указывать на функцию, которая облегчает вызов различных функций в случае определения массива указателей.
- Если вы хотите использовать другой тип данных переменной, вы можете использовать указатель типа void.