Константные указатели
Константные указатели, указатели-константы и указатели на константы
Очень много ошибок в программировании связано с неправильным или непредсказуемым изменением переменных. Даже в простом приложении можно напутать порядок работы или забыть удалить ресурсы. В многопоточных приложениях обобщённые ресурсы становятся настоящей головной болью. При совместной разработке, если функции позволяют изменять значение переданного аргумента, рано или поздно кто-нибудь обязательно их изменит неправильным образом.
Один из методов борьбы с такими ошибками – это запрет модификации объекта. В си можно создавать такие указатели, которые могут изменять своё значение (то есть, их можно переприсваивать), но при этом они могут только читать содержимое памяти и не могут его изменять.
#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
ничем не отличаются. Каких-либо условий, когда как писать далее делать не будем.
