1 Востаннє редагувалося pika1989 (30.10.2015 19:38:53)

Тема: У функції не ловить перший cin.getline

Задача: Написати програму, яка реалізує телефонну книгу з фіксованою(або динамічно змінюваною)
кількістю абонентів і всіма необхідними функціями. Використати вкладені структури(для адреси чи ПІБ).
Передбачити: добавлення запису у телефонну книгу, видалення запису, пошук даних про абонента по прізвищу
( чи імені), пошук даних по адресі(місту, селищу) та ін.
Реалізувала так:

Прихований текст

#include <iostream>
#include <cstring>
#include <conio.h>
#include <iomanip>

using namespace std;

struct Phonebook
{
    struct Name
    {
        char name[100];
        char surname[100];
    } name;
    char phone_number[50];
    struct Adress
    {
        char city[50];
        char street[50];
        int house_number;
        int flat_number;
    } adress;
};

void populateBaseWithTestData(Phonebook *&test, int size)
{
    const int TEST_NUMBER = 5;
    Phonebook members[5] = { { "Ivan", "Ivanov", "22-40-12", "Rivne", "Mlunivska", 40, 12 },
                             { "Olga", "Soroca", "23-34-45", "Rivne", "Kostromska", 12, 5 },
                             { "Alex", "James", "345-12-78", "Kyiv", "Khreshchatyk", 234, 12 },
                             { "Oleg", "Veremeyenko", "123-23-45", "Odessa ", "Sadova    ", 367, 123 },
                             { "Yana", "Kit      ", "2-78-12", "Kostopil", "Hrushevskoho", 65, 23 } };
    for (int i = 0; i < size; ++i)
        test[i] = members[i];
}

bool validInputPhoneNumber(const char *records)
{
    int i = 0;
    while (i < strlen(records))
    {
        if (!(isdigit(records[i]) || records[i] == '-'))
            return false;
        ++i;
    }
    return true;
}

bool validInputNameSurname(const char *records)
{
    int i = 0;
    while (i < strlen(records))
    {
        if (!(isalpha(records[i])))
            return false;
        ++i;
    }
    return true;

}

bool validInputNumber(const int records)
{
    if (records > 1)
        return true;
    else
        return false;
}

void inputRecord(Phonebook &records)
{
     
    do{
        cout << "Enter surname: ";
        cin.getline(records.name.surname, 100);
    } while (!validInputNameSurname(records.name.surname));
    cin.ignore(50, '\n');
    do{
        cout << "Enter name: ";
        cin.getline(records.name.name, 100);
    } while (!validInputNameSurname(records.name.name));

    do{
        cout << "Enter phone number: ";
        cin.getline(records.phone_number, 50);
    } while (!validInputPhoneNumber(records.phone_number));

    cout << "Enter city: ";
    cin.getline(records.adress.city, 50);
    
    cout << "Enter street: ";
    cin.getline(records.adress.street, 50);

    do{
        cout << "Enter the house number: ";
        cin >> records.adress.house_number;
    } while (!records.adress.house_number);
    do{
        cout << "Enter the flat number: ";
        cin >> records.adress.flat_number;
    } while (!records.adress.house_number);
    
}

Phonebook *createNewBase(int &size)
{
    size = 1;
    Phonebook *temp = new Phonebook[size];
    for (int i = 0; i < size; ++i)
        inputRecord(temp[i]);
    return temp;
}

void addRecord(Phonebook *&records, int &size)
{
    if (records == NULL)
    {
        records = createNewBase(size);
    }
    else
    {
        Phonebook *new_records = new Phonebook[size + 1];
        for (int i = 0; i < size; ++i)
            new_records[i] = records[i];
        delete[]records;
        records = new_records;
        inputRecord(records[size]);
        ++size;
    }
}

void headPrintRecord()
{
    cout << "N  " << "Name" << setw(15) << "Surname" << setw(15) << "Phone number" << setw(15) << "City" << setw(10) << "Street" << setw(10) << "House" << setw(6) << "Flat\n";
    cout << "-------------------------------------------------------------------------------\n";
}

void printRecord(const Phonebook record, int index)
{
    cout << index + 1 << "  " << record.name.name << setw(15) << record.name.surname << setw(15) << record.phone_number << setw(15);
    cout << record.adress.city << setw(15) << record.adress.street << setw(5) << record.adress.house_number << setw(4) << record.adress.flat_number << "\n";
}

