- •Глава 1 элементы языка
- •Вывод: Пробелы употреблять везде, где это допустимо и улучшает читабельность программы.
- •Введение в си
- •Глава 2 элементы данных
- •Глава 3 массивы и структуры
- •Глава 4 операции и выражения
- •Глава 5 основные операторы
- •Формат: ;
- •Глава 6. Ввод – вывод данных
- •Форма представления одного данного
- •6.2 Функции getchar(), putchar(), getch()
- •Глава 7. Блоки и процедуры
- •Глава 8 Препроцессор
- •Вычисление квадратичной формы
- •Глава 9 Символьная информация и строки
- •9.3 Строки или строковые константы
- •Глава 10 фAйлы
9.3 Строки или строковые константы
В программе строки, или строковые константы, представляются последовательностью изображений символов, заключенной в кавычки (не в апострофы), например “любые символы”. Среди символов строки могут быть эскейп-последовательности, соответствующие кодам не изображаемых (специальных) символьных констант.
Примеры:
“1234567890”
“\t состав президиума”
“начало строки \t и конец строки”.
В качестве терминирующего символа выбран символ с кодом 0 (не путайте его с символом '0'). Таким образом, определение
char HelloStr [] = "Hello, world";
фактически интерпретируется как
char HelloStr [] = {'H', 'e', 'l', 'l', 'o', ' ', ',', 'w', 'o', 'r', 'l', 'd', '\0'};
Это происходит при инициализации массива строкой. Во всех остальных случаях встретившаяся строка интерпретируется как еще не созданный безымянный массив соответствующей длины. То есть выражение
printf ("Hello, world\n");
на самом деле интерпретируется как
char str1 [ ] = "Hello, world\n";
printf (str1);
При размещении строки в памяти транслятор автоматически добавляет в ее конец символ ‘\0’, т.е. нулевой байт.
Количество элементов в таком массиве на 1 больше, чем в изображении соответствующей строковой константы, т.к. в конец строки добавили нулевой байт ‘\0’.
У строк есть еще особенность: транслятор отводит каждой строке отдельное место в памяти ЭВМ даже в тех случаях, когда несколько строк полностью совпадают (стандарт языка СИ предполагает, что в конкретных реализациях это правило может не выполняться).
Присвоить значение массиву символов (т.е. строке) с помощью обычного оператора присваивания нельзя. Поместить строку в массив можно либо с помощью инициализации (при определении символьного массива), либо с помощью функций ввода. В функции scanf() или printf() для символьных строк используется спецификация преобразования %s.
Пример:
/*печать символьной строки*/
#include<stdio.h>
void main()
{ char B[]=”Cезам, откройся!”;
printf(“%s”,B); } /*конец программы*/
Результат выполнения программы: Сезам, откройся!
В программе длина массива В – 17 элементов, т.е. длина строки, помещаемой в массив (16 символов), плюс нулевой байт окончания строки. Именно 17 байтов выделяется при инициализации массива в приведенном примере. Инициализация массива символов с помощью строковой константы представляет собой сокращенный вариант инициализации массива и введена в язык для упрощения. Можно воспользоваться обычной инициализацией, поместив начальные значения элементов массива в фигурные скобки и не забыв при этом поместить в конце списка начальных значений специальный символ окончания строки ‘\0’. Таким образом, в программе была допустима такая инициализация массива В:
char B[ ] = {‘C’,’е’,’з’,’а’,’м’,’,’,’ ’,’о’,’т’,’к’,’р’,’о’,’й’,’с’,’я’,’!’,’\0’};
Как вводить строки или выводить их на экран?
Выводиться строка может или уже известной вам функцией printf( ) со спецификатором ввода "%s", либо специальной функцией int puts (char *string), которая выводит строку string на экран и возвращает некоторое ненулевое значение в случае успеха.
Зачем нужен спецификатор "%s"? Это делается для того, чтобы можно было выводить строки с любыми символами. Сравните:
Пример:
char str [] = "Захотелось мне вывести %d...";
printf ("%s", str); /* Правильный вариант */
printf ("\n"); /* Разделитель новой строки */
printf (str); /* Неправильный вариант */
В первом случае функция напечатает именно то, что от нее требуется. А вот во втором случае printf(), встретив в строке str спецификатор "%d" (ведь теперь эта строка – первая, значит, она задает формат вывода), сделает вывод, что за ней должно следовать число. А так как оно не следует, то вместо "%d" будет напечатан некоторый мусор – число, находящееся в тот момент в стеке.
Последствия могут быть и более серьезными, если в строке находится последовательность "%s", то сочтет ее за строку, и будет выводить ее до тех пор, пока не встретит нулевой символ. А где она его встретит, сколько успеет напечатать и не crash'нется ли из-за обращения не к своей памяти – не знает никто.
Cоглашение о признаке окончания строки нужно соблюдать, формируя в программах строки из отдельных символов. В качестве примера рассмотрим следующую
Пример: Необходимо сохранить введенную строку.
/*чтение строки с терминала*/
int getline(char s, /*введенная строка*/
int lim) /*ее максимальная длина*/
{ int c, i; /* с – вводимый символ*/
for ( i=0; i<lim && (c = getchar() )!=EOF && c!=’\n’; i++ ) {
s[i]=c; }
s[i] = ’\0’;
return i; }
Ввод–вывод строк. Основные функции работы со строками
Одной из наиболее популярных операций ввода-вывода является операция ввода-вывода строки символов. В библиотеку языка СИ для обмена данными через стандартные потоки ввода-вывода включены функции ввода-вывода строк gets() и puts(), которые удобно использовать при создании диалоговых систем.
Для ввода строки существует функция с прототипом
char *gets (char *string),
которая считывает строку с клавиатуры и помещает ее в буфер string, указатель на который и возвращает. Если произошла ошибка, то возвращается EOF.
Функция имеет только один аргумент – указатель s на массив символов. Прототип функции описан в файле <stdio.h>.
Функция gets() завершает свою работу при вводе символа ‘\n’, который автоматически передается с клавиатуры в ЭВМ при нажатии клавиши <Enter>. При этом сам символ ‘\n’ во вводимую строку не записывается. Вместо него в строку помещается нуль–символ ‘\0’. Таким образом, функция gets() производит ввод “правильной” строки, а не просто последовательности символов.
Здесь следует обратить внимание на следующую особенность ввода данных с клавиатуры. Функция gets() начинает обработку информации от клавиатуры только после нажатия клавиши <Enter>. Таким образом, она “ожидает”, пока не будет набрана нужная информация и нажата клавиша <Enter>. Только после этого начинается ввод данных в программу.
Пример: #include <stdio.h>
int main (void) {
char string[80];
printf ( "Input a string:" );
gets ( string );
printf ( "The string input was: %s\n", string );
return 0; }
Функция puts() (вывод строки на экран) в случае успешного завершения возвращает последний выведенный символ, который всегда является символом ‘\n', если произошла ошибка, то возвращается из функции EOF. Прототип этой функции имеет следующий вид:
int puts ( char*s ); /*функция вывода строки*/
Функция имеет только один аргумент – указатель s на массив символов. Прототип функции описан в файле <stdio.h>.
Приведем простейший пример использования этих функций.
#include<stdio.h>
char strl[ ] = ”введите фамилию сотрудника:”;
int main ( ) {
char name[80];
puts(strl0;
gets(name);
return 0; }
Напомним, что любая строка символов в языке СИ должна заканчиваться нуль–символом ‘\0’. В последний элемент массива strl нуль–символ будет записан автоматически во время трансляции при инициализации массива. Для функции puts() наличие нуль-символа в конце строки является обязательным.
В противном случае, т.е. при отсутствии в символьном массиве символа ‘\0’, программа может завершиться аварийно, т.к. функция puts() в поисках нуль-символа будет перебирать всю доступную память байт за байтом, начиная, в нашем примере, с адреса strl. Об этом необходимо помнить, если в программе происходит формирование строки для вывода ее на экран дисплея.
Пример: #include <stdio.h>
int main ( void ) {
char string[] = "This is an example output string\n";
puts(string);
return 0; }
Функции манипуляции со строками
Так как в Cи нет предопределенного типа для строки, то нет и столь привычных многим операций, как сравнения и склеивания строк, реализованных во многих языках как операторы сложения и сравнения. Здесь сложение массивов недопустимо, а при сравнении будут сравниваться не сами строки, а только указатели на них, что нам, конечно же, неинтересно.
Для манипуляций со строками существует набор функций, объявленных в файле <string.h> (те, кто пишет под Windows, могут включать вместо него файл <windows.h>).
Наиболее важные функции:
int strcmp (char *string1, char *string2)
осуществляет сравнение двух строк. Возвращает отрицательное число, если первая строка меньше второй, 0, если строки равны и положительное число, если первая строка больше второй. Более детально, функция возвращает разницу между кодами первых встретившихся неодинаковых символов (если строки неодинаковы по длине, то когда-то ненулевой символ будет сравниваться с нулем).
Пример:
#include <string.h>
#include <stdio.h>
int main (void) {
char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc";
int ptr;
ptr = strcmp (buf2, buf1);
if (ptr > 0)
printf("buffer 2 is greater than buffer 1 \n" );
else
printf("buffer 2 is less than buffer 1 \n");
ptr = strcmp( buf2, buf3 );
if (ptr > 0)
printf("buffer 2 is greater than buffer 3\n");
else
printf("buffer 2 is less than buffer 3\n" );
return 0; }
На экране появится:
buffer 2 is greater than buffer 1
buffer 2 is less than buffer 3
char *strcpy (char *dest, char *source)
осуществляет копирование строки source на место строки dest. Опять-таки позаботьтесь о том, чтобы вся строка поместилась в отведенном для нее месте. Функция возвращает указатель на строку-приемник.
Пример: #include <stdio.h>
#include <string.h>
int main (void) {
char string[10];
char *str1 = "a b c d e f g h i";
strcpy (string, str1);
printf( "%s \n", string);
return 0; }
На экране появится: a b c d e f g h I
char *strcat (char *string1, char *string2)
осуществляет склеивание двух строк. Вторая строка добавляется в конец первой. Функция не проверяет (да и не может проверять технически) наличие необходимого количества памяти в конце первой строки – об этом должны позаботиться вы. Функция возвращает указатель на первую строку.
Пример:
#include <string.h>
#include <stdio.h>
int main(void) {
char destination[25];
char *blank = " ", *c = "C++", *turbo = "Turbo";
strcpy (destination, turbo); //Копирование строки "turbo"
на место destination
strcat (destination, blank); // Склеивание destination …
strcat (destination, c); // сначала с blank, потом с c
printf("%s\n", destination);
return 0; }
На экране появится: Turbo C ++
int strlen (char *string)
возвращает длину строки string (не считая нулевого символа).
char *strdup (char *string)
создает дубликат строки string и возвращает указатель на него. Учтите, что в отличие от остальных функций, strdup сама создает строку и поэтому после того, как она стала вам не нужна, не забывайте ее освободить.
char *strncpy ( char *dest, char *source, int count)
char *strncat ( char *string1, char *string2, int count)
аналогично strcpy и strcat, но копируются только первые count символов. Функции не добавляют к строке завершающего нуля – вам придется сделать это самим.
char *strchr (char *string, int c)
char *strstr (char *string, char *substring)
ищут первое вхождение в строку string соответственно символа c и подстроки substring. Обе функции возвращают адрес первого вхождения или NULL, если такового не найдено.
Пример:
int main (void) {
char string[15];
char *ptr, c = 'r';
//Создаем строку
strcpy (string, "This is a string");
ptr = strchr(string, c);
if (ptr)
printf("The character %c is at position: %d\n", c, ptr-string);
else
printf( "The character was not found\n" );
return 0; }
На экране появится: The character r is at position: 12