
- •Лекция 13
- •Основные понятия
- •Операции со строками
- •Инициализация строки
- •Возможные ошибки при работе со строками
- •Ввод-вывод строк
- •Преобразование значения базового типа в с-строку
- •Ввод ограниченного числа символов строки
- •Функция вывода строки
- •Особенности посимвольного вывода строки
- •Копирование строк
- •Оптимизация текста программы на примере функции копирования
- •Функции для работы с с-строками
- •Определение длины строки
- •Копирование строк
- •Объединение строк
- •Сравнение строк
- •Поиск символа в строке
- •Проверка принадлежности символа некоторому множеству
- •Поиск строки в строке
- •Преобразование и заполнение строк
- •Преобразование строки в число
- •Преобразование числа в строку
- •Преобразование строчных символов строки в прописные и наоборот
- •Реверс строки
- •Заполнение строки символом
- •Пример применения функций преобразования
- •Выделение лексем
- •Динамические строки
- •Копирование строки в динамическую строку
- •Передача строки в функцию в качестве параметра
- •Пример_1: в main()– строка-массив; в функции – строка-указатель
- •Пример_2: в main() – строка-указатель; в функции – строка-указатель
- •Передача в функцию массива строк
- •Примеры работы со строками Определение длины строки с помощью функции пользователя
- •Реверс строки (перегрузка функций)
- •Удаление начальных пробелов из строки
- •Проверка, является ли строка целым числом
- •Проверка, является ли строка 16-ичным целым числом
- •Проверка, является ли строка дробным числом без знака
- •Перевод двоичного числа в десятичное
- •Перевод шестнадцатеричного числа в десятичное
- •Перевод десятичного числа в двоичное
- •Перевод десятичного числа в с/с от 2-х до 10
- •Перевод десятичного числа в шестнадцатеричное
- •Определение количества слов в фразе
- •Выделение слов в тексте по нажатию произвольной клавиши
- •Сортировка вводимых с клавиатуры строк *
- •Сортировка строк в зависимости от признака, передаваемого функции main() через аргумент argv *
- •Инвертирование строки с помощью рекурсивной функции
Возможные ошибки при работе со строками
Основные ошибки при работе с С-строками происходят из-за отсутствия понимания специфики описания строк (строка-массив или строка-указатель)
//пример_4
int main ( )
{
char msg[10]; //определение строки-массива
//msg="hello"; // error!!! пытаемся изменить указатель-константу!!!
strcpy_s (msg, "hello"); //ok!!! заполнение строки копированием!!!
char *name; //определение указателя на char
//scanf ("%s", name); // error!!! место под строку-указатель не выделено!!!
name = (char*) malloc(10); // ok!!! присваивание указателю адреса динамической строки
// или name = new char[10];
printf ("name?");
scanf ("%s",name); //ввод строки, перед именем переменной не ставится символ &
// ввод выполняется до первого пробельного символа
printf ("%s%s", msg, name);
_getch();
return 0;
}
Так как имя строки-массива – это указатель-константа, то нельзя выполнить присваивание:
char array[20];
//array = "Literal of string"; // error!!!
Заполнить строку-массив можно с использованием функции копирования (что мы видели в примере: strcpy_s (msg, "hello");).
При использовании строки-указателя без ее инициализации, необходимо позаботиться о выделении места под строку в динамической памяти.
Ввод-вывод строк
Для ввода-вывода С-строк используются функции printf (),scanf (),gets() и puts(), унаследованные из библиотеки С. Функция gets(s) читает символы с клавиатуры, в том числе и пробелы (до символа новой строки), и помещает их в строку, завершая ее 0-символом; функция puts(s) выводит строку, заменяя 0-символ символом новой строки.
// С-ввод строки до первого пробельного символа
int main()
{
const int MAX = 80;
char str[MAX]; // строка-массив
printf ("Enter a string: ");
scanf ("%s", str); //odin_dwa адрес переменной здесь не указываем
printf("%s", str); //odin_dwa
printf(" %3s\n", str); //3 – минимальный размер поля вывода : odin_dwa
printf(" %10.2s\n", str); // od выравнивание вправо и 2 символа
printf(" %-10.2s\n", str); //od выравнивание влево и 2 символа
printf (" string?\n");
scanf ("%s", str); //вводим: odin dwa, но вводится только odin (до пробела)
printf (" %s\n", str); // в буфере ввода остался «хвост» dwa
//fflush (stdin); // для корректной дальнейшей работы scanf() // требуется очистка буфера ввода: fflush (stdin);
printf (" string?\n");
scanf ("%s", str);
printf (" %s\n", str);
_getch();
return 0;
}
// С-ввод строки с пробелами
int main()
{
const int MAX = 10;
char str[MAX]; // строка-массив
printf ("Enter a string: ");
gets(str); //ввод строки: odin dwa
puts(str); //вывод строки: odin dwa
_getch();
return 0;
}
//посимвольный ввод строки в стиле С
int main()
{
const int MAX = 10;
char str[MAX]; // строка-массив
printf ("Enter a string: ");
for (int i=0; i<MAX; i++)
scanf ("%c", &str[i]); //ввод символов 1234567899
str[MAX-1]='\0';
printf ("%s", str); //вывод строки 123456789
int i=0;
printf ("\nEnter a string: ");
while ( (str[i] = _getch() ) !=13 ) // или != ‘\r’ посимвольный ввод
_putch (str[i++]); // посимвольный вывод
str[i] = '\0'; //завершение строки
_putch ('\n'); _putch ('o'); _putch ('k');
printf ("\n%s", str); //вывод строки
_getch();
return 0;
}
Для ввода-вывода С-строк в стиле С++ используются известные нам объекты cin и cout.
//ввод строки до первого пробельного символа
int main()
{
const int MAX = 80;
char str[MAX]; // строка-массив
cout << "Enter a string: ";
cin >> str; //ввод строки
cout << "You entered: " << str << endl; //вывод строки
_getch();
return 0;
}
//посимвольный ввод строки
int main()
{
const int MAX = 10;
char str[MAX]; // строка-массив
cout << "Enter a string: ";
for (int i=0; i< MAX-1; i++)
cin >> str[i]; //ввод символов 1234567899
str[MAX-1]='\0';
cout << "You entered: " << str << endl; //вывод строки: 123456789
_getch();
return 0;
}
Для ввода любых символов, включая пробельные, используются методы get() и get(c) класса istream, объектом которого является cin:
char c, d, e;
c=cin.get(); //возвращается код извлеченного из потока символа или EOF
cin.get(d); //извлеченный из потока символ записывается в переменную-аргумент
cin.get(e);
//посимвольный ввод строки с использованием метода get()
int main()
{
const int MAX = 10;
char str[MAX]; // строка-массив
cout << "Enter a string: ";
for (int i=0; i< MAX-1; i++)
cin.get(str[i]); //ввод без пробелов символов 12345 9
str[MAX-1]='\0';
cout << "You entered: " << str << endl; //вывод строки 12345 9
_getch();
return 0;
}
Для ввода строки из нескольких слов используются методы getline() или get() объекта cin:
//ввод строки из нескольких слов с использованием метода getline()
int main()
{
const int MAX = 80;
char str[MAX];
cout << "\nEnter a string: ";
cin.getline (str, MAX); //ввод строки в str
//символ ‘\n’ считывается (удаляется) из потока ввода
//и вместо него в строковую переменную записывается ‘\0’
cout << "You entered: " << str << endl;
cin.get (str, MAX); // ввод строки в str
//символ ‘\n’ остается в потоке
//в строковую переменную добавляется ‘\0’
cout << "You entered: " << str << endl;
_getch();
return 0;
}
// ввод нескольких строк, завершающихся <enter>, в качестве одной строки
const int MAX = 2000;
char str[MAX];
int main()
{
cout << "\nEnter a string:\n";
cin.get(str, MAX, '$'); //ввод всех строк завершается символом $
cout << "You entered:\n" << str << endl;
_getch();
return 0;
}
В этом случае можно ввести несколько строк, завершающихся <enter>, и только затем набрать символ $ (все строки будут восприняты как одна строка):
Enter a string:
qwert
12345
qwert$
You entered:
qwert
12345
qwert
Обратите внимание на «плохую» работу метода get() при вызове его с двумя аргументами два раза подряд:
char s[10];
int n=5;
cin.get (s, n); //1 вводим 123<enter>,‘\n’остается в потоке ввода
cout << s << endl; //2 выводит 123
cin.get (s, n); //3 считывает пустую строку
cout << s << endl; //4 выводит пустую строку
cin.get (s, n); //5 считывает пустую строку
cout << s << endl; //6 выводит пустую строку
cout << "end" << endl; //7 выполняется!!!
Результат работы:
123
123
end
За выводом в операторе //2 сразу последует сообщение “end”, выведенное оператором //7. Это происходит из-за символа ‘\n’, оставленного в потоке ввода первым вызовом метода get(), т.е. оператором //1. Поэтому операторами //3 и //5 будут считаны (и, соответственно) выведены на экран пустые строки.
Удалить символ ‘\n’ из входного потока можно путем вызова метода get() без параметров cin.get():
char s[10];
int n=5;
cin.get (s, n); //1 вводим 123<enter>,‘\n’остается в потоке ввода
cout << s << endl; //2 выводит 123
cin.get (); //удаляем ‘\n’ из входного потока
cin.get (s, n); //3 вводим 234<enter>,‘\n’остается в потоке ввода
cout << s << endl; //4 выводит 234
cin.get (); //удаляем ‘\n’ из входного потока
cin.get (s, n); //5
cout << s << endl; //6
cout << "end" << endl; //7
Результат работы:
123
123
234
234
345
345
end
Еще лучше – использовать в таких случаях метод getline().
Следующий цикл обеспечивает ввод символов до нажатия ctrl+z – признака конца файла
char c;
while ((c=cin.get())!=EOF) { //ввод символов, выход из цикла – ctrl+z – признак конца файла
cout << c;
}
Для ввода нескольких С-строк можно использовать метод getline() в заголовке цикла:
int main()
{
const int n = 80;
char s[n];
while (cin.getline(s, n)) { //ввод строки в s, выход из цикла – ctrl+z – признак конца файла
cout << s << endl; //вывод строки
//………. обработка строки
}
_getch();
return 0;
}