На этом шаге мы рассмотрим ососбенности использования таких указателей.
Символьная константа или массив символов в языке С - это строка символов с признаком конца (символом '\0').
Если, например, имеем char а [10];, то а - это указатель на первый элемент массива а[0].
Если, с другой стороны, имеем char *p=&a[0], то наряду с инициализацией а[] =" abc"; можем записать *р="abc". Компилятор в обоих случаях, начиная с адреса, помещенного в указатель р, разместит символы а, b, с.
Следовательно, оперирование именем массива и указателем на этот массив равносильно. Но за исключением некоторого небольшого обстоятельства: если мы хотим записать строку символов в некоторое место памяти, то при объявлении
char a[100];
Кстати, функции тоже могут быть "указателями", т. е. возвращать указатели на объекты заданного типа. В этом случае функция при ее объявлении имеет вид:
<тип объекта, на который указывает указатель>* <имя функции>(аргументы функции).
Например, рассмотрим функцию char* strsave(s). Приведем в качестве примера программу, работающую с указателями символьного типа. Программа содержит функции работы с символьными строками, в которых отражена работа с указателями.
// 56_1.cpp: главный файл проекта. #include "stdafx.h" #include <clocale> //обязательно для функции setlocale() #include <stdio.h> //for getchar(),putchar() #include <conio.h> #include <string.h> using namespace System; #define MAXLINE 1000 #define eof -1 //Ctrl+z // --- Ввод строки с клавиатуры --- int getline(char s[], int lim) { int c,i; for(i=0; i<lim-1 && (c=getchar()) != eof && c != '\n'; i++) s[i]=c; s[i]='\0'; i++; //для подсчета количества return i; } // --- Копирует t[] в s[] --- void strcpy1 (char s[], char t[]) { int i=0; while((s[i]=t[i])!='\0') i++; } // --- Копирует строку, на которую указывает указатель t, // в строку, на которую указывает указатель s --- void strcpy2 (char *s, char *t) { while((*s=*t) != '\0') { s++; t++; } } // --- Выделяет с помощью new() память по длине строки, на которую указывает s, // и в эту память помещает саму строку, а затем выдает указатель на начало // помещенной в буфер строки. --- char *strsave(char *s) { char *p; int i = strlen(s) + 1; p = new char [i]; //выделение памяти в куче if((p != NULL)) strcpy2(p,s); //копирует строку в кучу return p; //возвращается указатель на строку, помещенную в кучу } void main() { setlocale(LC_ALL,"Russian"); //функция setlocale() с аргументами //для корректного вывода кириллицы //Проверка strcpy1() printf("Задайте строку для strcpy1 >"); char s[MAXLINE], t[MAXLINE]; getline(t,MAXLINE); //ввод строки с клавиатуры в t strcpy1(s,t); printf("Входная строка = %s\nВыходная строка = %s\n",t,s); //Проверка strcpy2() printf("Задайте строку для strcpy2 >"); getline(t,MAXLINE); //ввод строки с клавиатуры в t strcpy2(&s[0],&t[0]); printf("Входная строка = %s\nВыходная строка = %s\n",t,s); //Проверка strsave() printf("Задайте строку для strsave >"); getline(s,MAXLINE); //ввод строки в s char *p = strsave(&s[0]); //в р указатель на память, куда записана строка из s printf("Сохраненная строка = %s\n", p); delete [] p; //возврат памяти в кучу _getch(); }
Результат работы приложения изображен на рисунке 1.
Рис.1. Результат работы приложения
Функция void strcpy1(char s[],char t[]) копирует массив в массив. Это происходит поэлементно с помощью цикла while, в заголовочно части его находится выражение, которое надо вычислить, чтобы принять решение о продолжении/завершении цикла.
При вычислении выражения происходит поэлементная пересылка: пересылается один элемент, затем начинает работать тело while, в котором всего один оператор наращивания индекса элемента массива. Когда тело завершается, управление передается в заголовочную часть while, где снова вычисляется выражение, обеспечивающее пересылку следующего элемента массива в массив s и т. д., пока не будет переслан последний символ: '\0'. Когда это произойдет, результат выражения станет равным нулю, и функция завершится. Функция не возвращает никакого значения (ее тип void), но через параметр, адрес которого передается в функцию (массив s[]), возвращает копия массива t[].
Параметрами функции void strcpy2(char *s, char *t) являются указател типа char. Эта функция копирует символы, начиная с адреса, на которы указывает указатель t, в область, на которую указывает указатель s. Перед применением этой функции (как отмечалось ранее) надо определить область памяти, на которую указывает указатель s: либо через массив, либо через функцию new(). В теле strcpy2() организован цикл посимвольного копирования символов из одной области в другую с помощью указателей этих областей: указатель *t передает элемент входной области, а указатель *s - выходной.
После того как первый элемент перешлется, в теле while произойдет приращение значений указателей на единицу, которое позволит обратиться к следующему элементу объекта. Программа снова возвратится в заголовочную часть while, обеспечивающую пересылку второго элемента в область, на которую указывает s (и т. д., пока не будет переслан последний элемент - признак конца массива). При этом значение выражения в заголовочной части while станет равным нулю и циклическая конструкция while завершит работу.
Функция char *strsave(char *s) копирует строку символов, на которую указывает указатель s, в буфер памяти, выделяемый стандартной функцией new(), и возвращает указатель на начало этого буфера, чтобы в дальнейшем можно было извлекать сохраненную в нем строку.
Копирование производится с помощью ранее рассмотренной функции strcpy2(). Работа происходит следующим образом: длина исходной строки с учетом признака конца строки определяется с помощью стандартной функции strlen(). Затем с помощью функции new() выделяется участок памяти такого же размера, как длина входной строки. Перед тем как начать копирование с использованием указателя, возвращенного функцией new(), проверяется, успешно ли сработала эта функция (т. е. действительно ли выделено место в памяти). Это существенный вопрос, т. к. свободной памяти в данный момент могло не оказаться или мог произойти какой-либо сбой. Если память выделена, то new() возвращает ненулевой указатель. После выделения памяти происходит собственно копирование в буфер и возврат указателя, содержащего адрес начала области копирования.
При пояснении основной программы стоит обратить внимание только на проверку strcpy2(). Так как эта функция работает с указателями, то ей мы и передаем указатели: адреса первых элементов массивов.
delete [] p; //возврат памяти в кучу
На следующем шаге мы рассмотрим особенности использования массива массивов в качестве аргумента функции.