Строки в Borland C++ 3.1 как таковые отсутствуют. Для их обработки программисты, пишущие программы для операционной системы MS-DOS, часто используют указатель на область памяти или массивы символов. Для многих начинающих перспектива работы с указательными переменными может казаться неудобным способом обработки и пугающим примером для обучения, отчего может происходить некоторый дискомфорт. На самом деле любая строка представляет из себя одномерный массив символов с некоторыми особенностями.
От обычного массива строку отличает наличие признака конца строки.
Признак конца строки помогает обрабатывать символьные массивы не как массивы, а как строки. Основной массив разбивается на две половины: строка и мусор. А делится массив именно признаком.
Выглядит это так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//clang C++ Знакомство с Си-строками Листинг #1
#include <iostream>
usingnamespacestd;
intmain(){
constintN=10;
charS[N]="HELLO";
/*Работа как с полным массивом*/
for(inti=0;i<N;i++){
cout<<i<<") "<<S[i]<<'\n';//Обходим массив полностью
}
cout<<'\n';
/*Работа с массивом как со строкой*/
for(inti=0;S[i]!=0;i++){
cout<<i<<") "<<S[i]<<'\n';
}
}
При работе программы вы можете увидеть, что при работе с массивом как со строкой не трогается часть массива. Это получается благодаря признаку окончания строки, нуль-символу. Если не путать число ноль и символ ноль, то вы легко поймёте этот ограничитель. Символы заключаются в одинарные кавычки, а число пишется как оно есть.
В Си-строках признаком окончания строки служит символ с нулевым ASCII кодом, в примере в качестве этого символа использовалось число 0
С массивами обычно возникает не так много проблем. Первая проблема, характерная проблема новичков, возникает при работе с указателями на символьные массивы. Проблема эта возникает из-за неявных, невидимых нам, преобразований, из-за которых мы часто не понимаем, что вообще происходит.
В С++ правилами языка оговорено, что любому массиву можно задавать количество ячеек только неизменяемым значением, т. е. нужно задавать константу непосредственно в исходном коде. Из-за этого ограничения нельзя ввести число ячеек, используя клавиатуру, во время работы программы. Хоть некоторые компиляторы и позволяют такое проворачивать, это всё специфическое поведение отдельных компиляторов, как минимум изменить вы однажды введённое число ячеек в обычный массив — не сможете. Из-за такой ситуации, люди, пишущие низкоуровневые коды, использующие в С++ Си-стиль, применяют указатели на массивы. Указатели дают возможность задавать количество ячеек в ходе работы программы на законных основаниях. Хотя вы и не сможете без дополнительных усилий изменить первозаданное количество ячеек в массиве в ходе работы программы. Конечно можно говорить о динамических массивах, но мы, новички, пока что разбираем примитивные массивы, поэтому такие штуки, как векторы — не оговариваются.
Указательная переменная, указывающая на символьный массив, может обрабатываться как строка.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Borland C++ 3.1 Указатель на символьную строку Листинг #2
#include <iostream.h>
#include <conio.h>
intmain(){
clrscr();
char*S="HELLO";//Указатель на символьную строку
cout<<S<<'\n';
S="My name is C++";//Легко присваивается литеральная строка
cout<<S<<'\n';
S="How are you?";//Легко присваивается литеральная строка
cout<<S;
cin.get();
}
Литеральная строка — это такая строка, которая представляет собой значение для переменной, но описывается прямым текстом непосредственно в исходном коде программы.
С одной стороны кажется, что всё ОК, что всё работает. Трудно предвидеть, что попытки ввода строки посредством клавиатуры, и использование показанного подхода будут ломать программу. Попробуйте записать значение в S, используя cin, запустить программу и проверить работу.
Если всё сделали правильно, то программа у вас, наверное, сломалась.
Здесь дело в том, что вы пытаетесь изменить неизменяемую строку. Из-за некоторых не очень приятных фокусов компиляторов С++, вам неочевидно, что указатель указывает на неизменяемое значение. Трудно новичкам объяснить это чудо-юдо, но можно заставить взять за правило, что если работаешь с указателем на строку, то выдели указателю памяти вручную. В случае ручного выделения указателю памяти программа чудить не станет, останется только не забыть очистить память в конце работы.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Borland C++ 3.1 Ручное выделение памяти для строки Листинг #3
#include <iostream.h>
#include <conio.h>
intmain(){
clrscr();
char*S=newchar[255];//Имитация строки в 255 символов
cin>>S;//Чтение слова
cout<<S<<'\n';//Вывод слова на экран
cin.get();
delete[]S;//уборка за собой
cin.get();
}
Такой код более практичен, да и вводить значения в ходе работы программы куда интереснее, чем задавать их непосредственно в исходном коде. Этот ввод значений в ходе работы программы стал возможен только из-за использования указательной переменной, для которой обязательно было выделено сколько-то памяти, сейчас 255 байт. 1 байт = 1 символ.
Несмотря на то, что ситуация стала выглядит лучше, всё на самом деле не очень здорово. Если вы пытались ввести строку с пробелами, то могли увидеть факт того, что строка режется. Запоминается только часть строки, идущая до первого пробела. Это происходит из-за операции >>, которую использует объект cin. Работа со строковыми данными и работа с численными данными в целом сильно отличается, поэтому для работы со строками существует множество специальных строковых функций. У объекта cin есть специальный метод работы со строковыми данными, метод getline. Этому методу нужно подсказать, с какой переменной нужно работать и длину строки.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Borland C++ 3.1 Ввод строк c пробелами посредством клавиатуры Листинг #4
#include <iostream.h>
#include <conio.h>
intmain(){
intN=255;
char*S=newchar[N];//Имитация строки в 255 символов
cin.getline(S,N);//Ввод строки с клавиатуры
cout<<S<<'\n';
cin.getline(S,N);//Ввод строки с клавиатуры
cout<<S<<'\n';
delete[]S;
}
При запуске программы просто введите какую-то строку и нажмите Enter.
По этому коду, листинг #4, могу сказать, что фактическое число символов как бы на один меньше заявленного. Не забывайте, что в таких строках есть специальный символ, который обозначает признак конца строки, вот одна ячейка для него должна быть броня, из-за неё и считаем, что символов в строке на один меньше заявленного. Вовнутрь getline передалась S и длина, нужная S. Вот и всё. getline позволили запомнить вводимое с клавиатуры значение в памяти компьютера.
Приведу пример решения одной из очень простых задач: подсчитать число пробелов в строке, введённой с клавиатуры.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Borland C++ 3.1 Ввод строки с клавиатуры и подсчёт пробелов Листинг #5
#include <iostream>
#include <conio.h>
intmain(){
intN=255;
char*S=newchar[N];//Имитация строки в 255 символов
intcount_space=0;//Число пробелов
cin.getline(S,N);
cout<<S<<'\n';
/*СЧИТАЕМ ПРОБЕЛЫ*/
for(inti=0;S[i]!=0;i++){
if(S[i]==' ')count_space++;//Если элемент массива пробел, накручиваем счётчик
}
/*КОНЕЦ ПОДСЧЁТА*/
cout<<count_space<<'\n';
cin.get();
delete[]S;
}
В показанном коде идёт простой обход массива, но анализ границы происходит по признаку окончания строки. В противном случае можно обойти мусор, в котором могут оказаться пробелы, и получить неправильный результат. В противном — это если обходить массив полностью.
Ещё можно использовать функцию gets. Но она опаснее cin.getline:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Borland C++ 3.1 Строки Ввод gets Листинг #6
#include <iostream.h>
#include <stdio.h> //Для gets
intmain(){
intN=15;
char*S=newchar[N];//Имитация строки в 255 символов
intcount_space=0;//Число пробелов
cout<<"input S: ";
gets(S);//Ввод с помощью gets
cout<<S<<'\n';
delete[]S;
}
Хоть ввод с помощью gets и выглядит проще, на самом деле он очень опасен. Попробуйте в коде задать указатель на строку в два символа, а при вводе строки во время работы прораммы введите какую-нибудь длинную строку. gets не отслеживает выход за пределы массива, поэтому ичего хорошего от предложенных мной вам действий ждать не стоит. В общем gets — это один из самых опасных способов взаимодействия со строкой/массивом.
3 комментария на «“Строки String в Borland C++ 3.1 для начинающих”»
cin.getline(S,maxL);//Вводим строку с клавиатуры и присваиваем её в S
нужно переписать
C++
1
gets(S);//Вводим строку с клавиатуры и присваиваем её в S
Автор сайта отвечает:
)))
а еще нужно убрать iostream и вместо cout использовать printf
а еще нужно забыть про С++, потому как это уже язык С
============================================
Так не то, чтобы нужно, но можно. Хотя вы можете аргументировать. Я спорить не буду.
Я скажу свои аргументы:
мешать С++ и С нехорошо. (хотя и есть задачи, решаемы только с помощью С)
я почти во всех своих статьях использую объекты cin и cout. У них есть свои методы. Их я тоже часто использую в материалах.
для современных компиляторов (например используемом в CodeBlocs) вообще нужно использовать тип данных string, а там чтение
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <string>
intmain()
{
std::stringS;
std::getline(std::cin,S);
std::cout<<S;
return0;
}
и над вашим комментарием написано про gets, оно там и было написано (я не сейчас добавил).
Это не лично к вам (Gen). Это к тем, кто поймет не так как нужно вашу подсказку.
все то хорошо, только в 8 студии этот cin.getLine() не ждет пока юзер введет что-то с консоли
void main()
{
char c; char s[15];
while(1==1) {
cout<>c;
if (c==’0′) break;
cout<<"vvesti text <=50\n";
cin.getline(s, 50);
cout <<s;
}
может надо очистка вх потока flush(stdin)?
Автор сайта отвечает:
Я вас вообще сейчас не понял. Поконкретнее можете истолковать?
судя по вашему коду вам нужен массив строк, но cin.getline читает только одну, а не много. И вы видите в этом проблему. (это единственное, что я могу предположить)
Имхо, не стоит использовать функцию gets(). Про неё вообще лучше забыть. Она не проверяет нарушение границы массива/строки, и более опасного вызова, чем этот, в стандартной библиотеке нет.
Вместо gets() можно (и нужно) использовать fgets() (ну или gets_s() в новом стандарте Си).
При использовании gets строку
нужно переписать
все то хорошо, только в 8 студии этот cin.getLine() не ждет пока юзер введет что-то с консоли
void main()
{
char c; char s[15];
while(1==1) {
cout<>c;
if (c==’0′) break;
cout<<"vvesti text <=50\n";
cin.getline(s, 50);
cout <<s;
}
может надо очистка вх потока flush(stdin)?
Имхо, не стоит использовать функцию gets(). Про неё вообще лучше забыть. Она не проверяет нарушение границы массива/строки, и более опасного вызова, чем этот, в стандартной библиотеке нет.
Вместо gets() можно (и нужно) использовать fgets() (ну или gets_s() в новом стандарте Си).