Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Проблема с cin.getline()

Ответить
Настройки темы
C/C++ - Проблема с cin.getline()

Аватара для Chilli

Новый участник


Сообщения: 28
Благодарности: 2


Конфигурация

Профиль | Отправить PM | Цитировать


В некоторой части программы требуется ввести строку (включая пробелы), для чего я решил использовать cin.getline().
Код: Выделить весь код
char *text;
text=new char;
. . . . .
cin.sync();
cin.getline(text,sizeof(text));
OemToCharA(text,text);
cout<<text; // проверка
cin.sync();
cin.clear();
cin>>hz;
. . . . .
При таком раскладе из введенной строки выводятся первые 3 символа, остальное куда-то пропадает.
Если написать, к примеру, cin.getline(text,40); , т.е. ограничить строку до 40 символов включая символ перехода на след. строку, тогда никаких проблем нет.
Но задача состоит как раз таки в том, чтобы через cin.getline() вывести строку, размер которой, так сказать, динамический.
Я, конечно, подозреваю, что подобное невозможно без ограничения/декларации символьного массива, но все же - возможно ли решить такую проблему?

Отправлено: 21:53, 10-12-2010

 
pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Код: Выделить весь код
char *text; //1
text=new char; //2
(1) text имеет тип char* (указатель на char), его размер sizeof(text) = 4
(2) new char() вернёт указатель на 1 (!) символ. Попытка записи туда более 1 символа приведёт к порче разметки памяти.
basic_istream::getline считывает символы и складывает их в заранее выделенную память, поэтому на вход ему надо подсовывать столько памяти, во сколько уместится самая большая строка, которую хочешь прочитать. Размер строки можно потом узнать поиском нулевого символа '\0'.
Доставшаяся `C++` строка char* по наследству от `C` не умеет сама менять свой размер. Вместо этого нужно выделять новую память, копировать туда новое содержимое строки и удалять старую память.
Если тебе нужно такую строку, которая умеет менять свой размер, используй шаблон basic_string.
Код: Выделить весь код
#include <string>
using namespace std;

...

string text;
// в файле string определена глобальная функция
// getline(basic_istream<..>& source, basic_string<..>& dest, int char_delimiter='\n');
getline(cin, text);

cout << text << endl;
В различных версиях STL может быть по-разному, но как правило внутри string содержится char*, для которого сделано автоматическое управление памятью.
Это сообщение посчитали полезным следующие участники:

Отправлено: 10:54, 11-12-2010 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Аватара для ganselo

Старожил


Сообщения: 232
Благодарности: 90

Профиль | Сайт | Отправить PM | Цитировать


Цитата Chilli:
При таком раскладе из введенной строки выводятся первые 3 символа, остальное куда-то пропадает. »
siezof(text) возвращает 4, следовательно cin записывает 3 символа и плюс один на \0.

Цитата Chilli:
char *text; text=new char; »
вы динамически выделили память под 1 символ, а пытаетесь записывать строку.

Цитата Chilli:
Но задача состоит как раз таки в том, чтобы через cin.getline() вывести строку, размер которой, так сказать, динамический. »
Используйте класс std::string.

Код: Выделить весь код
#include <iostream>
#include <string>
using namespace std;

int main()
{
    string text;

    getline(cin, text);
    cout << text << endl;
}
Пока писал, pva опередил с ответом)

-------
К величайшему сожалению "история учит нас тому, что она ничему не учит".

Это сообщение посчитали полезным следующие участники:

Отправлено: 11:01, 11-12-2010 | #3


Аватара для Chilli

Новый участник


Сообщения: 28
Благодарности: 2

Профиль | Отправить PM | Цитировать


pva,
Цитата pva:
Код:
#include <string>
using namespace std;
...
string text;
// в файле string определена глобальная функция
// getline(basic_istream<..>& source, basic_string<..>& dest, int char_delimiter='\n');
getline(cin, text);
cout << text << endl; »
ganselo,
Цитата ganselo:
Код:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string text;
getline(cin, text);
cout << text << endl;
} »
О такой реализации я думал, но такие строки не прогнать через OemToChar(), что очень нужно, т.к. в дальнейшем предусматривается вариант вывода текста.
Но интересно то, что через cin>>text; строка будет записываться до пробела/символа перевода строки.
Собственно полный код:
Код: Выделить весь код
#include <iostream>
#include <Windows.h>

