🏠 | 💻 IT | Программирование Code | C |

Указатели

Адрес в памяти

Прежде чем углубляться в указатели. Разберем оператор &

Создадим файл address.c и напишем небольшую программу.

#include <stdio.h> int main() { int a; printf("Address of variable a in memory is: %u\n", &a); int b; printf("Address of variable b in memory is: %u\n", &b); double c; printf("Address of variable c in memory is: %u\n", &c); int d; printf("Address of variable d in memory is: %u\n", &d); return 0; }

andrey@olegovich:/mnt/c/Users/Andrei/c$ gcc -o address address.c
andrey@olegovich:/mnt/c/Users/Andrei/c$ ./address

Address of variable a in memory is: 3802827836 Address of variable b in memory is: 3802827832 Address of variable c in memory is: 3802827824 Address of variable d in memory is: 3802827820

Как видите, мы получили адрес a и адрес b, который меньше на четыре, адрес c меньше уже на 8 потому что тип c double и под него нужно не 4 а 8 байт. С помощью этого метода, Вы можете проверить сколько точно байт занимает тот или иной тип у Вашего компилятора.

Введение в указатели

Указатели хранят адреса переменных в памяти. Хотя это и не реальный адрес в вашей CPU а виртуальный, который потом будет сопоставлен реальныму Вашей ОС, сути это не меняет.

Указатель - это тоже переменная, поэтому можно сделать указатель на указатель.

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

char * ptr_to_char;

Тем не менее, можно задать указатель void то есть с неизвестным типом.

void * ptr_to_unknown;

С такими указателями надо быть особенно осторожными.

указатель = 0 это null pointer - особый указатель, который никуда не указывает.

int * ptr_to_nothing = 0;

Если Ваш указатель указывает куда-то не туда - Вы получите segmentation fault.

Разыменование это получение значения, которое записано там куда указывает указатель

Рассмотрим небольшой пример

#include <stdio.h> #include <stdlib.h> int main() { int money = 100; int *p = &money; // p указывает на место в памяти, //в котором хранится переменная money //в данный момент значение, которое там хранится это 100 printf("money = %d\n", money); // ожидаем увидеть 100 printf("p = %d\n", p); // ожидаем увидеть адрес переменной money // делаем разыменование printf("*p = %d\n", *p); // ожидаем увидеть 100 int balance; // делаем разыменование balance = *p + 20; printf("balance = %d\n", balance); return 0; }

Выполним этот код два раза подряд

andrey@olegovich:/mnt/c/Users/Andrei/c$ ./money

money = 100 p = -814504480 *p = 100 balance = 120

andrey@olegovich:/mnt/c/Users/Andrei/c$ ./money

money = 100 p = -691897248 *p = 100 balance = 120

money и balance, как и ожидалось не изменяются, а вот адрес памяти выделенный под money, за которым мы наблюдаем через p - изменяется

#include <stdio.h> int main() { int a; printf("Address of variable a in memory is: %u\n", &a); // Ожидаем какое-то заранее неизвестное число int b = 10; printf("Address of variable b in memory is: %u\n", &b); // Ожидаем число на 4 меньше предыдущего double d; printf("Address of variable d in memory is: %u\n", &d); // Ожидаем число на 8 меньше предыдущего float f = 5.8; printf("Address of variable f in memory is: %u\n", &f); // Ожидаем число на 4 меньше предыдущего int *ptr1; ptr1 = &a; int *ptr2 = &b; float *ptr3 = &f; printf("---------------------------------------------------\n"); printf("Value of ptr1 is %u\n", ptr1); // Ожидаем адрес a printf("Value of ptr2 is %u\n", ptr2); // Ожидаем адрес b printf("Value of ptr3 is %u\n", ptr3); // Ожидаем адрес f printf("---------------------------------------------------\n"); printf("Value stored in a = %u\n", a); // Ожидаем какой-то мусор printf("Value stored in a access with ptr1 = %u\n", *ptr1); // Ожидаем то же самое мусорное значение printf("Value stored in b = %u\n", b); // Ожидаем 10 printf("Value stored in b access with ptr2 = %u\n", *ptr2); // Ожидаем 10 printf("---------------------------------------------------\n"); printf("Comment: now a = 30 \n"); printf("---------------------------------------------------\n"); a = 30; printf("Address of variable a in memory is: %u\n", &a); // Ожидаем тот же самый адрес printf("Value stored in a = %u\n", a); // Ожидаем 30 printf("The sum of a and b is %d\n", *ptr1 + *ptr2); // Ожидаем 40 printf("---------------------------------------------------\n"); printf("Address of ptr1 in memory is: %u\n", &ptr1); // Ожидаем какое-то заранее неизвестное число printf("Address of ptr2 in memory is: %u\n", &ptr2); // Ожидаем число на 8 меньше предыдущего если у Вас x64 архитектура и на 4 меньше если x86 printf("Address of ptr3 in memory is: %u\n", &ptr3); // Ожидаем число на 8 меньше предыдущего если у Вас x64 архитектура и на 4 меньше если x86 printf("---------------------------------------------------\n"); printf("Comment: now ptr1 = ptr2\n"); printf("---------------------------------------------------\n"); ptr1 = ptr2; // теперь ptr1 указывает туда же куда и ptr2 printf("Address of variable b in memory is: %u\n", &b); // Адрес b не должен измениться с предыдущего вызова printf("Value of ptr1 is: %u\n", ptr1); // Ожидаем адрес b printf("Value stored in b access with ptr1 = %u\n", *ptr1); // Ожидаем 10 printf("---------------------------------------------------\n"); printf("Address of ptr1 in memory is: %u\n", &ptr1); // Адрес ptr1 не должен измениться printf("Address of ptr2 in memory is: %u\n", &ptr2); // Адрес ptr2 не должен измениться printf("Value stored in a = %u\n", a); // Ожидаем 30 printf("---------------------------------------------------\n"); return 0; }

Как сделать segmentation fault

Это не сложно - попробуйте разыменовать указатель, который никуда не указывает.

#include <stdio.h> #include <stdlib.h> int main() { int * p = 0; int var = *p + 3; return 0; }

Следующий урок: Структуры Предыдущий урок: Побитовые операции

Статьи о Си:
Учебник по Си
Boolean в Си
Сокеты в Си
К и Р
Что такое argc, char * argv[]
Функция scanf()
Структуры в Си
Оператор «стрелка» указатель на член структуры

Если остались вопросы - смело задавайте их в комментариях.

Поиск по сайту
Контакты и сотрудничество:
Рекомендую наш хостинг beget.ru
Пишите на info@urn.su если Вы:
1. Хотите написать статью для нашего сайта или перевести статью на свой родной язык.
2. Хотите разместить на сайте рекламу, подходящуюю по тематике.
3. Реклама на моём сайте имеет максимальный уровень цензуры. Если Вы увидели рекламный блок недопустимый для просмотра детьми школьного возраста, вызывающий шок или вводящий в заблуждение - пожалуйста свяжитесь с нами по электронной почте
4. Нашли на сайте ошибку, неточности, баг и т.д. ... .......
5. Статьи можно расшарить в соцсетях, нажав на иконку сети: