КАК использовать строки?

Если вы дочитали мою книгу до этой главы, знайте - в вас начинает просыпаться настоящий программист! Ведь основаня черта настоящего программиста - упорство! Я возводил у вас на пути скучные листинги, строил заборы из математических форумул, ударялся в теорию. Теперь же эта книга будет всё интереснее, а мы с вами скоро начнём разговаривать на одном языке - Си++.

Как нам помогают строки?
КАК узнать длину строки?
Как сложить две строки?
КАК из строки сделать число?
КАК из числа сделать строку?
КАК что-то найти в строке?
КАК сравнить две строки?


Вопрос: Как нам помогают строки?

Как мы знаем, изначально программирование создавалось для того, чтобы считать. Однако чем дальше, тем больше компьютеры находили своё применение и в других областях нашей жизни. В реальности мы гораздо больше имеем дело с текстовой информацией, чем с цифрами - мы читаем вывески на улице, рекламу в метро, получаем информацию из книг и газет, Интернет-сайтов и теленовостей. И когда компьютер стал претендовать на эти сферы жизни, ему пришлось обучаться читать, писать и говорить.

Для компьютера текст представляется в виде строк - знакомого уже нам типа данных. Что такое строка? Это последовательность символов, заканчивающаяся символом конца строки '\0'. Сферы применения строк обширны: когда мы заполняем текстовые поля в окнах Windows или вводим пароль, тем самым мы вводим строки. Весь диалог компьютера с пользователем построен на строках! А ещё текстовые файлы и WEB-сайты, документы и таблицы. Строки - это сама жизнь! И чем выше мы будем подниматься в уровне программирования, тем чаще с ними будем встрeчаться!


Перед тем, как начать изучать строки я озвучу список основных функций для работы со строками в языке СИ.

Название функции
Действия
Тип
strcat
Склеивает две строки в одну
char *
strcmp(char *, char *)
Сравнение двух строк
int
strcpy(char *, char *)
Копировать одну строку в другую
char *
strlen(char *)
Вычислить длину строки
int
strlwr(char *)
Преобразовать строку в нижний регистр
char *
strrev(char *)
Инвертировать строку (обратить)
char *
strup(char *)
Преобразовать строку в верхний регистр
char *
atof(char *)
Преобраовать строку в тип float
double
atoi(char *)
Преобраовать строку в тип int
int
atol(char *)
Преобраовать строку в тип long
long
ecvt(char *)
Преобраовать строку в тип double
double
gcvt(double)
Преобразовать тип double в строку
char *
itoa(int)
Преобразовать тип int в строку
char *
ltoa(long)
Преобразовать тип long в строку
char *

Подобно тому, как все математические функции "лежат" в библиотеке math.h, функции для работы со строками объединены в библиотеке string.h

Вопрос: КАК узнать длину строки?

Для того, чтобы точно знать, сколько выделить памяти для хранения строки, часто нам нужно получить длину конкретной строки. Разного рода функции иногда предлагают не просто ввести строку, а указать какое количество символов из неё мы хотели бы использовать. Чаще всего мы хотим ввести всю строку, поэтому есть смысл не считать вручную, а просто измерить длину строки и подставить в функцию.

#include<iostream.h>
#include<string.h>

void main()
{
char *str = "машина";

cout<<"Длина строки: "<<strlen(str)<<" символов";

}

Функция strlen() возвращает количество символов в строке. Например для строки "машина" она вернёт число 6.


Вопрос: Как сложить две строки?

Помните мы писали программу, которая c нами здоровалась? Там была строка:

cout<<"Здравствуйте, "<<name;

И умная программка добавляла в конец ваше имя.

А если мы хотим сложить две строки, которые заранее не известны? Для этого в программировании применяется операция "склеивания" - конкатенции (знаю - жуткое слово!), которая позволяет просто сложить две строки вместе и получить одну. В языке СИ такой операции нет, но зато в библиотеке string.h есть специальная функция strncat(), которая позволяет склеивать исходную строку с подстрокой.

#include<iostream.h>
#include<string.h>


void main()
{
char kuda[20];
char *otkuda="Федерация";

strcpy(kuda, "Российская "); //копирование в строку kuda

strncat(kuda, otkuda, strlen(otkuda)); //склеиваем две строки, результат - в строке kuda

cout<<kuda; //на экране фраза "Российская Федерация".

}

