Слайд 1Технологии программирования
Доц. каф. «Медиаменеджмента и медиапроизводства» Евич Л.Н.
Слайд 2Лекция 8. Строки в С++.
Строка в C++ — это массив
символов, заканчивающийся нулевым символом (‘\0’). Строка доступна через указатель на
первый символ в строке. Значением строки является адрес ее первого символа.
Исторически символ занимает 1 байт, в этом случае он имеет тип char.
При этом существуют и другие кодировки, в которых символ представляется, например, двумя байтами. Для работы с такими строками требуются специальные функции.
Слайд 3Лекция 8. Строки в С++.
Между однобайтными и фиксированными многобайтными
строками принципиальной разницы нет. В С/С++ существует специальный тип для
многобайтных символов - wchar_t и специальные функции для работы со строками, состоящими из таких символов.
Размер wchar_t не фиксирован в стандарте и определяется реализацией компилятора. На многих платформах и компиляторах это два байта, соответствующих кодировке Unicode.
Слайд 4Лекция 8. Строки в С++.
Символы
Символьная переменная — это переменная типа
char, занимающая в памяти 1 байт. В отличие от строк,
символ — это встроенный интегральный тип в С/C++, для него допустимы все операции, допустимые для интегральных типов.
Существуют символьные литералы, они записываются в одинарных кавычках (прямых апострофах). Пример символьного литерала:
char sym;
sym='A'; //Символьный литерал. Его значение – код символа А(латинское) в используемой кодировке
В вышеприведенном примере значением sym является 65 в кодовой таблице ASCII. В этом случае строка sym=’A’ абсолютно эквивалентна строке sym=65. Однако, в целях улучшения портируемости лучше всегда использовать запись в апострофах
Слайд 5Лекция 8. Строки в С++.
Для записи символьных литералов типа wchar_t
используется запись, аналогичная записи для строковых литералов этого типа:
wchar_t sym;
sym=L'ab';
//Символьный многобайтовый литерал. Количество символов между апострофами зависит от размера типа wchar_t
Существует специальный формат для записи символьных литералов – слеш, за которым идет код символа. Такая форма записи необходима, если мы хотим использовать элемент, не отображающийся в печатный символ, например нуль-терминатор, который представляется так: ’\0’.
Слайд 6Лекция 8. Строки в С++.
ПРИМЕЧАНИЕ
В фрагменте
char sym1;
char sym2;
char sym3;
sym1=0;
//(1)
sym2='\0'; //(2)
sym3='\0x00'; //(3)
строки (1), (2) и (3) имеют один и
тот же эффект. Однако вторая и третья запись считаются нагляднее – мы сразу видим, что работаем именно с символом.
Не путайте ‘\0’, ‘0’ и “0”. Первое – символьный литерал, соответствующий символу с кодом 0. Второе – такой же литерал, но обозначающий цифру 0, ее код в ASCII-кодировке 48. Третий — это строковый литерал, содержащий два символа, цифру 0 и нуль-терминатор.
Слайд 7Лекция 8. Строки в С++.
Создание строк
В С++ существует 2 типа
строк.
Первый из них - это массив переменных типа char.
Например:
char name[50]; cin>>name; cout<<"Hello "<
Второй из вариантов, более удобный - это специальный класс string
Для его работы необходимо в начале программы подключить заголовочный файл string:
#include
Слайд 8Лекция 8. Строки в С++.
Объявление строк
char str1[10]; // Строка -
массив из 10 символов. Начальное значение символов не определено.
char str2[10]="Hello";
/*
Используется инициализация (не присваивание!). В первые 5 символов записывается “Hello”, в 6 – нуль-терминатор, значение трех последних не определено.*/
char str3[10]={'H', 'e', 'l', 'l', 'o', '\0'}; //Эквивалентно предыдущему.
Слайд 9Лекция 8. Строки в С++.
Объявление строк
char str4[10]="Very long line"; //Ошибка.
Массив из 10 элементов нельзя инициировать более длинной последовательностью.
char str5[]="Very
long line"; /*Компилятор автоматически определяет длину массива (в нашем случае 15) и инициализирует его последовательностью символов. */
char* str6;
/*Строка - указатель на символ. В большинстве случаев для ее использования
потребуется выделить память.*/
str6=(char*) malloc(10);
free(str6);
Слайд 10Лекция 8. Строки в С++.
Примеры неверных присваиваний.
Пример 1.
char str1[10], str2[10];str1="Hello";str2=str1;
//Одна
и та же ошибка в обоих операторах =.
//Имя массива
нельзя использовать в левой
//части оператора присваивания.
//Ошибка приводит к сбою на этапе компиляции
Слайд 11Лекция 8. Строки в С++.
Примеры неверных присваиваний.
Пример 2.
char str1[10]= "Hello";char*
str2;str2=str1;str2[1]='u';
// Возможно имеется идеологическая ошибка. Неправильно полагать, что в
str2 теперь содержится копия str1. Указатель указывает не на копию, а на ту же самую строку. При любом изменении содержимого str2 изменяется str1.
Слайд 12Лекция 8. Строки в С++.
Особенности ввода/вывода строк
Строку можно присвоить массиву,
используя операцию cin — взять из потока. Из потока считываются
символы пока не встретится пробел, символ табуляции, символ новой строки или указатель конца файла.
Пример:
char str[10];
cin>>str;
При этом длина вводимой строки не может быть более 9 символов, чтобы оставить место для завершающего нулевого символа.
Слайд 13Лекция 8. Строки в С++.
Для ввода строк, состоящих из нескольких
слов, в одну строковую переменную, используют методы getline или get
класса istream.
cin.get(char *_Str, int _Count, char _Delim);
cin.getline(char *_Str, int _Count, char _Delim);
где:
_Count – количество считываемых символов.
_Delim – символ разделитель, останавливающий ввод, если он встретится до того как будет введено _Count-1 символов. По умолчанию он равен ‘\n’. Символ разделитель удаляется.
_Str – строка, в которую записываются считываемые символы.
Слайд 14Лекция 8. Строки в С++.
Пример 1:
#include ;
#include ;
using namespace std;
void main() {
char str[10];
cin.getline(str,10);
cout << str;
_getch();
}
Слайд 15Лекция 8. Строки в С++.
Пример 1_1:
#include ;
#include ;
using namespace std;
void main() {
char str[10];
cin.get(str,10);
cout << str;
_getch();
}
Слайд 16Лекция 8. Строки в С++.
Удобным способом определить размер массива является
использование оператора C++ sizeof:
сin.getline(str, sizeof(str));
Пример 2:
#include ;
#include ;
using
namespace std;
void main() {
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout << "str1: " << str1 << endl;
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
_getch();
}
Слайд 17Лекция 8. Строки в С++.
Результат работы программы
При первом вызове функции
get() для второго параметра установлено значение 10, третий параметр по
умолчанию устанавливается как символ разрыва строки (\n).
Если символ разрыва строки (\n) повстречается раньше, чем будет введен последний допустимый символ строки, функция вставит в этом месте концевой нулевой символ, но символ разрыва строки при этом останется в буфере и будет считан очередной функцией ввода.
Слайд 18Результат работы программы
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
Слайд 19Результат работы программы
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
Слайд 20Результат работы программы
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
Слайд 21Результат работы программы
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
если введено более 9-ти символов, то функция get() оборвет ввод строки после прочтения из буфера 9 символов, после чего добавит концевой нулевой символ (\0). При этом остальные введенные символы остаются в буфере
Слайд 22Результат работы программы
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
Слайд 23 char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
Слайд 24 char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.get(str3,sizeof(str3));
cout << "str3" << str3 << endl ;
Для очистки буфера, перед вызовом функции get() будем вызывать функцию ignore()
Функция ignore() определена в классе istream:
istream& istream::ignore(streamsize n=1, int delim=EOF);
Эта функция извлекает из потока и отбрасывает: либо streamsize символов (по умолчанию n=1), либо все символы, пока в потоке не встретится символ, заданный параметром delim.
Слайд 25Пример 2_1
#include ;
#include ;
using namespace std;
void main() {
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
<< "str1: " << str1 << endl;
cin.ignore(255,'\n');
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.ignore(cin.rdbuf() -> in_avail());
cin.get(str3,sizeof(str3));
cout << "str3: " << str3 << endl ;
_getch();
}
В строке 8 мы указали количество символов (255), которое, как мы полагаем, может находиться в буфере.
Слайд 26Пример 2_1
#include ;
#include ;
using namespace std;
void main() {
char str1[10], str2[10], str3[10];
cin.get(str1,10);
cout
<< "str1: " << str1 << endl;
cin.ignore(255,'\n');
cin.get(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.ignore(cin.rdbuf() -> in_avail());
cin.get(str3,sizeof(str3));
cout << "str3: " << str3 << endl ;
_getch();
}
В строке 11 в качестве первого параметра функции ignore() указано значение соответствующее размеру буфера.
Слайд 27streambuf* istream::rdbuf() const;
streamsize streambuf::in_avail();
Функция rdbuf()возвращает указатель на строковый буфер для
текущего строкового потока.
Функция in_avail(), принадлежащая классу streambuf, возвращает количество
символов, содержащихся в буфере.
Вызов функции
cin.ignore(cin.rdbuf()->in_avail());
позволит очистить буфер от содержащихся в нем символов.
Слайд 28Cтроку
cin.ignore(cin.rdbuf()->in_avail());
можно так же записать в виде
cin.ignore(numeric_limits::max(),'\n');
В этом случае в
качестве первого параметра функции ignore() указано значение соответствующее размеру буфера.
Класс
numeric_limits описывает арифметические свойства встроенных числовых типов.
numeric_limits<тип>::max — Возвращает максимально допустимое конечное значение для типа, указанного в треугольных скобках. Например, numeric_limits::max() возвращает максимально допустимое значение типа int.
Слайд 29Пример 2_1
#include ;
#include ;
using namespace std;
void main() {
char
str1[10], str2[10], str3[10];
cin.getline(str1,10);
cout
endl;
cin.getline(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.getline(str3,sizeof(str3));
cout << "str3: " << str3 << endl ;
_getch();
}
Слайд 30Пример 2_1
#include ;
#include ;
using namespace std;
void main() {
char
str1[10], str2[10], str3[10];
cin.getline(str1,10);
cout
endl;
cin.getline(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.getline(str3,sizeof(str3));
cout << "str3: " << str3 << endl ;
_getch();
}
Слайд 31
cin.getline(str1,10);
cout
"str2: "
<< str3 << endl ;
Здесь программа прекращает выполнение при попытке ввода данных. Если функция getline извлекает str.max_size элементов, то она вызывает функцию SetState (ios_base :: failbit). Функция setstate(state) устанавливает флаги, содержащиеся в state.
Слайд 32Состояния потока и их значения (фаги)
Слайд 33Функции для работы с состоянием потока данных
Слайд 34При вызове функции clear() без параметров сбрасываются все флаги ошибок
(в том числе и eofbit):
// Сброс всех флагов ошибок (включая
eofbit) strm.clear();
Если функция clear() вызывается с передачей параметра, то состояние потока данных изменяется в соответствии с переданным значением; переданные флаги устанавливаются для потока данных, а остальные флаги сбрасываются.
У этого правила есть единственное исключение: при отсутствии потокового буфера (когда rdbuf()==0) флаг badbit устанавливается всегда.
Слайд 35Для того чтобы осуществить ввод следующей строки с помощью функции
getline() необходимо сбросить флаг и очистить буфер. Очистка буфера
может быть осуществлена, например, с помощью функции fflush(stdin).
int fflush(FILE *stream) —
Если stream связан с файлом, открытым для записи, то вызов fflush() приводит к физической записи содержимого буфера в файл. Если же stream указывает на вводимый файл, то очищается входной буфер. В обоих случаях файл остается открытым.
Возврат 0 означает успех, а возврат ненулевой величины указывает на наличие ошибки по записи.
Слайд 36Пример 3
#include ;
#include ;
using namespace std;
void main() {
char
str1[10], str2[10], str3[10];
cin.getline(str1,10);
cout
endl;
cin.clear();
fflush(stdin);
cin.getline(str2,sizeof(str2));
cout << "str2: " << str2 << endl ;
cin.clear();
fflush(stdin);
cin.getline(str3,sizeof(str3));
cout << "str3: " << str3 << endl ;
_getch();
}
Слайд 37Альтернативные функции ввода-вывода данных
Если нужно считать в буфер определенное количество
символов, не разбираясь, есть ли там переводы строк или нет,
то следует воспользоваться функцией
read(),
а затем с помощью другой функции,
gcount(),
определить, сколько именно символов удалось прочесть:
Слайд 38Пример
char buf[1024];
int chars_read;
cin.read(buf, sizeof(buf));
chars_read = cin.gcount();
Функции
put() для
вывода одного символа;
write() запишет в выходной поток sizeof(buf)
символов.
Слайд 45Пример 4
Дана строка символов. Составить программу, которая подсчитывает, сколько
раз среди данных символов встречается пробел.
#include ;
#include ;
using namespace std;
void main() {
char strR[255], ch;
int k=0;
cout << "vvedite stroku \n";
cin.get(strR,sizeof(strR));
for (int i=0;i<=strlen(strR);i++)
if (strR[i]==' ') k++;
cout << "v stroke \"" << strR << "\" sodergitsja "< " probelov"< _getch();
}
Слайд 46#include ;
#include ;
using namespace std;
void main() {
char
strR[255], ch;
int k=0;
cout
stroku \n";
cin.get(strR,sizeof(strR));
for (int i=0;i<=strlen(strR);i++)
if (strR[i]==' ') k++;
cout << "v stroke \"" << strR << "\" sodergitsja "< " probelov"< _getch();
}
Слайд 47Пример 5
Дана строка символов и слово. Составить программу, которая
после каждого слова этой строки, введенное слово.
//копирование первого слова в
новую переменную
//в исходной переменной оставляем все слова кроме первого.
#include ;
#include ;
using namespace std;
void main() {
char str1[255], s[40];
cout << "vvedite stroku \n";
cin.get(str1,sizeof(str1));
s[0]='\0';
if (strcspn(str1," ")!=NULL)
strncat(s,str1,strcspn(str1," "));
strcpy(str1,strchr(str1,' ')+1);
cout << "stroka1:”<< str1 <<" str2:"< _getch();
}
Слайд 48
//копирование первого слова в новую переменную
//в исходной переменной оставляем
все слова кроме первого.
#include ;
#include ;
using namespace std;
void main()
{
char str1[255], s[40];
cout << "vvedite stroku \n";
cin.get(str1,sizeof(str1));
s[0]='\0';
if (strchr(str1,' ')!=NULL)
strncat(s,str1,strcspn(str1," "));
strcpy(str1,strchr(str1,' ')+1);
cout <<"stroka1:"< _getch();
}
Слайд 49
#include ;
#include ;
using namespace std;
void main() {
char str1[255], str2[20], s[40];
cout
\n";
cin.get(str1,sizeof(str1));
cout << "vvedite slovo \n";
cin.get(str2,sizeof(str2));
s[0]='\0';
if (strcspn(str1," ")!=NULL) {
strncat(s,str1,strcspn(str1," "));
strcat(s," "); strcat(s,str2); strcat(s," ");
strcpy(str1,strchr(str1,' ')+1);
}
cout << "stroka1:" << str1 << " str2:"< _getch();
}
Слайд 50#include ;
#include ;
using namespace std;
void main() {
char
str1[255], str2[20], s[40];
cout
cin.get(str1,sizeof(str1));
cin.ignore(255,'\n');
cout << "vvedite slovo \n";
cin.get(str2,sizeof(str2));
cin.ignore(255,'\n');
s[0]='\0';
while (strchr(str1,' ')!=NULL)
if (strchr(str1,' ')!=NULL) {
strncat(s,str1,strcspn(str1," "));
strcat(s," "); strcat(s,str2); strcat(s," ");
strcpy(str1,strchr(str1,' ')+1);
cout << "stroka1:" << str1 << " str2:"< }
strcat(s,str1);
cout << "stroka1:" << str1 << " str2:"< _getch(); }
Слайд 51#include ;
#include ;
using namespace std;
void main() {
char
str1[255], str2[20], s[40];
cout
cin.get(str1,sizeof(str1));
cin.ignore(255,'\n');
cout << "vvedite slovo \n";
cin.get(str2,sizeof(str2));
cin.ignore(255,'\n');
s[0]='\0';
while (strchr(str1,' ')!=NULL)
if (strchr(str1,' ')!=NULL) {
strncat(s,str1,strcspn(str1," "));
strcat(s," "); strcat(s,str2); strcat(s," ");
strcpy(str1,strchr(str1,' ')+1);
cout << "stroka1:" << str1 << " str2:"< }
strcat(s,str1);
cout << "stroka1:" << str1 << " str2:"< _getch(); }
Слайд 52Задания для самостоятельной работы
60. Составьте программу, которая запрашивает имя
человека и выводит на экран это имя с приветствием.
61. Дана
строка, состоящая не менее чем из двух символов. Составьте программу, которая выводит на экран предпоследний символ.
62. Даны натуральное число n и строка символов. Составьте программу,
которая определяет, верно ли, что в строке имеются n подряд идущих пробелов.
63. Даны натуральное число n и строка символов. Составьте программу,
которая копирует первые n символов из исходной строки в новую. Если n больше длины строки, то строка копируется целиком.
64. Дана строка символов, содержащая слова, то есть
группы символов, разделенные пробелами (не менее одного). Составьте программу, которая определяет, сколько начальных букв первого слова совпадает с начальными буквами второго слова.
65. Дана строка символов. Составьте программу, которая исключает из строки группы символов, расположенные между скобками, например, круглыми. Скобки тоже исключить. Предполагается, что внутри пары скобок других скобок нет.
Лекция 8. Строки в C++.
Слайд 53Задания для самостоятельной работы
Дана строка символов, содержащая слова, то есть
группы символов, разделенные пробелами (не менее одного). Составьте программу,
которая находит длину самого короткого слова..
Дана строка символов. Составьте программу, которая выясняет, верно ли, что в данной строке больше букв, чем цифр.
Дана строка символов, состоящая из n (n>=20) символов. Составьте программу, которая переставляет в обратном порядке символы, расположенные между k-й и m-й буквами. Значения k и m вводятся с клавиатуры (k
Дана строка символов, содержащая слова, то есть группы символов, разделенные пробелами (не менее одного). Составьте программу, которая выводит на экран все слова, встречающиеся в исходной строке ровно один раз.
Даны строки символов. Составьте программу, которая определяет, можно ли из символов первой строки составить вторую строку.
Лекция 8. Строки в C++.
Слайд 54Задания для самостоятельной работы
71. На вход программы подаются сведения о
набранных на ЕГЭ баллах учениками данной школы по трём предметам.
В первой строке сообщается количество учащихся N (N<100), каждая из следующих N строк имеет формат: <Фамилия> <Инициалы> <БаллыПоРусскомуЯзыку> <БаллыПоМатематике> <БаллыПоИнформатике>, где <Фамилия> -- строка, состоящая не более чем из 20 символов, <Инициалы> --- строка, состоящая из 4-х символов (буква, точка, буква, точка), <БаллыПоРусскомуЯзыку>, <БаллыПоМатематике>, <БаллыПоИнформатике>~--- целые числа в диапазоне от~0 до~100. Все элементы одной строки отделены друг от друга пробелом.
Пример входной строки:
Петров С.Н. 78 82 70
Требуется написать как можно более эффективную программу, которая
будет выводить на экран фамилии и инициалы учеников, набравших
максимальную сумму баллов по трём предметам (таких учеников может
быть несколько), а также набранную ими сумму баллов.
Лекция 8. Строки в C++.