c++拆分字符数组而不使用任何库

ee7vknir  于 2023-01-28  发布在  其他
关注(0)|答案(3)|浏览(135)

我遇到了一个奇怪的问题,当我在函数内部输出printf时,split代码正确返回,但当作为示例调用它时,split代码将错误返回输出。

    • 问题**:当我把它作为一个示例调用时,我如何得到正确的输出?(见下面的用法)

下面是代码:

typedef struct SplitText
{
    int splitLen;
    char* splitTxt[100];
    char* subTxt(char* text, int index, int len)
    {
        char subTxt_[1000];
        int count = 0;
        for (int i = 0; i < 1000; i++)
            subTxt_[i] = '\0';
        for (int i = index; i < index + len; i++)
            subTxt_[count++] = text[i];

        return subTxt_;
    }

    void split(char* text, char sep)
    {
        char separator[3] = { '<', sep, '>' };
        int textLen = strlen(text);
        int splitIndex = 0;
        int splitCount = 0;
        for (int t = 0; t < textLen; t++)
        {
            if (text[t] == separator[0] && text[t + 1] == separator[1] && text[t + 2] == separator[2])
            {
                if (splitIndex != 0)
                    splitIndex += 3;
                splitTxt[splitCount] = subTxt(text, splitIndex, t - splitIndex);
                splitIndex = t;
                
                //correct output
                printf(splitTxt[splitCount]);
                printf("\n");

                splitCount++;
            }
        }
        splitLen = splitCount;
    }
}SplitText;

用途:

SplitText st;
st.split("testing<=>split<=>function<=>", '=');
for (int i = 0; i < st.splitLen; i++)
{
    //incorrect output
    printf(st.splitTxt[i]);
    printf("\n");
}
printf("--------\n");
rta7y2nd

rta7y2nd1#

这一点:

char* subTxt(char* text, int index, int len)
    {
        char subTxt_[1000];

        ...

        return subTxt_;
    }

返回一个指向局部堆栈变量(或局部数组变量)的指针会导致类似这样的奇怪事情发生。
破坏返回指针内容的典型情况是,当调用另一个函数时,subTxt_占用的内存将被下一个调用函数的堆栈变量覆盖。
更好:

char* subTxt(char* text, int index, int len)
    {
        char *subTxt = new char[1000];

        ...

        return subTxt_;
    }

然后确保调用subTxt的人记住返回指针上的delete []
或者直接使用std::string并完成它(除非这是学术练习)。
此外,这是未定义的行为:

for (int t = 0; t < textLen; t++)
    {
        if (text[t] == separator[0] && text[t + 1] == separator[1] && text[t + 2] == separator[2])

t == textLen-1时,则引用text[t+2]text[t+1]是越界访问。请将其更改为:

for (int t = 2; t < textLen; t++)
    {
        if (text[t-2] == separator[0] && text[t -1] == separator[1] && text[t] == separator[2])

并在块内对t执行类似的修复。

e1xvtsh3

e1xvtsh32#

你可以创建一个splitstring函数来代替struct/class。
无论如何,你的代码看起来仍然很像“C”,因为它有固定大小的字符数组,这将限制可用性和稳定性(超出范围的数组错误)。
C中的字符串通常是std::string.类型,然后C使用string_view对该字符串进行查看(因此不会复制任何数据,但这也意味着string_view仅在其查看的字符串存在期间有效)。
如果不知道字符串中子字符串的数目,就不应该使用固定大小的数组,而应该使用std::vector(如果需要,可以在内部调整大小)
这就是split_string函数在当前C++中的样子,注意,与“C”风格的编程相比,代码也更好地显示了它正在做什么,“C”风格的编程显示了更多你正在做什么。

std::vector<std::string_view> split_string(std::string_view string, std::string_view delimiters)
{
    std::vector<std::string_view> substrings;
    if(delimiters.size() == 0ul)
    {
        substrings.emplace_back(string);
        return substrings;
    }

    auto start_pos = string.find_first_not_of(delimiters);
    auto end_pos = start_pos;
    auto max_length = string.length();

    while(start_pos < max_length)
    {
        end_pos = std::min(max_length, string.find_first_of(delimiters, start_pos));

        if(end_pos != start_pos)
        {
            substrings.emplace_back(&string[start_pos], end_pos - start_pos);
            start_pos = string.find_first_not_of(delimiters, end_pos);
        }
    }

    return substrings;
}
xkrw2x1b

xkrw2x1b3#

看一下 std::string_view。你可以避免分配内存,它有一个内置的子字符串函数。当使用printf打印到控制台时要小心,因为“%s”会打印整个字符串。请参阅printf文档。

for(auto view : container_with_string_views)
   printf("%.*s, (int)view.size(), view.data());

相关问题