Язык Си - руководство для начинающих - M. УЭИТ
Шрифт:
Интервал:
Закладка:
Если бы я имел столько денег, сколько могу потратить,
Я никогда бы нe жаловался, что приходится чинить старые стулья.
Я считаю 63 символа.
Теперь вы можете построить работающую версию функции gets( ); она должна быть похожа на нашу функцию getint( ) из гл. 10, но гораздо проще ее.
ФУНКЦИИ, РАБОТАЮЩИЕ СО СТРОКАМИ
Большинство библиотек языка Си снабжено функциями, работающими со строками. Рассмотрим четыре наиболее полезных и распространенных: strlen( ), strcat( ), strcmp( ) и strcpy( ).
Мы уже применяли функцию strlen( ), которая находит длину строки. Используем ее в нижеследующем примере функции, укорачивающей длинные строки.
Функция strlen( )
/* Функция Прокруста */
fit(string, size)
char *string;
int size;
{
if(strlen(string) > size)
*(string + size) = ' ';
}
Проверьте ее в "деле" в этой тестовой программе:
/* тест */
main( ) {
static char mesg[ ] = "Ну, теперь держитесь, компьютероманы.";
puts(mesg);
fit(mesg, 10);
puts(mesg);
}
Программа выдает:
Ну, теперь держитесь, компьютероманы.
Ну, теперь
Наша функция помещает символ ' ' в одиннадцатый элемент массива, заменяя символ пробела. Остаток массива остается на старом месте, но puts( ) прекращает работу на первом нуль-символе и игнорирует остаток массива.
Функция strcat( )
Вот что умеет делать функция strcat( ):
/* объединение двух строк */
#include
< stdio.h>
main( )
{
static char flower [80];
static char addon[ ] = "ы пахнут старыми ботинками.";
puts(" Назовите ваш любимый цветок." );
gets(flower);
strcat (flower, addon);
puts(flower);
puts(addon);
}
Получаем на экране:
Назовите ваш любимый цветок.
Ирис
Ирисы пахнут старыми ботинками.
Очевидно, что strcat( ) (string concatenation) использует в качестве аргументов две строки. Копия второй строки присоединяется к концу первой, и это объединение становится новой первой строкой. Вторая строка не изменяется.
Внимание! Эта функция не проверяет, умещается ли вторая строка в первом массиве. Если вы ошиблись при выделении памяти для первого массива, то у вас возникнут проблемы. Конечно, можно использовать strlen( ) для определения размера строки до объединения.
/* Объединение двух строк, проверка размера первой */
#include <stdio.h>
#define SIZE 80
main( )
{
static char flower[SIZE];
static char addon[ ] = " ы пахнут старыми ботинками." ;
puts(" Назовите ваш любимый цветок. ");
gets(flower);
if((strlen(addon) + strlen(flower) + 1) < SIZE)
strcat (flower, addon);
puts(flower);
}
Мы добавляем 1 к объединенной длине для размещения нуль-символа.
Функция strcmp( )
Предположим, что вы хотите сравнить чей-то ответ со строкой, находящейся в памяти:
/* Будет ли это работать? */
#include <stdio.h>
#define ANSWER " Грант"
main( )
{
char try [40];
puts(" Кто похоронен в могиле Гранта?" );
gets(try);
while(try != ANSWER)
puts(" Нет, неверно. Попытайтесь еще раз." );
gets(try);
} puts(" Правильно.");
}
Хотя эта программа и смотрится неплохо, она не будет работать правильно, try и ANSWER на самом деле являются указателями, поэтому сравнение (try != ANSWER) спрашивает не о том, одинаковы ли эти две строки, а одинаковы ли два адреса, на которые ссылаются try и ANSWER. Так как ANSWER и try запоминаются в разных ячейках, эти два указателя никогда не могут быть одним и тем же, и пользователю всегда сообщается, что программа неверна. Такие программы обескураживают людей.
Нам нужна функция, которая сравнивает содержимое строк, а не их адреса. Можно было бы придумать ее, но это уже сделала за нас функция strcmp( ) (string comparision).
Теперь исправим нашу программу:
/* это будет работать */
#includе <stdio.h>
#define ANSWER " Грант"
main( )
{
char try [40];
puts(" Кто похоронен в могиле Гранта?" );
gets(try);
while(strcmp(try, ANSWER) != 0)
{ puts(" Нет, неверно. Попытайтесь еще раз.");
gets(try);
} puts(" Правильно!");
}
Так как ненулевые значения интерпретируются всегда как "true", мы можем сократить оператор while do while(strcmp(try, ANSWER)).
Из этого примера можно сделать вывод, что strcmp( ) использует два указателя строк в качестве аргументов и возвращает значение 0, если эти две строки одинаковы. Прекрасно, если вы придете к такому выводу.
Хорошо, что Strcmp( ) сравнивает строки, а не массивы. Поэтому, хотя массив try занимает 40 ячеек памяти, а " Грант" - только 6 (не забывайте, что одна нужна для нуль-символа), сравнение выполняется только с частью try, до его первого нуль-символа. Такую функцию strcmp( ) можно использовать для сравнения строк, находящихся в массивах разной длины.
А что если пользователь ответил " ГРАНТ" или " грант" или "Улиссес С. Грант" ? Хорошо, если пользователю сказали, что он ошибся? Чтобы сделать программу гибкой, вы должны предусмотреть несколько допустимых правильных ответов. Здесь есть некоторые тонкости. Вы могли бы в операторе #define определить в качестве ответа " ГРАНТ" и написать функцию, которая превращает любой ответ только в это слово. Это устраняет проблему накопления, но остаются другие поводы для беспокойства.
Между прочим, какое значение возвращает strcmp( ), если строки не одинаковы? Вот пример:
/* возвраты функции strcmp */
#include <a: stdio.h>
main( )
{
printf(" %d n" , strcmp( "A" , " A" ));
printf(" %d n" , strcmp( "A" , " B" ));
printf(" %d n" , strcmp( "B" , " A" ));
printf(" %d n" , strcmp( "C" , "A" ));
printf(" %d n" , strcmp(" apples", " apple"));
}
В результате получаем
0 -1
1
2 115
Как мы и предполагали, сравнение "А" с самим собой возвращает 0. Сравнение "А" с "В" дает -1, а "В" с "А" дает 1. Это наводит на мысль, что strcmp( ) возвращает отрицательное число, если первая строка предшествует второй в алфавитном порядке, или положительное число, если порядок иной. Кроме того, сравнение "С" с "А" дает 2 вместо 1. Картина проясняется: функция возвращает разницу между двумя символами в коде ASCII. В более общем смысле strcmp() передвигается вдоль строк до тех пор, пока не находит первую пару не совпадающих символов; затем она возвращает разницу в кодах ASCII. Например, в самом последнем примере "apples" и "apple" совпадают, кроме последнего символа 's', в первой строке. Он сопоставляется с шестым символом в "apple", который является нуль-символом (0 в ASCII).
Возвращается значение
's' - ' ' = 115 - 0 = 115,
где 115 является кодом буквы 's' в ASCII.
Обычно вам не нужно точно знать возвращаемое значение. Чаще всего вы только хотите знать, нуль это или нет, т. е. было ли совпадение. Или, может быть, вы пытаетесь отсортировать строки в алфавитном порядке и хотите узнать, в каком случае сравнение дает положительный, отрицательный или нулевой результат.
Можно использовать эту функцию, чтобы проверить, остановится ли программа, читая вводимую информацию:
/* Начало какой-то программы */
#include &stdio.h&
#define SIZE 81
#define LIM 100
#define STOP " " /* нулевая строка */
main( )
{
static char input[LIM][SIZE];
int ct = 0;
while(gets(input[ct]) != NUL && strcmp(input[ct].STOP) !=0
&& ct++ < LIM)