Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Проблема с cin.getline() (http://forum.oszone.net/showthread.php?t=193611)

Chilli 10-12-2010 21:53 1562918

Проблема с cin.getline()
 
В некоторой части программы требуется ввести строку (включая пробелы), для чего я решил использовать 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() вывести строку, размер которой, так сказать, динамический.
Я, конечно, подозреваю, что подобное невозможно без ограничения/декларации символьного массива, но все же - возможно ли решить такую проблему?

pva 11-12-2010 10:54 1563148

Код:

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*, для которого сделано автоматическое управление памятью.

ganselo 11-12-2010 11:01 1563153

Цитата:

Цитата 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 опередил с ответом)

Chilli 11-12-2010 12:34 1563202

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* ?

ganselo 11-12-2010 13:29 1563221

Цитата:

Цитата Chilli
Стоит оставить все в таком виде или все таки есть вариант преобразования string в char* ? »

Используйте:
char *string::c_str();
Код:

string text = "text";
printf(text.c_str());


Drongo 11-12-2010 23:51 1563665

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;
}
//---------------------------------------------------------------------------


pva 14-12-2010 21:21 1565922

Цитата:

Цитата 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, и не париться.

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


Время: 17:23.

Время: 17:23.
© OSzone.net 2001-