C/C++ · 9 min read · Oct 11, 2025
Изучение C/C++ шаг за шагом - Страница 9
09. Шаг за Шагом C/C++ — Программирование на C - Указатели
Указатели
| | 1. О памяти
- Схема адресации
- Как найти адрес переменной
- Указатели
- Арифметика указателей
- Указатели и массивы
- Указатели и строки
- Глоссарий |
1. О памяти
Компьютер имеет возможность хранить данные и манипулировать ими. Хранение данных требует устройства хранения, которое удобно для быстрого и точного хранения и извлечения данных без путаницы. Обычно компьютер должен идти на компромисс с двумя методами хранения.
| | |
SRAM Статическая оперативная память
DRAM Динамическая оперативная память
EEPROM Электрически стираемая программируемая память только для чтения
Чипы памяти могут хранить данные, инструкции и промежуточные и конечные результаты. Память организована в байты, каждый байт способен хранить один символ информации. Каждый байт памяти имеет адрес или номер местоположения, который уникально его идентифицирует. Размер памяти измеряется либо в килобайтах (КБ), мегабайтах (Мб), гигабайтах или терабайтах (ТБ).
ОЗУ:
Устройство памяти - это место хранения для хранения информации.
Жизненно важный ресурс компьютера, память выделяется каждой переменной после их объявления в C-программе. Тип переменной определяет количество байтов памяти, которое будет выделено для каждой переменной.
| |
|
2. Схема адресации
| |
|
Вышеуказанная картинка сообщает вам следующую информацию.
| | 1. ОЗУ - это временная память и часть компьютера.
- Она может хранить значение программы.
- Каждый байт в ОЗУ идентифицируется уникальным положительным номером, называемым адресом.
- Адреса представлены как числа, так же как и номера домов на улице.
- Номер начинается с 0 и увеличивается оттуда 1-2-3 и так далее.
- Если у нас есть 640 КБ памяти, то самый высокий адрес - 655,359, для 1 МБ памяти - 1,048,575.
- Наша программа, когда она загружается в память, занимает определенный диапазон этих адресов.
- Это означает, что каждая переменная и каждая функция в нашей программе начинается с определенного адреса. |
3. Как найти адрес переменной
В последнем разделе пункт 8 говорит о том, что каждая переменная/функция начинается с определенного адреса. Адреса - это уникальные положительные числа в шестнадцатеричном формате.
Найти адрес переменной - это простая задача с помощью оператора & ( адрес ).
& ( адрес ) - Он может сообщить вам адрес переменной / функции в текущей программе.
Следующая программа демонстрирует, как найти адрес переменной ‘a’
| | / 58_address.c /
#include
int main()
{
int a = 10;
printf(“\n Значение A: %d”, a);
printf(“\n Адрес A: %d”, &a);
return 0;
} |
Замените вышеуказанные отмеченные значения формата на следующий формат, чтобы получить абсолютное шестнадцатеричное значение адреса.
0x%x
Пример.
printf("\nАдрес A: 0x%x", &a);Программа для нахождения адреса функции ‘disp()’
| | / 59_address.c /
#include
void disp()
{
printf(“\nПривет”);
printf(“\nКак дела”);
printf(“\nТы”);
} int main()
{
disp();
printf(“\nАдрес disp(): 0x%x”, &disp);
return 0;
} |
4. Указатели
Согласно последнему разделу мы знаем, как находить и отображать адрес переменной/функции.
На этот раз мы учимся, как хранить адрес переменной/функции в другой переменной.
Примечание: Переменные могут хранить постоянные значения.
| | Попробуйте следующее: int a, b;
a = 5; / Верно /
b = &a; / Неверно / Снова попробуйте следующее: int a, b;
a = 5; / Верно /
b = &a; / Верно */ |
b = &a; правильно! Да, переменные (обычные переменные) не могут хранить адреса. Но переменные, предшествующие ‘*’ (указатели), могут хранить как постоянные значения, так и адреса других переменных/функций.
Указатель: Переменная, которая хранит адресные значения.
| | Переменные (обычные)
Обычная переменная выполняет только одну операцию для хранения постоянных значений | Переменные указателей (переменные, предшествующие ‘*’)
Переменные указателей могут выполнять две операции для хранения постоянных значений, а также адресных значений других переменных/функций |
Ссылка на / Указатель на / Содержимое по адресу (*)
int *ptr;Для непосвященных это довольно странный синтаксис. Звездочка означает указатель на. Таким образом, оператор определяет переменную ptr как указатель на int. Это другой способ сказать, что переменная может хранить адрес целочисленных переменных.
| | Если бы мы назвали это типом указателя, мы могли бы написать объявление так.
pointer ptr; /* неверно */
``` Проблема в том, что компилятору нужно знать, к какому типу переменной указывает указатель. |
| | Объявление переменной указателя
char *cptr; /* Указатель на символ */
int *iptr; /* Указатель на int */
float *fptr; /* Указатель на float */
struct emp *e; /* Указатель на абстрактные данные emp e */ |
#### Доступ к переменной, на которую указывает:
Вот специальный способ доступа к значениям переменной, используя ее адрес вместо ее имени.
| | /* 60_addr.c */
#include
int main()
{
int var1 = 11; /* переменная var1 = 11 */
int *ptr; /* Переменная ptr как указатель на */
ptr = &var1; /* Хранит адрес var1 в ptr */
printf("Значение var1: %d", *ptr); /* Указатель на адрес var1 */
return 0;
} |
| |  |
Если оператор printf("%d", ptr); тогда он отображает значение ptr, то есть адрес var1, но вышеуказанный оператор может отображать содержимое адреса, которое было сохранено в переменной ptr.
Программа для демонстрации использования Address_Of и Pointer_To
| | /* 61_ptrdemo.c */
#include
int main()
{
int a = 10, *p; /* Целое a и указатель p */
p = &a; /* Присваивает адрес a указателю p */
printf("\nЗначение A: %d", a); /* Содержимое a */
printf("\nАдрес A: 0x%x", &a); /* Адрес a */
printf("\nЗначение P: 0x%x", p); /* Содержимое p */
printf("\nАдрес P: 0x%x", &p); /* Адрес p */
printf("\nСодержимое по адресу a: %d", *p); /* Указатель на &a */
return 0;
} |
#### 5. Арифметика указателей
Все переменные могут поддерживать арифметические операции, а также мы можем выполнять арифметические операции над указателями. Язык C/C++ поддерживает 4 арифметические операции над указателями, а именно.
| | Операция
Сложение
Вычитание
Инкремент
Декремент | Символ
+
-
++
-- |
Примечание: Основная характеристика арифметики указателей заключается в том, что вышеуказанные операторы применяются в байтах относительно типа переменной.
| | /* 62_ptr.c */
/* Демонстрация арифметики указателей */
#include
int main()
{
int a, *p;
a = 100;
p = &a;
(*p)++; /* Увеличивает указатель на (содержимое по адресу) на 1 */
printf("%d", *p);
return 0;
} |
| | Вывод
101 |
Демонстрация арифметики указателей, инкремент значения адреса
| | /* 63_ptr.c */
/* Увеличивает значение адреса на 1 */
#include
int main()
{
int a, *p;
a = 100;
p = &a;
*p++; /* Увеличивает значение адреса в p на 1 */
printf("%d", *p);
return 0;
} |
| | Вывод
Неожиданный вывод |
Вышеуказанная программа иллюстрирует арифметические операторы относительно как значения, так и инкрементации адреса. p - это переменная указателя, а a присваивается 100, а также p присваивается адрес a.
Теперь *p++ влияет на инкрементирование или фактически пропускает память на 2 байта, чтобы получить новый адрес и их содержимое.
Если это **(*p)++, тогда содержимое, на которое указывает p**, равно 100, увеличивается, в результате чего получается 101.
#### 6. Указатели и массивы
В языке C/C++ типы данных указатели и массивы схожи друг с другом. Элементы массива ссылаются, а также переменная указателя, обе используются для хранения адреса элементов данных в памяти.
| | char name[20];
Или
char *name ;
char months[12][10];
Или
char **months; |
Существует тесная связь между указателями и массивами. Вот обзор массивов.
| | /* 64_ptrarr.c */
#include
int main()
{
int i, a[5] = { 56, 43, 78, 98, 12 };
for( i = 0; i < 5; i++)
printf("\n%d", a[i]);
return 0;
} |
Существует возможность доступа к элементам массива, используя нотацию указателя.
Найдите вывод следующей программы.
| | /* 65_ptrarr.c */
#include
int main()
{
int i, a[5] = { 56, 43, 78, 98, 12 };
for( i = 0; i < 5; i++)
printf("\n%d", *(a + i) );
return 0;
} |
Следующая программа:
| | /* 66_ptrarr.c */
#include
int main()
{
int i, a[] = { 56, 43, 78, 98, 12 }, *p;
p = a;
for( i = 0; i < 5; i++)
printf("\n%d", *(p + i) );
return 0;
} |
Вот самый простой способ напечатать элементы данного массива (размер не требуется).
| | /* 67_ptrarr.c */
#include
int main()
{
int i, a[] = { 56, 43, 78, 98, 12 }, *p;
p = a;
while (*p) /* или for(int i = 0; i<5; i++ ) */
printf("\n%d", *p++);
return 0;
} |
#### 7. Указатели и строки
Строка - это коллекция символов, включая пробелы. На этот раз мы обсуждаем, как обрабатывать строки с помощью указателей. Больше никаких обсуждений, чтобы не путаться. Вот простая задача, чтобы проверить как указатели, так и массив строк.
Существует тонкая разница между строками и указателями, следуйте программе.
| | /* 68_ptrstr.c */
#include
int main()
{
char str1[] = "Вы хотели бы исследовать C.";
char *str2 = "Вы хотели бы исследовать C.";
puts(str1);
puts(str2);
str1++; /* Неверное выражение */
str2++; /* Верное выражение */
puts(str2); /* печатает вы хотели бы исследовать…… */
return 0;
} |
Строки как аргументы функции
Переменная указателя более гибкая, чем переменные массива, вот программа, чтобы продемонстрировать и отобразить строку с помощью нотации указателя.
| | /* 69_ptrarr.c */
#include
void disp(char *p);
int main()
{
char str[] = "Привет!!..Привет!!.. Указатели могут с этим справиться?";
disp(str);
return 0;
} void disp(char *p)
{
while(*p)
printf("%c", *p++);
} |
Массив указателей на строки
Существует недостаток в хранении массива строк, в том, что подмассивы, которые хранят строку, должны быть одинаковой длины. Так что пространство теряется, когда строки короче подмассивов.
Вот решение:
| | /* 70_strings.c */
#include
int main()
{
char *weeks[7] = { "Воскресенье", "Понедельник", "Вторник", "Среда",
"Четверг", "Пятница", "Суббота" };
int i;
for( i = 0; i < 7; i++)
puts(weeks[i]);
return 0;
} |
Когда строки не являются частью массива, C/C++ размещает их последовательно в памяти, так что нет потерь пространства.
**/* Пример программы для хранения массива указателей типа ‘int’ */**
| | /* 71_ptrarr.c */
#include
int main()
{
int *arr[4]; /* Массив указателей на int */
int i = 31, j = 5, k = 19, l = 71, m;
arr[0] = &i;
arr[1] = &j;
arr[2] = &k;
arr[3] = &l;
for(m = 0; m <= 3; m++)
printf("\n%d", *(arr[m]));
return 0;
} |
Взгляд на библиотечные функции
Мы уже знакомы со стандартными строковыми функциями. У них есть строковые аргументы, которые указываются с использованием нотации указателя,
Если мы ясны с концепцией указателей и строк, мы можем написать свои собственные строковые функции.
Вот пример программы для копирования строки.
**/* Копирует одну строку в другую с помощью указателей */**
| | /* 72_strcpy1.c */
#include
void strcpy1(char * dest, char *src);
int main()
{
char *str1 = "Как я могу узнать больше о C/C++ !!!";
char *str2;
strcpy1(str2, str1);
puts(str2);
return 0;
} void strcpy1(char * dest, char *src)
{
while(*src)
*dest++ = *src++;
*dest = '\0';
} |
#### 8. Глоссарий
| Адрес | Значение, указывающее на местоположение в памяти. Указатель содержит адрес или местоположение значения, в отличие от самого значения. |
| Массив | Массив - это коллекция элементов данных одного типа. |
| Смежный | Характеристика хранения, которая указывает, что значения хранятся в последовательных местах как в памяти, так и на диске. |
| Функция | Серия инструкций для выполнения конкретной задачи, которые могут быть объединены с другими функциями для создания программы. |
| Память | Описание устройства или носителя, который может принимать данные, хранить их и предоставлять по запросу позже. Синоним хранения. |
| Указатель | Содержит адрес или местоположение памяти значения, в отличие от самого значения. |
| ОЗУ | (Оперативная память) 1. Устройство хранения, структурированное так, что время, необходимое для извлечения данных, не зависит существенно от физического местоположения данных. 2. *Основной раздел хранения* персонального компьютера. |
| Строка | Массив, способный хранить ноль или более символов. В C строка объявляется как массив символов с добавленным NULL () символом, чтобы указать конец строки. |
| Переменная | Имя, связанное с местоположением в памяти, значение которого может изменяться во время выполнения программы. | Get new posts in your inbox
No spam. Unsubscribe anytime.