Функция strcpy(to, from) копирует строку from в строку to. Кстати, это ещё один из способов присвоения строке значения. Функция strncat объединяет две строки, дописывая в конец строки kuda строку otkuda. Этот процесс можно сравнить с локомотивом, в конец которого на товарной станции прицепляют ещё один вагончик. Для каждого нового вагона нам понадобится функция strncat.

Обратите внимание, что у функции strncat три аргумента. Функция гибка и позволяет скопировать не всю строку, а только её часть. Если мы точно знаем сколько символов в строке otkuda, можно третьим аргументом задать число, но проще всего измерить длину строки с помощью известной нам уже функции strlen().


Вопрос: КАК из строки сделать число?


Для чего это нужно? Часто программа получает данные от пользователя в виде строки. Например, данные полученные из текстовых полей Windows - всегда строковые. И даже если пользователь ввёл число, оно всё равно будет представлено, как строка. Чтобы подставить это число в форумулу, вам придётся его конвертировать в строку.

Вот пример поля ввода:


#include <stdlib.h>
#include <iosatream.h>

void main()
{
int n;
char *str="123456"; //объявляем строку

n=atoi(str); //конвертируем в число

cout<<"Строка = "<<str<<"Число = "<<n;
}


В некоторых классах Windows есть методы, позволяющие сразу получать целые числа из текстовых полей, но метода, позволяющего сразу считывать числа с плавающей запятой, нет, поэтому в любом случае вам понадобится конвертирование. Для преобразования строки в число с плавающей запятой существует функция atof(char *str), которая по своему применению аналогична.

В этом примере мы используем новую для нас библиотеку "stdlib.h" - в данной библиотеке содержится большинство функций конвертирования, а также множество других функций самого разного назначения. Это библиотека очень широкого профиля.

После получения строки из поля ввода, конвертирования в число, подстановки в формулу, или куда-то ещё, ответ зачастую придётся выводить в какое-нибудь окно. Естественно, напрямую число в окно мы не сможем - оно нас просто не поймёт, и заставит выполнять обратное преобразование - теперь уже из числа в строку.
Иногда ответ должен сопровождаться каким-то текстом, например: "U = 127,24 v ". Для создания такого дружественного интерфейса удобнее использовать не саму операцию конвертирования, а записать в один буфер и число и текст.

Функция sprintf аналогична функции printf, с той лишь разницей, что вывод информации осуществляется не в какое-то устройство вывода, а в буфер данных. Используя эту функцию, мы сможем комбинировать различные типы данных в любой последовательности.

#include <stdio.h>

void main()
{
char buffer[25]; //строка, длиной 25 символов
const double f=127.24; //число с плавающей точкой

sprintf(buffer, "U = %3.2f V\n", f);

printf("%s", buffer);

}

Однако, если нам необходимо просто преобразовать число в строку, можно использовать функцию конвертирования, описанную в следующем разделе.

Вопрос: КАК из числа сделать строку?


#include<stdio.h>

void main()
{
int number = 123456;
char *string;

itoa(number, string, 10); //число 10 заботится о добавлении минуса отрицательными числам
printf("Число = %d Строка = %s", number, string);
}


Конвертирование - очень важная задача, и в математических программах без неё никуда. Если ваша программа что-то считает, получая данные от пользователя, вы будете использовать конвертирование постоянно.


Вопрос: КАК что-то найти в строке?


Иногда нам нужно проверить строку на наличие в ней какого-нибудь символа. Например, если пользователь вводит свой E-mail хорошо бы проверить, есть ли в нём символ "at", который в России чаще называют собакой @? Кроме того, в каждом адресе электронной почты есть по крайней мере одна точка.
Следующая программа последовательно проверяет наличие в строке знака "@" и точки.

#include<stdio.h>
#include<string.h>
#include<conio.h>

void main()
{
char *ptr;

char email[256];

int flag = 0;

printf("Введите E-mail: ");
scanf("%s", email);

ptr = (char *)memchr(email, '@', strlen(email));

if(!ptr) flag = 1;

ptr = (char *)memchr(email, '.', strlen(email));

if(!ptr) flag = 1;


if(flag) {

printf("\n%s не является E-mail адресом", email);

}
else {
printf("\nE-mail адрес: %s успешно введён!", email);

}

getch();

}