using namespace std;

struct students
{
	char *fio, *bk;
	int *mark;
	float pay;
	students *next;
};

struct group
{
	int num;
	students *st;
	group *NEXT;
};

void main()
{
	setlocale(0, "rus");
	group gr, *TOP, *P, *Q, *S;
	students *top, *p, *q, *s;
	int v;
	bool f, g=false, g1=false;
	char ch;

	do
	{
		cout<<"1) Добавить группу.\n2) Вывод.\n";
		cin>>v;
		switch (v)
		{
		case 1:
			if (g)
			{
				S=new group;
				Q->NEXT=S;
				Q=S;
			}
			else
			{
				TOP=Q=new group;
				g=true;
			}
			while (1)
			{
				f=false;
				cout<<"Введите номер группы: ";;
				cin>>Q->num;
				cin.sync();
				do
				{
					cout<<"Добавить студента? ";
					cin>>ch;
					cin.sync();
				}
				while (ch!='y' && ch!='n');
				if (g1)
				{
					s=gr.st=new students;
					q->next=s;
					q=s;
				}
				else
				{
					top=q=gr.st=new students;
					g1=true;
				}
				while (ch=='y')
				{
					f=true;
					q->fio=new char;
					q->bk=new char;
					q->mark=new int[5];
					cout<<"Введите имя студента: ";
					cin.getline(q->fio,41);
					cin.clear();
					cin.sync();
					OemToCharA(q->fio,q->fio);
					do
					{
						cout<<"Форма обучения: бюджет или контракт? ";
						cin>>ch;
						cin.sync();
						switch (ch)
						{
						case 'b':
							q->bk="Бюджет";
							break;
						case 'k':
							q->bk="Контракт";
							break;
						}
					}
					while (ch!='b' && ch!='k');
					cout<<"Запилите оценки:\n";
					for (int i=0; i<5; i++)
					{
						cout<<i+1<<"-я оценка: ";
						cin>>q->mark[i];
						cin.sync();
						if (q->mark[i]<0 || q->mark[i]>5)
						{
							i--;
							cout<<"Неверная оценка! Повторите ввод.\n";
						}
					}
					cout<<"Введите размер стипендии: ";
					do
					{
						cin>>q->pay;
						cin.sync();
						if (q->pay<0) cout<<"Сумма не может быть отрицательной!\nПовторите ввод: ";
					}
					while (q->pay<0);
					do
					{
						cout<<"Добавить ещё студента? ";
						cin>>ch;
						cin.sync();
					}
					while (ch!='y' && ch!='n');
					if (ch=='n') break;
					s=gr.st=new students;
					q->next=s;
					q=s;
				}
				q->next=0;
				Q->st=top;
				do
				{
					cout<<"Добавить ещё группу? ";
					cin>>ch;
					cin.sync();
				}
				while (ch!='y' && ch!='n');
				if (ch=='n') break;
				g1=false;
				S=new group;
				Q->NEXT=S;
				Q=S;
			}
			Q->NEXT=0;
			break;
		case 2:
			system("cls");
			S=TOP;
			while (S)
			{
				cout<<"Группа №"<<S->num<<':'<<endl;
				if (f)
				{
					s=S->st;
					while (s)
					{
						cout<<"\n	ФИО: "<<s->fio<<endl;
						cout<<"	Ф/о: "<<s->bk<<endl;
						for (int i=0; i<5; i++) cout<<"	Оценка "<<i+1<<": "<<s->mark[i]<<endl;
						cout<<"	Стипендия: "<<s->pay<<endl;
						s=s->next;
					}
				}
				cout<<endl<<endl;
				S=S->NEXT;
			}
			break;
		}
	}
	while (v);
}
По задаче с помощью программы нужно записать студенческий поток при помощи списков, где относительно групп вводится только номер каждой группы, а относительно студентов вводятся ФИО, форма обучения, 5 оценок и стипендия. Это малая часть того, что будет в итоге, но не суть. Код очень трудно читать, т.к. я отвык комментить строки и, к сожалению, лень временами отделять куски кода пустыми строками.
В общем проблема возникла именно с вводом ФИО.
Стоит оставить все в таком виде или все таки есть вариант преобразования string в char* ?

