Ошибка отладки задания c ›= -1 && c‹ = 255

Мне сложно понять эту ошибку времени выполнения в моем коде. Это было задание для моего класса, которое, как я думал, будет легким, но что-то странное продолжается. Я разместил свой код ниже.

Подсказка для этого назначения заключалась в создании программы, которая просит пользователя ввести несколько слов, а затем она должна вывести, сколько слов есть. У меня был друг, запускавший программу, и она работала, однако всякий раз, когда я пытаюсь ее запустить, я получаю эту ошибку времени выполнения. [http://imgur.com/FcdN3zK]

Имейте в виду, что я новичок в C ++ и программировании в целом, поэтому я не смогу понять очень технические ответы. Спасибо заранее за вашу помощь.

#include <string>
#include <iostream>
#include <cstring>

using namespace std;

int wordCounter(char *);

int main()
{
    char *stringArray = nullptr;
    stringArray = new char[120];

    cout << "Please enter a saying or a phrase that has more than one word: " << endl;
    cin.getline(stringArray, 120);

    int words = wordCounter(stringArray);
    cout << "Your statement contains " << words << " words." << endl;

    system("pause");
    return 0;
}

int wordCounter(char *stringTest)
{
    char characterToTest;
    int numberOfWords = 0;
    for (int i=0; i < 120; i++)
    {
        characterToTest = *(stringTest + i);
        if (isspace(characterToTest) && i != 120)
        {
            char characterToTestTemp = *(stringTest + (i + 1));
            if (isalnum(characterToTestTemp))
            {
                numberOfWords++;
            }
        }
    }
    return numberOfWords;
}

person Dranslin    schedule 14.02.2015    source источник
comment
Вы не останавливаетесь на фактической длине ввода, поэтому вы обрабатываете неопределенную мусорную вставку, равную длине входной строки.   -  person WhozCraig    schedule 14.02.2015
comment
Когда я запустил ваш код на моем c ++, я изменил nullptr на NULL (я использую более старую версию, поэтому нет nullptr), и моя программа скомпилирована без каких-либо проблем, но количество слов неверное.Если я введу 3 слова, на выходе будет 2 слова, и если я введу 20 слов, на выходе будет 19 слов.   -  person Arun A S    schedule 14.02.2015
comment
В вашем коде несколько проблем. Неспособность проверить конец фактической строки, которая была введена (а не конец буфера), является одним из них. Ожидание первого пробела перед попыткой распознать какое-либо слово - это еще один (вот почему вы не учитываете первое слово).   -  person Marc van Leeuwen    schedule 14.02.2015
comment
@ ArunA.S Неопределенное поведение может проявляться по-разному. Ваш компилятор либо имеет char как беззнаковый, либо не проверяет, какое значение передается в пробел и т. Д., Либо инициализирует буфер нулем.   -  person Alan Stokes    schedule 14.02.2015
comment
@ Алан Стоукс, я не понимаю, о чем вы говорите (я не настолько умен, но все еще новичок). Я имел в виду, что когда я скомпилировал код @ Dranslin, он показал ошибку из-за nullptr. Мой компилятор - gcc 4.8.0 (Devc ++), поэтому я изменил nullptr на NULL, и программа скомпилировала и выдала результат (хотя количество слов всегда казалось на 1 меньше, чем число, которое я ввел). Пожалуйста, объясните, что вы имели в виду (у меня не было неопределенного поведения).   -  person Arun A S    schedule 14.02.2015
comment
@ ArunA.S Программа читает после конца строки и делает другие плохие вещи (описанные в ответах). Но C ++ не требовал сообщения об ошибке; он просто говорит, что поведение не определено, поэтому программа может делать все, что угодно. OP посчастливилось получить сообщение об ошибке. Допускается и то, что вы не ответили, но получили неправильный ответ.   -  person Alan Stokes    schedule 14.02.2015


Ответы (4)


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

Вот что вы, вероятно, пытаетесь сделать:

int wordCounter(const char *str)
{
    int numberOfWords = 0;
    while (*str)
    {
        // skip any leading whitespace
        while (*str && isspace(static_cast<unsigned char>(*str)))
            ++str;

        // if we're still on string data, we have another word
        if (*str)
        {
            // skip everything up to more whitespace
            while (*str && !isspace(static_cast<unsigned char>(*str)))
                ++str;

            // and count the word
            ++numberOfWords;
        }
    }
    return numberOfWords;
}

Или что-то подобное. Может потребоваться дополнительная обработка для учета знаков препинания и т. Д. Это останавливается, как только вы дойдете до терминатора входной строки.

Удачи.

person WhozCraig    schedule 14.02.2015

isspace и друзей на удивление сложно назвать правильно. В частности, вы не можете безопасно передать им char, потому что значения char могут быть отрицательными, а это недопустимо, как говорится в сообщении об ошибке.

Вы должны выполнить преобразование в unsigned char, чтобы быть в безопасности:

isspace(static_cast<unsigned char>(characterToTest))

Это не основная проблема, вам нужно сначала исправить переполнение, но это часть того, почему вы получаете сообщение об ошибке.

person Alan Stokes    schedule 14.02.2015

Ваша функция wordcount всегда обрабатывает 120 символов независимо от длины действительно прочитанной входной строки. Итак, вы читаете конец строки и имеете дело с неинициализированной памятью.

Документация Microsoft гласит: «Поведение _isctype и _isctype_l не определено, если c не является EOF или находится в диапазоне от 0 до 0xFF включительно. Когда используется отладочная библиотека CRT и c не является одним из этих значений, функции вызывают утверждение».

Это причина для утверждения.

Строки C заканчиваются нулем, вы должны проверить это условие в своем цикле.

int wordCounter(char *stringTest)
{
    char characterToTest;
    int numberOfWords = 0;
    for (int i = 0; i < 120; i++)
    {
        characterToTest = *(stringTest + i);
        if (characterToTest == 0)  
            break; // <-- exit the loop at the end of the string
        if (isspace(characterToTest) && i != 120)
        {
            char characterToTestTemp = *(stringTest + (i + 1));
            if (isalnum(characterToTestTemp))
            {
                numberOfWords++;
            }
        }
    }
    return numberOfWords;
}

у вас могут быть другие логические ошибки в вашей функции подсчета, например, не подсчет первого слова.

person Pierre    schedule 14.02.2015

Спасибо за вашу помощь. Читая об этом (и я понимаю, что у меня есть логические ошибки, которые не учитываются, если пользователь ничего не вводит и отправляет, он все равно будет печатать 1), я смог придумать немного другой подход к этому.

Вот исправленный код.

#include <string>
#include <iostream>
#include <cstring>

using namespace std;

int wordCounter(char *, int);

int main()
{
    cout << "Please enter a saying or a phrase that has more than one word: " << endl;

    string testString;
    getline(cin, testString);

    int stringLength = testString.length();

    char *stringArray = nullptr;
    stringArray = new char[stringLength];

    strcpy(stringArray, testString.c_str());

    int words = wordCounter(stringArray, stringLength);
    cout << "Your statement contains " << words << " words." << endl;

    system("pause");
    return 0;
}

int wordCounter(char *stringTest, int length)
{
    char characterToTest;
    int numberOfWords = 1;
    for (int i=0; i < length; i++)
    {

            characterToTest = *(stringTest + i);

            if (isspace(characterToTest) && (i != length))
            {

                    char characterToTestTemp = *(stringTest + (i + 1));
                    if (isalnum(characterToTestTemp))
                    {
                            numberOfWords++;
                    }
            }
    }
    return numberOfWords;
}
person Dranslin    schedule 14.02.2015
comment
int stringLength = testString.length (); char * stringArray = новый символ [stringLength]; strcpy (stringArray, testString.c_str ()); вы создаете массив из N байтов, а затем копируете в него N + 1 байта (strcpy завершает свою копию дополнительным байтом \ 0). Это называется ошибкой переполнения буфера. - person Pierre; 15.02.2015