字符串数据似乎在 for 循环后被删除

String Data seems to be deleted after for loop

本文关键字:循环 删除 for 数据 字符串      更新时间:2023-10-16

在下面的代码中,每当我去调试器,段落的值被删除,或者返回到0,我似乎想不通为什么,想法?

void getFreqLetter(string paragraph){
    char alphabet[26] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
    int counter[26];
    //set counter values to zero
    for (int clear = 0; clear < sizeof(counter) - 1; ++clear){
        counter[clear] = 0;
    }
    cout << paragraph;
    int result = 0;
    for (int i = 0; i < sizeof(paragraph); ++i){
        //case:found
        for (int j = 0; j < sizeof(alphabet) - 1; ++j){
            if (alphabet[j] == paragraph[i]){
                counter[j]++;
            }
        }
        //go through array find largest value
        for (int k = 0; k < sizeof(counter) - 1; ++k){
            if (counter[k] > result){ result = counter[k]; }
        }
        cout << result;
    }
}

总之,所有问题都是由于您滥用sizeof .

sizeof(paragraph) 没有做你认为它正在做的事情:它返回 string 类的大小,而不是字符串实例中的字符数。

您应该使用 paragraph.size() 而不是假设它是std::string类型。

sizeof(alphabet) 通过幸运的巧合返回数组中的元素数:sizeof(char) 由标准定义为 1。这样的"王牌"代码应该附上注释!

你没有那么幸运sizeof(counter).您返回的值是sizeof(int)的倍数,该倍数因平台而异(2、4 和 8 是常见的(。你应该写sizeof(counter) / sizeof(int)sizeof(counter) / sizeof(counter[0]).后者是一些人的首选,因为您不需要对类型进行硬编码,并且由于C++标准不允许零长度数组,因此counter[0]定义良好。

(这里要记住的是,sizeof是在编译时计算的(。

很简单。

你在循环条件中的sizeof(counter)实际上是sizeof(int) * 26的,所以你的字母表被你的循环(从迭代 27 开始(和一些堆栈(特别是将返回地址设置为 0,以及 paragraph 参数的内部(压垮了。

而且你的- 1不应该在那里,因为你使用的是严格的比较。

您可能希望跟踪第一个循环并观察 sizeof(counter) 的值。

如果你想要counter数组中的元素数量,一种惯用的方法是sizeof(counter) / sizeof(counter[0])

此外,string的长度应该由 paragraph.size() 获得,因为 sizeof(paragraph) 返回管理字符串的对象的大小,而不是字符串本身。

最后,sizeof(alphabet)做正确的事情,因为sizeof(char)被定义为 1。

现在,对于一些 C++11 魔法:

#include <array>
const std::array<char,26u> alphabet{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 
    'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 
    's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
std::array<int, 26u> counter;
//set counter values to zero
for (int clear = 0; clear < counter.size(); ++clear){
    counter[clear] = 0;
}

这消除了许多(所有(sizeof陷阱,同时同样高效。

此代码

//set counter values to zero
for (int clear = 0; clear < sizeof(counter) - 1; ++clear){
    counter[clear] = 0;
}

无效,导致内存覆盖。

要么使用

for (int clear = 0; clear < sizeof( counter ) / sizeof( *counter ); ++clear){
    counter[clear] = 0;
}

for (int clear = 0; clear < 26; ++clear){
    counter[clear] = 0;
}

std::memset( counter, 0, 26 * sizeof( int ) );

或者简单地在声明数组时将其初始化为零

int counter[26] = {};

此循环

for (int j = 0; j < sizeof(alphabet) - 1; ++j){
    if (alphabet[j] == paragraph[i]){
        counter[j]++;
    }

也是无效的。字符数组alphabet不包含终止零。所以循环应该写成

for (int j = 0; j < sizeof(alphabet); ++j){
    if (alphabet[j] == paragraph[i]){
        counter[j]++;
    }

并且此循环无效

for (int k = 0; k < sizeof(counter) - 1; ++k){
    if (counter[k] > result){ result = counter[k]; }
}

见上文。

如果对幻数 26 使用命名常量,则不会出错。

例如

const int N = 26;
char alphabet[N] = 
{ 
   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 
   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' 
};
//...
for ( int j = 0; j < N; ++j )
{
        if (alphabet[j] == paragraph[i]){
            counter[j]++;
}

要找到最大的数字,您可以使用在标头 <algorithm> 中声明的标准算法std::max_element。例如

int ewsult = *std::max_element( counter, counter + 26 );