char string[80];
позволяет описывать и обрабатывать символьные данные, однако тип char[ ] относится к целому типу, поскольку имеет дело с ASCII-кодами символов.
Особым случаем массива является строковый литерал (строка-константа) – последовательность любых символов, заключенных в кавычки: “это строковый литерал”. Строковый литерал представляется в памяти как массив элементов типа char[ ], в конце которого помещен символ ‘\0’ (нулевой байт); его называют ACSIIZ-строкой. Как и с любым массивом, со строковым литералом связан указатель-константа на первый элемент строки.
Можно также описать указатель символьного типа
char *str;
который пока не связан ни с какой символьной информацией.
Символьные массивы можно инициировать, вводить и выводить поэлементно, как и числовые массивы, однако более рационально выполнять инициирование с помощью строковых литералов, а ввод-вывод по ссылке на имя символьного массива, которое является указателем-константой на первый элемент массива (с индексом 0).
Совершенно идентичны следующие описания с инициализацией:
|
|
char string [10] = {‘с’,’л’,’о’,’в’,’о’,’\0’};
char string [10] = ”слово”;
Последнее описание выглядит проще, а нулевой байт записывается в конце строки автоматически. Адрес первого элемента (‘с’) становится синонимом имени массива string. Строка в массиве ограничена нулевым байтом, а остальные элементы массива не используются. Можно не задавать размер массива, компилятор выделит нужное число элементов плюс нулевой байт при инициализации:
char string[ ]=”слово”;
Описание вида char * str;
выделит место в памяти только для указателя str, а место для отсутствующей строки не выделяется. Можно инициировать указатель строковым литератором, например,
char * str = “Иванов А.С.”;
или присваиванием определить указатель:
str = “Иванов А.С.”;
тогда указатель получит адрес первого символа литерала, который располагается в сегменте данных программы.
Стандартные функции ввода-вывода можно использовать для обработки символьных данных.
Пример. Ввести и вывести строку символов.
Программа.
void main ()
{ char name [25];
puts (“Введите Фамилию И.О.:”);
gets (name);
puts (“Вывести Фамилию И.О.:”);
puts (name); /* или printf(“%s”, name); */
}
Функция scanf (“%s”, name) менее удобна, поскольку вводит символы до первого пробела.
При использовании указателя для выделения памяти под любое содержимое строки необходимо использовать функции динамического выделения памяти, для чего в начале программы необходимо добавить команду препроцессора
#include <alloc.h>.
Пусть дано описание указателя
char * str;
тогда оператор вида
str = (char*) malloc (30);
выделит 30 байт в динамической памяти и запишет адрес начала этого блока в указатель str.
|
|
Можно также использовать другую функцию:
str = (char*) calloc (количество, размер элемента);
которая возвращает указатель (адрес) на выделенный блок памяти = количество * размер элемента (байт) и обнуляет выделенную память.
После использования блока динамической памяти его надо освободить функцией
free (указатель), например, free (str).
Пример. Ввод и вывод строк в динамической памяти.
Программа:
#include <alloc.h>
void main ()
{ char * pname;
pname = (char*) malloc (30); /* выделение динамической памяти */
printf (“Введите Фамилию И.О.:”);
gets (name);
printf (“Вывод Фамилии И.О.:”);
free (name); /* освобождение динамической памяти */
}
Особый случай – инициализация двухмерного массива строковыми литералами. Многомерные массивы могут инициироваться и без указания одной (самой левой) из размерностей массива в [ ]. Компилятор сам определяет число элементов по числу членов в списке инициализации.
Например,
char str [ ] [80] = { “Первая строка”,
“Вторая строка”,
“Третья строка” };
Как было показано выше, элементы массива str[0], str[1], str[2] являются указателями на строки двухмерного массива, что можно использовать при обработке таких массивов.
Пример. Ввод и вывод строковых данных.
Программа:
void main ()
{ int i;
char buffer [3][80];
puts (“Введите строки в буфер:”);
for (i=0; i<3; i++) gets (buffer[i]);
puts (“Вывод строк из буфера:”);
for (i=0; i<3; i++) puts (buffer[i]);
}
Пример. Скопировать символы из массива s1, на который ссылается указатель ps1, в массив s2, на который ссылается указатель ps2. Исходная строка заканчивается символом ‘\0’.
Программа:
void main ()
{ char s1[80], s2[80], *ps1=s1, *ps2=s2; /* инициализация указателей */
clrscr (); /* очистка экрана */
puts (“Введите строку и нажмите Enter:”);
gets (s1); /* чтение строки и запись нуль-байта */
while (*ps1!= ’\0’) /* цикл пока не конец строки */
{ *ps2 = *ps1; /* копирование символа */
ps1++; /* переход к следующему символу в s1 */
ps2++; /* переход к следующему символу в s2 */
}
*ps2 = ’\0’; / * запись нуль-байта в строку s2 */
printf (“Скопирована строка:\n%s”,s2); /* вывод строки s2 */
} /* конец программы */
С учетом старшинства и действий операций присваивания (=), разадресации (*) и увеличения (++) копирование символов можно выполнить одним оператором while () с пустым телом цикла с одновременной проверкой условия:
while (*ps2++ = *ps1++);
Язык Си (и Си++) одновременно и любят и не любят за возможность использования столь лаконичных конструкций, которые требуют высокой квалификации программистов, но затрудняют понимание алгоритма.
Проще выглядит копирование символов с помощью оператора цикла:
for (i=0; s2[i]=s1[i]; i++); /* тело цикла – пустой оператор */