Константные указатели

Теги: Константные указатели, указатели константы, указатели на константы



Константные указатели, указатели-константы и указатели на константы

Очень много ошибок в программировании связано с неправильным или непредсказуемым изменением переменных. Даже в простом приложении можно напутать порядок работы или забыть удалить ресурсы. В многопоточных приложениях обобщённые ресурсы становятся настоящей головной болью. При совместной разработке, если функции позволяют изменять значение переданного аргумента, рано или поздно кто-нибудь обязательно их изменит неправильным образом.

Один из методов борьбы с такими ошибками – это запрет модификации объекта. В си можно создавать такие указатели, которые могут изменять своё значение (то есть, их можно переприсваивать), но при этом они могут только читать содержимое памяти и не могут его изменять.

#include <conio.h>
#include <stdio.h>

void main() {
	const char* p = NULL;
	unsigned length = 0;
	char word[] = "Hello world!";

	p = word;
	while (*p++) {
		length++;
	}
	//Операция *p = '?' запрещена и приведёт к ошибке

	printf("length(\"%s\") = %d", word, length);
	getch();
}

Использование константных указателей позволяет значительно обезопасить работу. Например, если мы используем функцию, и она принимает константный указатель, то мы уверены, что она не изменит наши данные.

#include <conio.h>
#include <stdio.h>

unsigned getSafeLength(const char *word) {
	const char *p = word;
	unsigned length = 0;
	if (word != NULL) {
		while (*p++) {
			length++;
		}
	}
	return length;
}

unsigned getUnsafeLength(char *word) {
	char *p = word;
	unsigned length = 0;
	if (word != NULL) {
		while (*p++) {
			//HAHAHA! EVIL ACTIVITY!
			if (*p == 'A') {
				*p = 'B';
			}
			length++;
		}
	}
	return length;
}

void main() {
	const char* p = NULL;
	unsigned length = 0;
	char word[] = "Hay guys! Right answer for #3 question is A";

	printf("length(\"%s\") = %d\n", word, getSafeLength(word));
	printf("length(\"%s\") = %d\n", word, getUnsafeLength(word));
	getch();
}

Когда мы видим код программы, у нас есть возможность узнать, меняются ли переданные аргументы или нет. Но это уже требует времени. Если мы пользуемся чужими библиотеками, то у нас есть доступ только до документации или до h-файлов.

unsigned getSafeLength(const char *);
unsigned getUnsafeLength(char *);

Из определения функции видно, что первая функция не может изменить аргумента, о второй ничего не известно. Старайтесь использовать константные указатели, где есть возможность.

Указатель может быть константой сам по себе. Это значит, что нельзя изменить содержимого указателя, но с помощью него можно получить доступ до содержимого объекта, на который он ссылается.

#include <conio.h>
#include <stdio.h>

void main() {
	int x = 100;
	int *const p = &x;

	printf("x = %d\n", x);
	*p = 200;
	printf("x = %d", x);
	//операция p = &? или p++ и т.п. запрещены

	getch();
}

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

#include <conio.h>
#include <stdio.h>

void main() {
	int x = 100;
	const int *const p = &x;

	printf("x = %d\n", x);
	printf("x = %d", *p);

	getch();
}

Можно также хранить указатель константы. Так как это константа, то необходимо, чтобы указатель тоже был константным.

#include <conio.h>
#include <stdio.h>

void main() {
	const int x = 100;
	const int *p;

	p = &x;

	printf("x = %d\n", x);
	printf("x = %d", *p);

	getch();
}

Ну и самый жуткий пример: константный указатель константа на константу. Область применения: сферическое программирование в вакууме.

Заметьте, const char *p и char const *p ничем не отличаются. Каких-либо условий, когда как писать далее делать не будем.

Q&A

Всё ещё не понятно? – пиши вопросы на ящик email
Указатели