Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Материалы для подготовки к экзамену по ОП.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
297.52 Кб
Скачать

Указатели и приведение типов

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

#include <conio.h>

#include <stdio.h>

#define SIZE 10

void main() {

int A = 10;

int *intPtr;

char *charPtr;

intPtr = &A;

printf("%d\n", *intPtr);

printf("--------------------\n");

charPtr = (char*)intPtr;

printf("%d ", *charPtr);

charPtr++;

printf("%d ", *charPtr);

charPtr++;

printf("%d ", *charPtr);

charPtr++;

printf("%d ", *charPtr);

getch();

}

В этом примере мы пользуемся тем, что размер типа int равен 4 байта, а char 1 байт. За счёт этого, получив адрес первого байта, можно пройти по остальным байтам числа и вывести их содержимое.

Null pointer - нулевой указатель

Указатель до инициализации хранит мусор, как и любая другая переменная. Но в то же время, этот "мусор" вполне может оказаться валидным адресом. Пусть, к примеру, у нас есть указатель. Каким образом узнать, инициализирован он или нет? В общем случае никак. Для решения этой проблемы был введён макрос NULL библиотеки stdlib.

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

int *ptr = NULL;

По стандарту гарантировано, что в этом случае указатель равен NULL, и равен нулю, и может быть использован как булево значение false. Хотя в зависимости от реализации NULL может и не быть равным 0 (в смысле, не равен нулю в побитовом представлении, как например, int или float).

Это значит, что в данном случае

int *ptr = NULL;

if (ptr == 0) {

...

}

вполне корректная операция, а в случае

int a = 0;

if (a == NULL) {

...

}

поведение не определено. То есть указатель можно сравнивать с нулём, или с NULL, но нельзя NULL сравнивать с переменной целого типа или типа с плавающей точкой.

#include <stdlib.h>

#include <stdio.h>

#include <conio.h>

void main() {

int *a = NULL;

unsigned length, i;

printf("Enter length of array: ");

scanf("%d", &length);

if (length > 0) {

//При выделении памяти возвращается указатель.

//Если память не была выделена, то возвращается NULL

if ((a = (int*) malloc(length * sizeof(int))) != NULL) {

for (i = 0; i < length; i++) {

a[i] = i * i;

}

} else {

printf("Error: can't allocate memory");

}

}

//Если переменая была инициализирована, то очищаем её

if (a != NULL) {

free(a);

}

getch();

}

Пример работы с указателями

Так как размер типа char всегда равен 1 байт, то с его помощью можно реализовать операцию swap – обмена местами содержимого двух переменных.

#include <conio.h>

#include <conio.h>

#include <stdio.h>

void main() {

int length;

char *p1, *p2;

char tmp;

float a = 5.0f;

float b = 3.0f;

printf("a = %.3f\n", a);

printf("b = %.3f\n", b);

p1 = (char*) &a;

p2 = (char*) &b;

//Узнаём сколько байт перемещать

length = sizeof(float);

while (length--) {

//Обмениваем местами содержимое переменных побайтно

tmp = *p1;

*p1 = *p2;

*p2 = tmp;

//не забываем перемещаться вперёд

p1++;

p2++;

}

printf("a = %.3f\n", a);

printf("b = %.3f\n", b);

getch();

}

В этом примере можно поменять тип переменных a и b на double или любой другой (с соответствующим изменением вывода и вызова sizeof), всё равно мы будет обменивать местами байты двух переменных.