Остановить подсчет, если персонаж не может быть найден на карте [закрыто]

avatar
That_Guy989
9 августа 2021 в 07:04
107
1
2

У меня есть задание, в котором я должен создать преобразователь римских цифр в целые числа. В моем коде я только что использовал карту, чтобы связать символы с целочисленными значениями, которые добавляются к сумме с учетом таких значений, как IV и т. д. Для строк, которые не полностью состоят из римских цифр, я пытался заставить его прекратить добавление, как только будет найден символ без сопоставленного значения, но у меня возникают проблемы.

#include <iostream>
#include <cctype>
#include <map>
#include <string>
#include <algorithm>

using namespace std;


int main(int argc, char *argv[]) {

map<char, int> num;
num.insert({ 'I', 1});
num.insert({ 'V', 5});
num.insert({ 'X', 10});
num.insert({ 'L', 50});
num.insert({ 'C', 100});
num.insert({ 'D', 500});
num.insert({ 'M', 1000});

string str;

while(getline(cin,str)){

    int sum = 0;

    transform(str.begin(), str.end(), str.begin(), ::toupper);

    for (int j = 0; j < str.length(); j++){

        if (num.count(str[j]) != 1){
            break;
        }


        if (num[str[j]] < num[str[j+1]]){
            sum += num[str[j+1]] - num[str[j]];
            j++;
            continue;
        }

            sum += num[str[j]];
    }

    cout << sum << "\n";
 }
 return 0;
}

Я думал, что num.count(str[j]) вернет 0, если сопоставленное значение не будет найдено, и тогда я мог бы использовать это, чтобы прервать цикл for, но я где-то ошибся. Когда я передаю аргумент командной строки iittii, я хотел бы, чтобы он выводил сумму 2 (поскольку он остановится, когда встретит первое t), но вместо этого я получаю 4.

Моя реализация неверна или есть альтернативный способ достижения этого?

Спасибо

Источник
paddy
9 августа 2021 в 07:10
1

break выходит только из самого внутреннего цикла. Если вы хотите выйти из обоих циклов, установите флаг, а затем выполните проверку и разрыв после цикла. Или оберните свой цикл в функцию, чтобы вы могли проверить результат, а затем прервать. Удобно, что для вас уже существует одна такая функция: std::any_of.

Igor R.
9 августа 2021 в 07:12
1

str[j+1] - это UB, поэтому ваша программа имеет случайное поведение

Evg
9 августа 2021 в 07:22
0

Не связанный. Не используйте тип int для индекса, это подписанный тип. str.length() возвращает тип без знака (std::size_t), и смешивание типов с разной подписью никогда не является хорошей идеей.

Ответы (1)

avatar
Job_September_2020
9 августа 2021 в 07:16
1

Я думаю, проблема в следующем блоке кода:

if (num[str[j]] < num[str[j+1]]){
    sum += num[str[j+1]] - num[str[j]];
    j++;
    continue;
}

Этот блок кода приводит к сбоям в работе вашей программы, потому что у него есть 2 проблемы:

  1. Неверно вычисляется sum.
  2. Это может привести к неожиданному сбою программы в какой-то момент (т.е. ошибка сегментации), потому что код str[j+1] означает, что index j+1 больше, чем длина str в конце цикла for, когда j = str.length - 1. Другими словами, это означает, что индекс j+1 в этой точке выходит за границы.

Итак, после того как я изменил этот блок кода, как показано ниже, ваша программа работает правильно:

    if (j > 0 &&
        num[str[j]] > num[str[j-1]]){
        sum += num[str[j]] - 2 * num[str[j-1]];           
        continue;
    }

Вот моя новая программа (с моим новым блоком кода):


#include <iostream>
#include <cctype>
#include <map>
#include <string>
#include <algorithm>

using namespace std;


int main(int argc, char *argv[]) {

map<char, int> num;
num.insert({ 'I', 1});
num.insert({ 'V', 5});
num.insert({ 'X', 10});
num.insert({ 'L', 50});
num.insert({ 'C', 100});
num.insert({ 'D', 500});
num.insert({ 'M', 1000});

string str;

while(getline(cin,str)){

    int sum = 0;

    transform(str.begin(), str.end(), str.begin(), ::toupper);

    for (int j = 0; j < str.length(); j++){

        if ( num.count(str[j]) < 1 ){
            break;
        }

        // HERE IS MY NEW BLOCK OF CODE :-)
        if (j > 0 &&
            num[str[j]] > num[str[j-1]]){

            sum += num[str[j]] - 2 * num[str[j-1]];           
            continue;
        }

            sum += num[str[j]];
    }

    cout << sum << "\n";
 }
 return 0;
}

Пожалуйста, дайте мне знать, подходит ли вам приведенный выше ответ.

Я выполнил 2 теста и убедился, что программа работает:

  1. Ввод = iittii

    В соответствии с вашим описанием проблемы я ввожу ввод iittii как вам нужно, и моя программа выдает правильный вывод 2 как вы ожидаете.

  2. Ввод = IV, IX, CD

    Кроме того, я также протестировал ввод, такой как IV, IX, CD, как пользователь. @ArminMontigny описал, и мой новый код работает правильно.