почему я могу ввести только tickcket_code и last name дальше программа просто завершается и также не работает функция delete Travelers?

#include <iostream>
#include <string>
using namespace std;
const int maxSize = 100;
struct Travelers
{
    int ticket_code;
    char lastname[maxSize];
    int numberofthings;
    int luggage_weight;
    Travelers* Next;
};
Travelers* Head;

void TravelersInput(int& ticket_code,char lastname[maxSize], int& numbeofthings,int& luggage_weight)
{
    cout << "Enter tour ticket code" << endl;;
    cin >> ticket_code;
    cout << "Enter your Lastname:" << endl;
    cin.get();
    cin.get(lastname, sizeof(lastname[maxSize]));
    cout << "Enter number of things:" << endl;
    cin >> numbeofthings;
    cout << "Enter your luggage weight:"<<endl;
    cin >> luggage_weight;
    cout << endl;
}

void PrintTravelers(Travelers* Head)
{
    Travelers* j = Head;
    while (j != NULL)
    {
        cout << "Travelers: " << j->ticket_code<< ";" << j->lastname<< ";" << j->numberofthings<< ";" << j->luggage_weight<< ";";
        j = j->Next;
    }
    cout << endl;
}

Travelers* TravelersSearch(Travelers* Head, int numberofthings)
{
    Travelers* p = Head; 
    while (p != NULL) 
    {
        if (p->numberofthings == numberofthings) 
            break; 
        p = p->Next;
    }
    return p;
}


void DeleteTravelers(Travelers*& pbeg, Travelers* pos)
{
    if (pbeg == NULL || pos == NULL)
        return; 
    if (pos == pbeg)
    {
        pbeg = pbeg->Next;
        delete pos;
    }
    else
    {
        Travelers* prev = pbeg;
        while (prev != NULL && prev->Next != pos)
            prev = prev->Next;
        if (prev != NULL)
        {
            prev->Next = pos->Next;
            delete pos;
        }
    }
}

void FreeTravelers(Travelers*& pbeg)
{
    Travelers* p;
    while (pbeg != NULL)
    {
        p = pbeg;
        pbeg = pbeg->Next;
        delete p;
    }
}

int main()
{
    int ticket_code;
    char lastname[maxSize]= { '\0' };
    int numberofthings;
    int luggage_weight;

    Travelers* Head = nullptr;
    int n;

    cout << "Number of Travelers = ";
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        TravelersInput(ticket_code, lastname, numberofthings, luggage_weight);
    }

    cout << " deleted Travelers = ";
    cin >> luggage_weight;
    DeleteTravelers(Head, TravelersSearch(Head, luggage_weight));
    PrintTravelers(Head);

    FreeTravelers(Head);

    system("pause");
    return 0;
}

Ответы (1 шт):

Автор решения: KoVadim

Давайте посмотрим детальнее на это выражение

cin.get(lastname, sizeof(lastname[maxSize]));

Нас тут интересует два момента - значение sizeof(lastname[maxSize]) и что вообще происходит. Главное, что нужно знать о sizeof - это то, что выражение не вычисляется, а только оценивается его тип, что бы знать размер и это делается на момент компиляции. В данном случае тип - это элемент массива, это char. значит все выражение равно 1.

По поводу UB - я нашел вот такое обсуждение - Does not evaluating the expression to which sizeof is applied make it legal to dereference a null or invalid pointer inside sizeof in C++? и похоже, что там как раз и сходятся к тому, что не, это не UB.

А теперь, а что же происходит? Теперь, когда мы немного разобрались с деталями, выражение можно переписать вот так

cin.get(lastname, 1);

и все очевидно - прочитать нужно... 0 символов. Почему? потому что count-1. И тут наступает проблема - в буфере то остаются еще символы(как минимум то вводился один символ (фамилии обычно меньше двух не бывает, но вряд ли кто то просто жал перевод строки). И в результате с буфера ничего не читается. И что же будет с этим буфером? а его попробуют читать последующие операции чтения. А там у нас

cin >> numbeofthings;

попытка прочитать число. А так как "фамилия" (lastname) обычно не содержит цифры вначале, то поток переходит в состояние "ай-ай-ай" (выставляется failbit) и отказывается дальше читать (то есть, все операции чтения игнорируются!).

Это выглядит красиво, но это не так. Оказывается, failbit выставляется чуточку раньше. В документации есть маленькая приписка

If no characters were extracted, calls setstate(failbit)

а у нас должно прочитаться не более 0 символов. То есть, попытка вызвать get(char_array,1) будет приводить к установке failbit...

Но почему возникла такая странная строка? скорее всего хотелось написать такое

cin.get(lastname, sizeof(lastname));

но дрогнула рука, скопировался параметр... и все скомпилировалось...

В целом, организация корректного ввода - не легкая задача, а организация ввода, понятного пользователю - ещё сложнее. Поэтому, я бы не заморачивался особо. Но немного можно сделать.

Но это только вершина айсберга. Дальше веселее. Посмотрим на TravelersInput. Она принимает по ссылке переменные, в которые с разной долей успеха что то вводит, а потом.... А потом ничего не делает. Она не добавляет новую структуру в список. Она просто выбрасывает значения. Список Head продолжает указывать на nullptr... Забавно

Теперь чуточку очевиднее - нужно эти данные все таки куда то добавить, плюс организовать корректный ввод. Я предлагаю так переделать функцию ввода

bool TravelersInput(Travelers* t)
{
    cout << "Enter tour ticket code" << endl;;
    cin >> t->ticket_codeticket_code;
    cout << "Enter your Lastname:" << endl;
    cin.get();
    cin.get(t->lastname, sizeof(t->lastname));
    cout << "Enter number of things:" << endl;
    cin >> t->ticket_codenumbeofthings;
    cout << "Enter your luggage weight:"<<endl;
    cin >> t->luggage_weight;
    cout << endl;
    return cin.good();
}

Она теперь получает указатель на структуру и заполняет её данными. И самое главное, в конце возвращает признак успешности ввода.

И теперь ввод будет выглядеть где то так

for (int i = 0; i < n; i++)
  {
      Travelers* t = new Travelers;
      if (!TravelersInput(t)) {
          // почистим память. Вроде я все правильно написал.
          delete t;
          FreeTravelers(Head);
          // выйдем
          return 1;
      }
      // а тут нужен код добавления этой структуры в список
      // напишите сами:)
  }
→ Ссылка