void printAllRecords(const Phonebook *records, int size)
{
    if (records == NULL)
        cout << "Phonebook is empty\n";
    else
    {
        headPrintRecord();
        for (int i = 0; i < size; ++i)
        {
            cout << i + 1 << "  " << records[i].name.name << setw(15) << records[i].name.surname << setw(15) << records[i].phone_number << setw(15);
            cout << records[i].adress.city << setw(15) << records[i].adress.street << setw(5) << records[i].adress.house_number << setw(4) << records[i].adress.flat_number << "\n";
        }
    }
}
void searchRecordBySurname(const Phonebook *records, int size, char *search_key)
{
    if (records == NULL)
        cout << "Phonebook is empty\n";
    bool search = false;
    for (int i = 0; i < size; ++i)
    {
        if (strcmp(records[i].name.surname, search_key) == 0)
        {
            printRecord(records[i], i);
            search = true;
        }
    }
    if (!search)
        cout << "Not found " << search_key << "!\n";
}

void searchRecordByStreet(const Phonebook *records, int size, char *search_key)
{
    if (records == NULL)
        cout << "Phonebook is empty\n";
    bool search = false;
    for (int i = 0; i < size; ++i)
    {
        if (strcmp(records[i].adress.street, search_key) == 0)
        {
            printRecord(records[i], i);
            search = true;
        }
    }
    if (!search)
        cout << "Not found " << search_key << "!\n";
}

void searchRecordByPhoneNumber(const Phonebook *records, int size, char *search_key)
{
    if (records == NULL)
        cout << "Phonebook is empty\n";
    bool search = false;
    for (int i = 0; i < size; ++i)
    {
        if (strcmp(records[i].phone_number, search_key) == 0)
        {
            printRecord(records[i], i);
            search = true;
        }
    }
    if (!search)
        cout << "Not found " << search_key << "!\n";
}

void deleteRecord(Phonebook *&records, int &size, int pos_record)
{
    if (records == NULL)
        cout << "Phonebook is empty\n";
    else
    {
        --pos_record;
        if (pos_record < 0 || pos_record >= size)
            cout << "Phonebook doesn't have any record with this number\n";
        else
        {
            Phonebook *new_records = new Phonebook[size - 1];
            for (int i = 0; i < pos_record; ++i)
                new_records[i] = records[i];
            for (int i = pos_record; i < size - 1; ++i)
                new_records[i] = records[i + 1];
            delete[]records;
            records = new_records;
            --size;
        }
    }
}

void deleteAllRecords(Phonebook *&records, int &size)
{
    if (records == NULL)
        cout << "Phonebook is empty\n";
    else
    {
        delete[]records;
        records = NULL;
        size = 0;
        cout << "Phonebook cleared\n";
    }
}

void printMenu()
{
    cout << "\tMENU\n\n";
    cout << "\t\t1 - Add records\n";
    cout << "\t\t2 - Show all records\n";
    cout << "\t\t3 - Delete record\n";
    cout << "\t\t4 - Search records by name\n";
    cout << "\t\t5 - Search records by street\n";
    cout << "\t\t6 - Search records by phone number\n";
    cout << "\t\t7 - Clear phonebook\n";
    cout << "\t\t0 - exit\n";
}

void menu(Phonebook *records, int size)
{
    enum action{EXIT, ADD_RECORDS, SHOW_ALL_RECORDS, DELETE_RECORD, SEARCH_RECORDS_BY_SURNAME,
                SEARCH_RECORDS_BY_STREET, SEARCH_RECORDS_BY_PHONE_NUMBER, CLEAR_PHONEBOOK};
    bool exit = false;
    do{
        system("cls");
        printMenu();
        cout << "\nYour choice: ";
        int user_choice;
        cin >> user_choice;
        switch (user_choice)
        {
        case ADD_RECORDS:
            system("cls");
            addRecord(records, size);
            cout << "Record added\n";
            break;
        case SHOW_ALL_RECORDS:
            system("cls");
            cout << "\n\tAll records in base\n\n";
            printAllRecords(records, size);
            break;
        case DELETE_RECORD:
            system("cls");
            int pos_delete_record;
            cout << "Enter the number of record which you want delete: ";
            cin >> pos_delete_record;
            deleteRecord(records, size, pos_delete_record);
            cout << "Record deleted\n";
            break;
        case SEARCH_RECORDS_BY_SURNAME:
            system("cls");
            char user_search_surname[100];
            cout << "Enter the surname what you want to find: ";
            cin >> user_search_surname;
            searchRecordBySurname(records, size, user_search_surname);
            break;
        case SEARCH_RECORDS_BY_STREET:
            system("cls");
            char user_search_street[50];
            cout << "Enter the name street what you want to find: ";
            cin >> user_search_surname;
            searchRecordBySurname(records, size, user_search_street);
            break;
        case SEARCH_RECORDS_BY_PHONE_NUMBER:
            system("cls");
            char user_search_phone_number[50];
            cout << "Enter the phone number what you want to find: ";
            cin >> user_search_surname;
            searchRecordBySurname(records, size, user_search_phone_number);
            break;
        case CLEAR_PHONEBOOK:
            deleteAllRecords(records, size);
            break;
        case EXIT:
            cout << "Good by!\n";
            exit = true;
            break;
        default:
            cout << "Incorrect choice!\n";
        }
        _getch();
    } while (!exit);
}

