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

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



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

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

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

#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
Указатели