Вопрос по комментарию к уроку о функциях C++ (функция авторизации пользователя)

Приветствую уважаемые мэтры. Не хотел создавать отдельную тему по просьбе Cranium, но увидев, что форум не особо многолюден решил написать. В предыдущей версии предложенного мною решения был БАГ, который я вроде исправил в нижеприведенном коде(отмечен примечанием). Суть темы не сколько получить рабочий код, сколько узнать, какой вариант решения более приемлем.
Программа проверяет ввод логина и пароля. Если пароль или логин не верны, она предлагает попробовать ввести их заново (если логин подтвержден, то предлагается ввести повторно только пароль к нему). Решение, соответственно, с использованием функций и без спец. возможностей языка (на основе уроков C++ до темы с функциями).
Спасибо за потраченное время.

#include <iostream>
#include <string>
using namespace std;




    bool pass(int j) //Функция проверки пароля для логина
    {
        string retry;
        string password;
        string p[5] = { "a", "b", "c", "d", "e" };//Массив с паролями (номер элемента массива с паролем соответствует номеру элемента массива с логином)

        cout << "Введите пароль :";
        getline(cin, password);
        cout << endl;
        if (p[j] == password)

            return true;

        else
        {
            cout << "Неправильный ввод пароля для логина :" << endl;
            cout << "Для повторного ввода нажмите 1 ";
            getline(cin, retry);
            cout << endl;
            if (retry == "1")
            {

                pass(j);
            }
            else
            {

                return false;
            }
        }
        return false;//ЛЕЧЕНИЕ БАГА ПРЕДЫДУЩЕГО РЕШЕНИЯ (в комментариях к теме о функциях)
    }


    bool log() //Функция проверки логина
    {
        string l[5] = { "1", "2", "3", "4", "5" };//Массив с логинами
        string login;
        string retry;
        bool   pr = false;


        cout << "Ввведите логин :";
        getline(cin, login);
        cout << endl;


        for (int i = 0; i < 5; i++)
        {
            if (login == l[i])
            {
                pr = true;
                if (!pass(i))

                    return false;

                else
                {
                    cout << "Авторизация выполнена! Пользователь :" << l[i] << endl<<endl;
                    return true;
                }

            }
        }

        if (pr == false)
        {
            cout << "Логин " << login << " не найден!" << endl;
            cout << "Для повторного ввода нажмите 1 ";
            getline(cin, retry);
            cout << endl;
            if (retry == "1")
                log();
            else
                return false;
        }

        return true;
    }
int main()

{
    setlocale (0, "");

        if (!log())
            cout<<"Программа работает без авторизации"<<endl<<endl;
        else
            cout << "Программа получила подтверждение регистрации" << endl<<endl;



    return 0;
}

Непрокатилло :/

раз:

Ввведите логин :1

Введите пароль :0

Неправильный ввод пароля для логина :
Для повторного ввода нажмите 1 1

Введите пароль :a

Программа работает без авторизации

два:

Ввведите логин :77

Логин 77 не найден!
Для повторного ввода нажмите 1 1

Ввведите логин :88

Логин 88 не найден!
Для повторного ввода нажмите 1 0

Программа получила подтверждение регистрации

Что мне не понравилось в коде (относится к обеим версиям):

(1) Код работает неправильно. Это — главный недостаток.

(2) Хардкодить логины и пароли — плохая идея. Ещё более плохая идея хардкодить их в разных местах программы. Не будем обращать внимание, что эта информация хранится в открытом виде — считаем, что программа учебная и задача криптозащиты не стоит.

В комментарии в программе ты сам написал: номер элемента массива с паролем соответствует номеру элемента массива с логином. Вопрос: зачем тогда два массива, когда можно обойтись либо одним двумерным массивом, либо одномерным массивом структур из двух полей? (Второе предпочтительнее.)

Исходя из вышесказанного, вырисовывается структура данных для хранения логинов/паролей. В примитивной реализации это

struct auth_data {
    std::string login, password;
};

Массив из таких структур легко инициализировать литералами в тексте программы (исключительно в целях отладки!). Но можно так же легко читать из внешнего источника, например из текстового файла (или БД). В дальнейшем эту структуру легко преобразовать в класс, который обеспечивает безопасное хранение логина/пароля, чтение из потока, запись в поток, криптозащиту, очистку памяти, сравнение и т.д., и т.п.

(3) Не знаю на сколько обоснована раздельная проверка логина и пароля. С точки зрения взлома, брутить сначала логин, а затем брутить пароль к уже известному логину гораздо проще, чем пытаться подбирать пару.

(4) Интерфейс работы с пользователем, по возможности, надо отделять от основной логики программы. Т.е. в данном случае, запросили у пользователя логин и пароль и вызвали функцию, которая обработает эту информацию. По результату, возвращённому функцией, сказали пользователю всё, что мы о нём думаем.

Сейчас у тебя всё смешано в одну кучу и размазано по коду ровным слоем.

В более продвинутом случае, все строки, которые показываются пользователю, лучше хранить в файле ресурсов, или хотя бы в отдельном cpp-файле в виде глобального константного массива строк. Это позволяет сделать безболезненную локализацию программы (перевод на другой язык, например на английский). Но это так, к слову.

(5) Использовать рекурсию вместо очевидного цикла — зло. На чём ты, кстати, и словил свои баги.
«Итерация свойственна человеку, рекурсия божественна.» — L Peter Deutsch. И, как всякий инструмент бога, рекурсию надо применять очень осмотрительно.

Попробуй переписать программу с учётом вышеописанных соображений.

Спасибо большое за отзыв! Как получу верное решение, постараюсь отписаться.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.