Проблема с выводом последнего слова строки.

Добрый день!
Дали задание определить слова, в которых есть три латинских буквы «а» (слова разделены запятыми, в конце точка).
Проблема: при выполнении выводятся все нужные кроме последнего слова, в счетчик оно тоже не засчитывается. Смог решить это поставив запятую перед точкой, но оказалось не вариант.
Еще была мысль делать цикл не до точки а до первого пробела, а между словами пробелы убрать, это работало, но потом надо будет сделать ввод из консоли, и тот кто будет вводить слова может делать пробелы, так что это тоже не подошло.
Вообщем, прошу совета... за другие косяки не ругайте, только учусь.

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

int ok = 0; // счетчик слов, удовлетворяющих условие
int vcount = 0; // счетчик символов в буфере
int main()
{

    int k = 0, a = 0; // k - счетчик знака , a - счетчик букв "а" в слове
    vector <char> buf; // используем вектор как буфер для слов на вывод
    char line[110] = "archer, eurosport, arabian, kick, ausralia, archer, eurosport, arabian, kick, ausralia, archer, arabian.";
    /*-------------------------------------------------------------------------------*/
    for (int i = 0; i < 110; ++i) { // вывод масива
        cout << line[i];
    } cout << endl;
    /*-------------------------------------------------------------------------------*/
    do { // выполняется, пока не всретит точку
        if (line[k] != ',' || line[k] != '.')
        {
            buf.push_back(line[k]);
            vcount++;
        }
        if (line[k] == 'a') { a++; }
        if (line[k] == ',' || line[k] == '.') /* если встречается запятая или точка слово идет на проверку условия*/
        {
            if (a == 3) {
                ok++;
                for (int i = 0; i < vcount; i++)
                {
                    cout << buf[i];
                } // вывод слова на екран если условие удовлетворено
            }
            buf.clear(); // очистка буфера
            vcount = 0; a = 0; // сброс счетчика
        }
        k++;
    } while (line[k] != '.');
    /*-------------------------------------------------------------------------------*/
    cout << endl;
    cout << "Words with 3x'a' = " << ok << endl; //вывод кол-ва слов с 3х"а"
    return 0;
}

За косяки не ругаю... но не могу не отметить: жу-у-уть.

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

Указатель ptr пробегает строку от начала до конца (до '\0'). Если текущий символ не является буквой (!isalpha(*ptr)), то считаем его разделителем слов. При этом, если счетчик букв «а» в только что закончившемся слове равен 3, то увеличиваем счетчик искомых слов, после этого сбрасываем счетчик букв «а», переводим указатель на следующий символ и переходим на начало цикла.

Если же текущий символ буква, то значит мы находимся внутри слова. Здесь проверяем символ на «а» и, если нужно, увеличиваем счетчик букв «а» и переводим указатель на следующий символ.

#include <iostream>

using namespace std;

int main() {

    /*-------------------------------------------------------------------------------*/
    char line[] = "archer, eurosport, arabian, kick, ausralia, archer, eurosport, arabian, kick, ausralia, archer, arabian.";
    cout << line << endl;
    /*-------------------------------------------------------------------------------*/

    int ok_word_counter = 0;    // счетчик слов с 3х"а"
    char *ptr = line;           // указатель по входной строке
    int cnta = 0;               // счетчик букв "а" в слове

    while (*ptr != '\0') {
        if (!isalpha(*ptr)) {
            if (cnta == 3)
                ++ok_word_counter;
            cnta = 0;
            ++ptr;
            continue;
        }
        if (*ptr == 'a')
            ++cnta;
        ++ptr;
    }
    if (cnta == 3)
        ++ok_word_counter;  // обработать счетчик для последнего слова

    /*-------------------------------------------------------------------------------*/
    cout << endl;
    cout << "Words with 3x'a' = " << ok_word_counter << endl; //вывод кол-ва слов с 3х"а"
    return 0;
}

Здесь есть пара подводных камней в виде локали и кодировки строки. Но для латиницы на это можно пока забить.

