【问题标题】:C++ program to count repeated words in a cstringC ++程序计算cstring中的重复单词
【发布时间】:2022-07-14 13:34:59
【问题描述】:

我一直在开发一个 C++ 程序,我已经制定了逻辑,但我无法执行它。问题是:

任务:编写一个程序,仅使用函数,具有以下特征。

  1. 程序从文件中读取段落并存储在字符串中。
  2. 然后程序计算段落中每个单词的出现次数,并存储所有单词及其出现次数。
  3. 如果该词在整个字符串中出现了多次,则它应该只存储该词在其总出现次数中的一次。
  4. 上述(第 3 部分)中描述的输出必须存储在一个新文件中。 样本输入: 是 是 是 是 是 是 是 是 是 是 是 是 是 是

    样本输出:

    是 5

    3

    和 4

    只有1个

    那 1

    我将缩短我编写的 Occurrence 程序, 我的逻辑是将令牌存储到字符数组中,然后将该数组与主要字符数组进行比较并进行增量:

     void occurances() {
        char* string = getInputFromFile();
        char separators[] = \",.\\n\\t \";
        char* token;
        char* nextToken;
        char* temp[100];
        token = strtok_s(string, separators, &nextToken);
        cout << temp;
        int counter = 0;
        int i = 0;
        while ((token != NULL)) {
            temp[i] = token;
            i++;
            for (int i = 0; i < strlen(string); i++) {
                for (int j = 0; j < 100; j++) {
                    if ((strcmp(token, *temp)) == 0) {
                        counter++;
                    }
                }
                cout << temp << \" : \" << counter << endl;
            }
            if (token != NULL) {
                token = strtok_s(NULL, separators, &nextToken);
            }
        }
    }
    

    我知道这段代码很荒谬,但请任何人好心给我一个线索,实际上我是 C++ 的新手。谢谢

  • 使用 std::string 而不是 C 字符串。使用std::unordered_map&lt;&gt;() 来计算您的单词。
  • 是的,这很容易,但我在这个阶段被严格禁止使用它们
  • 那么,您将不得不更清楚地概述您的要求和限制。如果这是作业就好了。没有理由隐瞒事实。使用我看到的代码,我不相信这甚至是 C++ 分配。
  • 如果您不允许在 C++ 课程中创建自己的类,并且不允许使用std::string 处理字符串,我会退出该课程。这是我很久以来听到的最荒谬的事情。
  • ...好的,所以它是“以错误的顺序学习所有内容”类型的课程之一。听起来很痛苦。

标签: c++ arrays pointers char c-strings


【解决方案1】:

如果将令牌存储到数组中,则该数组应该动态增长,因为一开始不知道令牌的数量。而且根据任务描述,不能使用C++标准容器,所以需要手动实现动态数组,例如:

#include <iostream>

std::size_t increase_capacity_value(std::size_t capacity) {
    if (capacity == 0) {
        return 1;
    }
    else if (capacity < (SIZE_MAX / 2)) {
        return capacity * 2;
    }
    return SIZE_MAX;
}

bool increase_array_capacity(char**& tokens_array, std::size_t*& tokens_count, std::size_t& capacity) {
    const std::size_t new_capacity = increase_capacity_value(capacity);
    if (new_capacity <= capacity) {
        return false;
    }

    const std::size_t tokens_array_byte_size = new_capacity * sizeof(char*);
    char** const new_tokens_array = static_cast<char**>(std::realloc(tokens_array, tokens_array_byte_size));
    if (new_tokens_array == nullptr) {
        return false;
    }

    tokens_array = new_tokens_array;

    const std::size_t tokens_count_byte_size = new_capacity * sizeof(std::size_t);
    std::size_t* const new_tokens_count = static_cast<std::size_t*>(std::realloc(tokens_count, tokens_count_byte_size));
    if (new_tokens_count == nullptr) {
        return false;
    }

    tokens_count = new_tokens_count;
    capacity = new_capacity;
    return true;
}

bool add_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
    if (array_size == array_capacity) {
        if (!increase_array_capacity(tokens_array, tokens_count, array_capacity)) {
            return false;
        }
    }

    tokens_array[array_size] = token;
    tokens_count[array_size] = 1;
    ++array_size;

    return true;
}

