Освоение указателей в C: практическое руководство от экспертов
Освоение указателей в C
Изучите основные концепции указателей в C: от адресов памяти до практических примеров и распространенных ошибок. Руководство для разработчиков, желающих углубить понимание с реальным кодом.
Указатели — краеугольный камень эффективного программирования на C. Прежде чем погрузиться в указатели, давайте вспомним, как работают адреса памяти в C.
Адреса памяти в C
Если у вас есть переменная var, выражение &var возвращает адрес, где хранится var.
Манипуляции с адресами часто встречаются, например, в scanf():
scanf("%d", &var);
Это сохраняет ввод пользователя непосредственно в ячейку памяти переменной var. Короткая демонстрация:
#include <stdio.h>
int main() {
int var = 5;
printf("var: %d\n", var);
printf("address of var: %p", &var);
return 0;
}
Вывод
var: 5 address of var: 0x7fffc1a2b1c8
Примечание: Адрес будет отличаться при каждом запуске и на каждой системе.
Что такое указатель?
Указатель — это переменная, которая хранит адрес памяти, а не обычное значение. Храня адреса, указатели обеспечивают косвенный доступ к данным, позволяя управлять динамической памятью, создавать эффективные структуры данных и осуществлять низкоуровневый системный контроль.
Объявление указателей
Типичный синтаксис объявления:
int *p;
Также встречаются вариации:
int *p1; int *p2;
Пробелы вокруг звездочки не влияют на объявление. Однако будьте осторожны с разделением запятыми:
int *p1, p2; /* p1 — указатель, p2 — int */
Присваивание адресов указателям
Пример:
int *pc, c;
c = 5;
pc = &c;
Здесь c получает значение 5, а pc сохраняет адрес c.
Разыменование указателей
Чтобы получить значение, хранящееся по адресу, на который указывает указатель, используйте оператор разыменования *:
int *pc, c;
c = 5;
pc = &c;
printf("%d", *pc); /* Выводит 5 */
Помните: pc — это указатель; *pc извлекает значение, на которое он указывает. Попытка присвоить адрес *pc (например, *pc = &c;) недопустима.
Оператор * называется оператором разыменования.
Изменение значений через указатели
Вы можете изменить базовые данные через их указатель:
int *pc, c;
c = 5;
pc = &c;
*pc = 1; /* c становится 1 */
printf("%d", c); /* Выводит 1 */
Несколько переменных могут использовать один и тот же указатель после переназначения:
int *pc, c, d;
c = 5;
d = -15;
pc = &c;
printf("%d", *pc); /* 5 */
pc = &d;
printf("%d", *pc); /* -15 */
Практический пример
Запустите эту полную программу, чтобы наблюдать, как значения указателей остаются постоянными, а данные, на которые они ссылаются, могут меняться:
#include <stdio.h>
int main() {
int *pc, c;
c = 22;
printf("Address of c: %p\n", &c);
printf("Value of c: %d\n\n", c);
pc = &c;
printf("Address of pointer pc: %p\n", pc);
printf("Content of pointer pc: %d\n\n", *pc);
c = 11;
printf("Address of pointer pc: %p\n", pc);
printf("Content of pointer pc: %d\n\n", *pc);
*pc = 2;
printf("Address of c: %p\n", &c);
printf("Value of c: %d\n\n", c);
return 0;
}
Вывод
Address of c: 0x7fffc1a2b1c8 Value of c: 22 Address of pointer pc: 0x7fffc1a2b1c8 Content of pointer pc: 22 Address of pointer pc: 0x7fffc1a2b1c8 Content of pointer pc: 11 Address of c: 0x7fffc1a2b1c8 Value of c: 2
Пояснение
int *pc, c;— объявляет указатель pc и int c.c = 22;— сохраняет 22 в памяти c.pc = &c;— указывает pc на c.c = 11;— обновляет значение через прямой доступ.*pc = 2;— меняет значение через указатель.
Распространенные ошибки с указателями
Типичные ошибки включают путаницу между указателями и значениями:
int c, *pc;
// Неверно — присваивание значения указателю
pc = c; // Ошибка
// Неверно — попытка присвоить адрес разыменованному указателю
*pc = &c; // Ошибка
// Верно — присваивание адреса указателю
pc = &c; // OK
// Верно — присваивание значения по адресу, на который указывает указатель
*pc = c; // OK
Для новичков синтаксис int *p = &c; может быть запутан. Он эквивалентен:
int *p;
p = &c;
Запись int* p = &c; уменьшает неопределенность.
Теперь, когда вы понимаете указатели, вы будете готовы изучить их отношения с массивами в следующем уроке.
Язык C
- C# Hello World — создание вашего первого C# приложения
- Понимание ключевых слов и идентификаторов C#: правила, списки и лучшие практики
- Мастерство C# переменных и примитивных типов данных: полное руководство
- Операторы C# — исчерпывающее руководство по операторам в C#
- Освоение побитовых и сдвиговых операторов в C#: полное руководство
- Основы ввода-вывода в C#: Console.WriteLine, ReadLine и форматирование
- Выражения, операторы и блоки в C#: подробное руководство с примерами
- Освоение комментариев в C#: виды, лучшие практики и XML-документация
- Освоение указателей в C: практическое руководство от экспертов
- Понимание взаимосвязи между массивами и указателями в C