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

时间:2014-09-10 07:51:43

标签: c++ arrays string data-loss

在下面的代码中,每当我去调试器时,段落的值被删除,或者返回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;
    }
}

3 个答案:

答案 0 :(得分:3)

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

造成的

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

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

sizeof(alphabet)以幸运巧合返回数组中元素的数量:标准的sizeof(char) 定义为1.这样的&#34; ace&#34 ;代码应附加评论!

sizeof(counter)你不是很幸运。您获得的价值是sizeof(int)的倍数,因平台而异(2,4和8很常见)。您应该写sizeof(counter) / sizeof(int)sizeof(counter) / sizeof(counter[0])。后者是一些人喜欢的,因为你不需要硬编码类型,因为C ++标准不允许零长度数组,counter[0]定义明确。

(这里要记住的是sizeof在编译时进行评估。

答案 1 :(得分:3)

易。循环条件中的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个陷阱,同时效率很高。

答案 2 :(得分:0)

此代码

//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]++;
}

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

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