Переменная flag - своеобразный выключатель, который имеет два состояния "истина" и "ложь". Такие переменные программисты часто так и называют "флагами" или "флажками". Они обозначают состояние. Первоначально переменная flag = 0. Но если программа не обнаруживает в строке знака "@" или точки, значение flag поменяется на 1. Условий может быть и больше (например, мы могли бы проверить, есть ли какие-то символы до знака "@" и находится ли точка после знака @, а не до него), однако работать они будут по тому же принципу.
В конце программы проверяется значение переменной flag, и если она изменила своё значение, E-mail адрес признаётся некорректным.
При разработки больших программ подобные проверки необходимо производить буквально на каждом шагу, они делают программу более надёжной и отказоустойчивой, страхуя нас от недопустимого типа данных. Согласитесь, если мы попытаемся отправить письмо на некорректный адрес, приятного в этом будет мало! Однако во избежание увеличения кода, мы заключим процедуру проверки адреса в маленькую проверочную функцию вида:

int IsEmail(char *email)

которая будет возвращать 0, если E-mail адрес был введён недостаточно корректно.

Часто производители программного обеспечения требуют регистрации и предлагают пользователю заполнить форму, в которой в том числе есть просьба указать электронный адрес. Знать ваш E-mail адрес производителю жизненно важно, чтобы впоследствии заваливать вас своей рекламой. Поэтому если вы введёте свой адрес неправильно или вообще проигнорируете эту просьбу, электронная форма откажется вас регистрировать.

Функция поиска в строке незаменима при работе с файлами (а храним мы данные именно в них - лучшего пока ничего не придумали). Есть и другие применения поиска: когда программа предлагает пользователю сохранить файл, с которым он работал, необходимо ввести его имя. Однако пользователи попадаются с совершенно разным профессиональным уровнем: кто-то вводит имена файлов с расширениями: "picture.bmp", а кто-то и не знает, что такое расширение. Нужно предусмотреть оба случая, и в случае, если пользователь просто ввёл имя: "моя картинка!!!!" добавить к этому имени расширение. Пример решения этой проблемы приведён ниже.

#include<stdio.h>
#include<string.h>
#include<conio.h>

void main()
{
char *ptr;

char filename[256];

printf("Введите имя файла: ");
scanf("%s", filename);

ptr = (char *)memchr(filename, '.w', strlen(filename));


if(ptr == 0){

strncat(filename, ".bmp", 4);
}

printf("\nИмя файла: %s", filename);


getch();

}


Вопрос: КАК сравнить две строки?

Часто, когда вы получаете от пользователя не числовые данные, а строковые, вам надо сравнить строку с уже имеющимся эталоном. Допустим, вы хотите, чтобы пользователь зарегистрировал свою версию вашей программы и ввёл пароль. Для этого и нужна функция сравнения строк strncmp(). Она возвращает ноль, если строки одинаковы.

Следующая ниже программа вполе функциональна. Она ни за что не пропустит построннего на ваш компьютер. При желании, вы можете включить её в файл autoexec.bat. Доступ посторонним будет закрыт навеки! (Конечно если вы всё ещё пользуетесь Windows 98).

#include <stdio.h>
#include <string.h>

int main()
{

char *password="BUSH"; //наш пароль
char enter[256]; //строка, которую будет вводить пользователь

int ptr;

do {
printf("Введите пароль: ");
scanf("%s", enter);

//сравниваем две строки по всей длине
ptr = strncmp(enter, password, strlen(password));

//если строки одинаковы
if (ptr == 0)
{
printf("Доступ открыт");
return(0);
}

else{
printf("Введён неверный пароль!");

}
}while(ptr!=0); //цикл повторяется, пока ptr не будет =0.
return 0;
}

Конечно в реальности никто не будет прописывать пароль в коде программы, иначе мало-мальски грамотный хаккер запросто его оттуда "достанет". Настоящие программы генерируют пароль из имени пользователя, таким образом, чтобы пароли никогда не повторялись. Также популярна онлайн регистрация, при которой пользователь получает пароль, регистрируясь на сайте фирмы. Получив такой пароль, программа преобразует его по сложному алгоритму и проверяет на соответствие какому-то правилу - например сумма кодов символов должна всегда быть равна 100 (или что-то в этом роде). Дружеский совет - никогда не давайте "говорящие" пароли, как в данном примере. Такие пароли разгадываются элементарно, путём простого перебора символов. Хороший пароль должен содержать цифры и буквенные символы разного регистра, также неплохо было бы включить в него специальные символы. В результате должно получиться нечто вроде: "$&weh!60Om17rv".

* * *

Подытожим. Мы освоили достаточно операций для работы со строками. Их хватит на первый и на второй случай. Если же вам понадобится что-то большее, читайте описания функций библиотеки string.h. В справочной системе.

Назад Содержание Вперёд