int main()
{
    int number_records = 5;
    //Phonebook *records = new Phonebook[number_records];
    //populateBaseWithTestData(records, number_records);
    Phonebook *records = NULL;
    menu(records, number_records);

    return 0;
}

І, ніби все працює, але при введенні даних у функції :

Прихований текст

void inputRecord(Phonebook &records)
{
     
    do{
        cout << "Enter surname: ";
        cin.getline(records.name.surname, 100);
    } while (!validInputNameSurname(records.name.surname));
    cin.ignore(50, '\n');
    do{
        cout << "Enter name: ";
        cin.getline(records.name.name, 100);
    } while (!validInputNameSurname(records.name.surname));

    do{
        cout << "Enter phone number: ";
        cin.getline(records.phone_number, 50);
    } while (!validInputPhoneNumber(records.phone_number));

    cout << "Enter city: ";
    cin.getline(records.adress.city, 50);
    
    cout << "Enter street: ";
    cin.getline(records.adress.street, 50);

    do{
        cout << "Enter the house number: ";
        cin >> records.adress.house_number;
    } while (!records.adress.house_number);
    do{
        cout << "Enter the flat number: ";
        cin >> records.adress.flat_number;
    } while (!records.adress.house_number);
    
}

не записує у змінну, яка для введення стоїть перша. Програма просить ввести значення, але його не записує.
Приклад,
основне меню програми:

Прихований текст
http://i.imgur.com/l0t9KC9.png

занесення даних:

Прихований текст
http://i.imgur.com/89Ee0I6.png

вивід:

Прихований текст
http://i.imgur.com/BznEDca.png

Поле Surname не заповнене. В чому може бути проблема?

2

Re: У функції не ловить перший cin.getline

 cin.ignore(50, '\n');

Оцей рядок потрібно переставити на початок ф-ії. Важко пояснити детально чому саме так, навіть з документації важко повністю "в'їхати" - http://www.cplusplus.com/reference/istr … am/ignore/, але повинно працювати.
Саме через купу отаких всяких речей, Я не люблю C++, вже навіть гидотна Java краще...

Мій блог про ОС сімейства *nix - http://nixtravelling.blogspot.com/
Подякували: pika19891

3

Re: У функції не ловить перший cin.getline

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

4

Re: У функції не ловить перший cin.getline

istream::getline і istream::operator>> - це різні способи введення, певною мірою несумісні. operator>> залишає в буфері клавіатури все, що йому не знадобилося; оскільки ви вводили число і Enter, а operator>> взяв тільки число - то знак нового рядку лишається в буфері і його отримує getline. Треба очищувати буфер вводу після operator>> перед getline - приблизно так:

std::cin.clear(); //якщо був збій вводу - відновлюємося
std::cin.ignore(INT_MAX,'\n'); //викидаємо, що можемо, по новий рядок включно
Подякували: pika1989, Master_Sergius, Ярослав3

5

Re: У функції не ловить перший cin.getline

std::cin.ignore(INT_MAX,'\n'); //викидаємо, що можемо, по новий рядок включно

мені здається що це каще робити за допомогою cin.sync()

6

Re: У функції не ловить перший cin.getline

Коли здається, треба хреститися.
sync() не обов'язково чистить ВСІ буфери, а тільки програмний буфер цієї програми. Якщо щось було в системному буфері, воно там цілком може лишитися.