在这种特殊情况下,字符串size()函数和strlen之间的区别

时间:2016-11-05 16:58:30

标签: c++

我最近做了这个问题

规格:

  

输入格式第一行包含测试用例数T.下一步,   T行跟随每个包含长字符串S.

     

输出格式对于每个长字符串S,显示SUVO的次数   并且SUVOJIT出现在其中。

我为此编写了以下代码:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int t;
    cin >> t;

    while (t--) {
        int suvo = 0;
        int suvojit = 0;
        string s;
        cin >> s;

        for (int i = 0; i <= s.size() - 7; i++) {
            if (s.substr(i, 7) == "SUVOJIT")
                suvojit++;
        }
        for (int i = 0; i <= s.size() - 4; i++) {
            if (s.substr(i, 4) == "SUVO")
                suvo++;
        }

        cout << "SUVO = " << suvo - suvojit << ", SUVOJIT = " << suvojit << "\n";
    }
    return 0;
}

关于此测试用例的substr()函数的有关超出范围异常的代码:

15
RSUVOYDSUVOJITNSUVOUSUVOJITESUVOSUVOSGSUVOKSUVOJIT
SUVOJITWSUVOSUVOJITTSUVOCKSUVOJITNSUVOSUVOJITSUVOJITSUVOSUVOSUVOJITTSUVOJ
SUVOSUVOSUVOJITASUVOJITGCEBISUVOJITKJSUVORSUVOQCGVHRQLFSUVOOHPFNJTNSUVOJITKSSUVO
SUVOJITSUVOJITJGKSUVOJITISUVOJITKJLUSUVOJITUBSUVOX
MMHBSUVOFSUVOFMSUVOJITUMSUVOJITPSVYBYPMCSUVOJIT
OASUVOSUVOJITSUVOSTDYYJSUVOJITSUVOJITSUVO
RLSUVOCPSUVOJITYSUVOSUVOOGSUVOOESUVOJITMSUVO
WVLFFSUVOJITSUVOVSUVORLESUVOJITPSUVOJITSUVO
RSUVOSUVOJITQWSUVOUMASUVOSUVOJITXNNRRUNUSUVOJIT
HYLSSUVOSUVOSUVOJITPOSUVOJIT
DGMUCSSSUVOJITMJSUVOHSUVOCWTGSUVOJIT
OBNSSUVOYSUVOSUVOJITSUVOJITRHFDSUVODSUVOJITEGSUVOSUVOSUVOJITSUVOSUVOJITSSUVOSUVOSUVOSSUVOJIT
AG
NSUVOJITSUVOSUVOJIT
CGJGDSUVOEASUVOJITSGSUVO

但是,当我不使用s.size()函数时,我将字符串转换为char常量并使用strlen获取它的长度,然后代码没有导致错误和所有内容顺利进行。

所以,我的问题是......为什么会这样?

这是我改变的工作代码:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int t;
    cin >> t;

    while (t--) {
        int suvo = 0;
        int suvojit = 0;
        string s;
        cin >> s;
        int le = strlen(&s[0]);
        for (int i = 0; i <= le - 7; i++) {
            if (s.substr(i, 7) == "SUVOJIT")
                suvojit++;
        }
        for (int i = 0; i <= le - 4; i++) {
            if (s.substr(i, 4) == "SUVO")
                suvo++;
        }

        cout << "SUVO = " << suvo - suvojit << ", SUVOJIT = " << suvojit << "\n";
    }
    return 0;
}

2 个答案:

答案 0 :(得分:3)

在一种情况下,使用size_t,在另一种情况下使用int。

如果长度是例如6个字符,那么s.size() - 7不是-1,而是一个巨大的数字,一切都出错了。但是如果你写int len = strlen(...),那么len - 7确实是-1,一切都很好。

当我看到从size_t中减去一个数字时,这是一个直接的红旗。写“i +7≤s.size()”,而不是“i≤s.size() - 7”。

答案 1 :(得分:1)

首先,在我的测试中,你的第二个导致了一个问题:

enter image description here

其次,特别是对于较旧的编译器(好吧,库,真的),这可能可怕效率低下,创建了大量的临时字符串,只用于与另一个字符串进行比较 1 < / SUP>

所以,让我们考虑一下应该如何完成工作。对于这种情况,std::string有一个名为find的成员。它返回一个字符串在另一个字符串中的位置,如果没有,则返回std::string::npos。当您不想从头开始时,它允许您指定开始搜索的起始位置。

当然,我们还有两个基本相同的代码实例,一次搜索SUVO,另一次搜索SUVOJIT。将搜索代码移入函数后,代码会好得多,因此我们只将搜索代码放在一个位置。

int count_pos(std::string const &haystack, std::string const &needle) {
    size_t pos = 0;
    int ret = 0;

    while ((pos = haystack.find(needle, pos)) != std::string::npos) {
        ++ret;
        ++pos;
    }
    return ret;
}

请注意,这也消除了更多混乱的“东西”,比如必须计算匹配时可能发生的最大位置。

1.为什么编译器/库年龄很重要?较旧的库通常使用COW字符串,为每个字符串动态分配存储空间。最近的那些通常包括所谓的“短字符串优化”,其中短字符串的存储在字符串对象本身内分配,从而避免动态分配。 功能