Учебник по программированию на C для Linux, часть 21: указатели на символы, массив указателей и указатель на указатель
На этой странице
- Указатели на символы, массив указателей и указатель на указатель в C
- Заключение
Концепция указателей действительно является одной из очень важных концепций языка программирования C. До сих пор мы обсуждали несколько аспектов указателей в C. Развивая это, в этом руководстве мы обсудим еще несколько концепций указателей.
Указатели на символы, массив указателей и указатель на указатель в C
Начнем с указателей на символы со следующих строк кода:
char p[] = "I like HowtoForge"
char *p = "I like HowToForge"
Первая строка определяет массив p, размер которого равен количеству символов в двойных кавычках. Но следующая строка определяет указатель p, указывающий на строковую константу.
Разница здесь в том, что первый p является массивом, вы можете легко модифицировать или изменить содержимое массива. Но поскольку второй p указывает на строковую константу, вы просто не можете изменить содержимое строки.
Например, следующий фрагмент кода пытается изменить строковую константу:
#include <stdio.h>
int main()
{
char *p = "I like HowToForge";
p[0] = 'U';
return 0;
}
И вот результат, полученный этим кодом в моей системе:
Segmentation fault
Эта ошибка предполагает, что выполнение программы внезапно прервалось, и это потому, что мы попытались изменить что-то постоянное.
Кроме того, имейте в виду, что, хотя указатель p может указывать на другую строку, вы не можете изменить базовый адрес массива p (если вы помните, мы уже обсуждали это в одном из наших предыдущих руководств).
Теперь перейдем к массивам указателей. Точно так же, как вы видели массивы целых чисел, символов и других типов, также может быть массив указателей. Например, следующая программа определяет массив arr целочисленных указателей и присваивает ему значения.
#include <stdio.h>
int main()
{
int *arr[3];
int a = 0, b = 1, c = 2;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;
return 0;
}
Обратите внимание, что значения, присвоенные массиву, являются адресами. Это связано с тем, что arr представляет собой массив указателей, а указатели не хранят ничего, кроме адресов. Теперь, если вы хотите получить доступ к значениям, хранящимся по этим адресам, вам придется использовать оператор *.
Следующий пример (который является не чем иным, как расширением предыдущего примера) демонстрирует это:
#include <stdio.h>
int main()
{
int *arr[3];
int a = 0, b = 1, c = 2;
arr[0] = &a;
arr[1] = &b;
arr[2] = &c;
for(int i=0; i < 3; i++)
printf("\n arr[%d] is: %d",i,*(arr[i]));
return 0;
}
Вот результат:
arr[0] is: 0
arr[1] is: 1
arr[2] is: 2
Подобно массивам целочисленных указателей (например, тому, который мы обсуждали здесь), вы можете иметь массивы, хранящие указатели на символы и многое другое.
Теперь давайте перейдем к указателю на указатели. Как мы уже повторяли несколько раз, указатель хранит адрес. До сих пор в этой продолжающейся серии руководств по программированию на C мы видели только указатель, указывающий на переменную, не являющуюся указателем, но факт в том, что указатели могут указывать и на другие указатели.
Это означает, что указатель может хранить адрес другого указателя. Например, ниже приведен двойной указатель или указатель на указатель:
int **ptr;
Вот фрагмент кода, использующий двойной указатель:
#include <stdio.h>
int main()
{
int *ptr;
int **p;
int a = 10;
ptr = &a;
p = &ptr;
printf("\n Pointer 'p' points to pointer 'ptr' which further points to value: %d", **p);
return 0;
}
Вот результат:
Pointer 'p' points to pointer 'ptr' which further points to value: 10
Итак, это был пример двойного указателя. В подобных строках вы можете иметь указатель на указатель на указатель, определенный как, например, int ***ptr. Максимальное количество таких указателей на уровни ...... зависит от реализации (хотя в некоторых случаях ограничение равно 12).
На практике, однако, вы, скорее всего, столкнетесь с указателем только на указатели до третьего уровня, поскольку большее количество уровней делает логику более сложной для понимания и сопровождения.
Заключение
Здесь мы обсудили три важные концепции, связанные с указателями. Вам рекомендуется опробовать примеры и концепции, которые мы обсуждали здесь, на вашей системе, чтобы лучше понять, как все это работает. В случае каких-либо сомнений или запросов, напишите нам комментарий ниже.