Отправлено: 12:34, 11-12-2010 | #4


Аватара для ganselo

Старожил


Сообщения: 232
Благодарности: 90

Профиль | Сайт | Отправить PM | Цитировать


Цитата Chilli:
Стоит оставить все в таком виде или все таки есть вариант преобразования string в char* ? »
Используйте:
char *string::c_str();
Код: Выделить весь код
string text = "text";
printf(text.c_str());

-------
К величайшему сожалению "история учит нас тому, что она ничему не учит".

Это сообщение посчитали полезным следующие участники:

Отправлено: 13:29, 11-12-2010 | #5


Аватара для Drongo

Будем жить, Маэстро...


Сообщения: 6694
Благодарности: 1393

Профиль | Сайт | Отправить PM | Цитировать


Chilli, Прошу прощения, возможно я неправильно понял задачу. Так не пойдёт?

Код: Выделить весь код
#include <iostream>
using namespace std;

int main()
{
  const int sizeString = 510;  // размер символьного массива ввода
  char string[sizeString];  // массив ввода
  int z;

  cout<<"   Array 510 Characther!!!\n\n"; // приглашение ввода
  cin.getline(string, sizeString, '\n');  // функция ввода
  cout<<endl;
  cout<<string<<endl;   // ПРОВЕРКА: введённого массива, вывод массва

  cin>>z;

  return 0;
}
//---------------------------------------------------------------------------

-------
Правильная постановка вопроса свидетельствует о некотором знакомстве с делом.
3нание бывает двух видов. Мы сами знаем предмет — или же знаем, где найти о нём сведения.
[Quick Killer 3.0 Final [OSZone.net]] | [Quick Killer 3.0 Final [SafeZone.cc]] | [Парсер логов Gmer] | [Парсер логов AVZ]

http://tools.oszone.net/Drongo/Userbar/SafeZone_cc.gif


Отправлено: 23:51, 11-12-2010 | #6

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Цитата Chilli:
но такие строки не прогнать через OemToChar() »
std::string этому нисколько не препятствует. Как правило string сделана как массив из char, поэтому можно пользоваться конструкцией типа:
Код: Выделить весь код
string
    str_1251 = "ывалорфывадлвр",
    str_oem;

str_oem.resize(str_1251.size());
CharToOem(str_1251.c_str(), &str_oem[0], str_oem.size());
cout << str_oem << endl;
но я бы посоветовал либо выставлять в консоли кодировку 1251 (chcp 1251), либо исходник писать в кодировке 866, и не париться.

Ещё, как вариант, можно вынести отдельно текстовые ресурсы, тогда ещё и на разные языки переводить программу можно будет

Отправлено: 21:21, 14-12-2010 | #7



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Проблема с cin.getline()

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
2008 - [решено] Проблема с ГП в AD., проблема при создании ГП к отдельным OU kozemit Windows Server 2008/2008 R2 2 15-07-2009 10:52
Разное - Проблема установки Adobe Flash Player и проблема Windows Live RubinSky Microsoft Windows 7 3 26-03-2009 21:23
Ошибка - Странная проблема с кодировкой(похоже проблема с преобразованием кодировок) Mertvii Microsoft Windows 2000/XP 1 13-07-2008 16:05
Как быстро и точно определить, в чём проблема? Явная проблема в железе UTU Непонятные проблемы с Железом 16 22-05-2006 01:27
cin и cout корректно ли работают в MSVC 6.0? Crew Программирование и базы данных 6 01-07-2003 21:06




 
Переход