std::size_t* get_token_count_storage(char* token, char** tokens_array, std::size_t* tokens_count, std::size_t array_size) {
    for (std::size_t i = 0; i < array_size; ++i) {
        if (std::strcmp(token, tokens_array[i]) == 0) {
            return tokens_count + i;
        }
    }
    return nullptr;
}

bool process_token(char* token, char**& tokens_array, std::size_t*& tokens_count, std::size_t& array_size, std::size_t& array_capacity) {
    std::size_t* token_count_ptr = get_token_count_storage(token, tokens_array, tokens_count, array_size);
    if (token_count_ptr == nullptr) {
        if (!add_token(token, tokens_array, tokens_count, array_size, array_capacity)) {
            return false;
        }
    }
    else {
        ++(*token_count_ptr);
    }
    return true;
}

int main() {
    char string[] = "is the is and the is and the and is and only that is";
    char separators[] = ",.\n\t ";

    std::size_t token_array_capacity = 0;
    std::size_t token_array_size = 0;
    char** tokens_array = nullptr;
    std::size_t* tokens_count = nullptr;

    char* current_token = std::strtok(string, separators);
    while (current_token != nullptr) {
        if (!process_token(current_token, tokens_array, tokens_count, token_array_size, token_array_capacity)) {
            break;
        }
        current_token = std::strtok(nullptr, separators);
    }

    // print the report only if all tokens were processed
    if (current_token == nullptr) {
        for (std::size_t i = 0; i < token_array_size; ++i) {
            std::cout << tokens_array[i] << " : " << tokens_count[i] << std::endl;
        }
    }

    std::free(tokens_array);
    std::free(tokens_count);
}

godbolt.org

【讨论】:

  • 好吧,如果我想在一个数组中存储一次任何标记,然后在删除字符数组中的重复项时用新单词替换它怎么办
【解决方案2】:

好吧,如果我想在一个数组中存储一次任何标记,然后在删除字符数组中的重复项时用新单词替换它怎么办

这也是可能的解决方案。但一般情况下,也需要为当前令牌动态分配内存。因为一开始也不知道令牌的长度:

void replace_chars(char* str, const char* chars_to_replace) {
    while (str && *str != '\0') {
        str = std::strpbrk(str, chars_to_replace);
        if (str == nullptr) {
            break;
        }

        const std::size_t number_of_delimiters = std::strspn(str, chars_to_replace);
        for (std::size_t i = 0; i < number_of_delimiters; ++i) {
            str[i] = '\0';
        }

        str += number_of_delimiters;
    }
}

bool keep_token(char*& token_storage, const char* new_token) {
    if (new_token == nullptr) {
        return false;
    }

    const std::size_t current_token_len = token_storage ? std::strlen(token_storage) : 0;
    const std::size_t requried_token_len = std::strlen(new_token);

    if (token_storage == nullptr || current_token_len < requried_token_len) {
        token_storage =
            static_cast<char*>(std::realloc(token_storage, (requried_token_len + 1) * sizeof(char)));
        if (token_storage == nullptr) {
            return false;
        }
    }

    std::strcpy(token_storage, new_token);
    return true;
}

std::size_t count_tokens_and_replace(char* str, std::size_t str_len, const char* token) {
    std::size_t number_of_tokens = 0;
    std::size_t i = 0;

    while (i < str_len) {
        while (str[i] == '\0') ++i;

        if (std::strcmp(str + i, token) == 0) {
            replace_chars(str + i, token);
            ++number_of_tokens;
        }

        i += std::strlen(str + i);
    }

    return number_of_tokens;
}

int main() {
    char string[] = "is the is and the is and the and is and only that is";
    char separators[] = ",.\n\t ";

    const std::size_t string_len = std::strlen(string);
    replace_chars(string, separators);

    std::size_t i = 0;
    char* token = nullptr;

    while (true) {
        while (i < string_len && string[i] == '\0') ++i;

        if (i == string_len || !keep_token(token, string + i)) break;

        std::cout << token << " : " << count_tokens_and_replace(string + i, string_len - i, token) << std::endl;
    }

    std::free(token);
}

godbolt.org

但是如果知道令牌长度不能大于N,则可以使用静态字符数组来保留当前令牌。它将允许从代码中删除动态内存分配。

【讨论】:

    猜你喜欢
    • 2012-10-04
    • 2017-01-31
    • 2013-12-06
    • 2011-04-25
    • 1970-01-01
    • 2023-03-31
    • 2013-12-09
    • 2019-10-16
    • 1970-01-01
    相关资源
    最近更新 更多