Жуть даже не в моем костыле, а в том что половина группы так ничего и не понимает в программировании, но это другая история...
За способ спасибо, разобрался что к чему (вроде), но в задании кроме подсчета слов должны те самые слова выводится. Для этого я и использовал вектор как единственный пока известный мне способ для буферизации слова, а буквы считались из самой сроки, сбрасывая счетчик натыкаясь на «небукву».
У меня остался только один вопрос: почему у меня при достижении точки не выполнялся цикл последний раз, если условие while (line[k] != '.') было после цикла, т.е. проход должен был быть?

По аналогии с Вашим кодом я добавил после цикла такой костыль:

if (line[k] == '.') {
        for (int i = 0; i < vcount; i++)
        {
            cout << buf[i];
        }
        ok++;
    }

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

РЕШЕНО
Цикл продолжать не до точки а до конца строки \0.
Я сейчас очень сильно матерюсь на себя.
Я ушел ̶ ̶у̶л̶у̶ч̶ш̶а̶т̶ь̶ пробовать не ухудшить свой костыль добавлением возможности ввода текста с консоли...

но в задании кроме подсчета слов должны те самые слова выводится

Это надо было сразу писать. Но не беда. Решается добавлением еще одного указателя, который отслеживает начало текущего слова. Печать слова вынес в отдельную функцию, что бы не дублировать код.

#include <iostream>

using namespace std;

// вывод фрагмента С-строки в поток
ostream& print_chars(ostream& os, char *begin, char *end) {
    for (char *c = begin; c != end; ++c)
        os << *c;
    os << endl;
    return os;
}

int main() {

    /*-------------------------------------------------------------------------------*/
    char line[] = "archer, eurosport, arabian, kick, ausralia, archer, eurosport, arabian, kick, ausralia, archer, arabian.";
    //char line[] = "aaaa aaa";
    cout << line << endl;
    /*-------------------------------------------------------------------------------*/

    int ok_word_counter = 0;    // счетчик слов с 3х"а"
    char *ptr = line;           // указатель по входной строке
    int cnta = 0;               // счетчик букв "а" в слове
    char *pwstart = line;       // указатель на начало текущего слова

    while (*ptr != '\0') {
        if (!isalpha(*ptr)) {
            if (cnta == 3) {
                ++ok_word_counter;
                print_chars(cout, pwstart, ptr);
            }
            cnta = 0;
            ++ptr;
            pwstart = ptr;
            continue;
        }
        if (*ptr == 'a')
            ++cnta;
        ++ptr;
    }
    if (cnta == 3) {
        ++ok_word_counter;  // обработать счетчик для последнего слова
        print_chars(cout, pwstart, ptr);
    }

    /*-------------------------------------------------------------------------------*/
    cout << endl;
    cout << "Words with 3x'a' = " << ok_word_counter << endl; //вывод кол-ва слов с 3х"а"
    return 0;
}

А еще можно сделать на регулярных выражениях.
Типа знаем С++11. Правда на указателях сильно пошустрее работать будет ;)

#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main() {
    string line{ "archer, eurosport, arabian, kick, ausralia, archer, eurosport, canabian, saaremaa, ausralia, archer, arabian." };
    cout << line << endl;

    int ok_word_counter = 0;                        // счетчик слов с 3х"а"
    const regex rx_word{ R"(\w+)" };                // регулярка на слова
    const regex rx_cond{ R"(([^a]*a){3}[^a]*)" };   // регулярка ровно на три "а" в строке

    sregex_iterator pos(line.cbegin(), line.cend(), rx_word);
    sregex_iterator end;

    for ( ; pos != end; ++pos) {
        if (regex_match(pos->str(), rx_cond)) {
            cout << pos->str() << endl;
            ++ok_word_counter;
        }
    }

    cout << endl;
    cout << "Words with 3x'a' = " << ok_word_counter << endl; //вывод кол-ва слов с 3х"а"
}

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

Ответить

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

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

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

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

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

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