来自strtok

时间:2015-11-04 21:55:32

标签: c++ string

更新:找到一些解决方法。见下文。

我编写了一个C ++(几乎是C除了new)函数,以便解析一个具有给定分隔符的字符串(以某种方式Cocoa的NSString -componentsSeparatedByString等价物。)

我正在做一些断言以测试我的代码,我已经使用strlen作为它的第一个元素。

实际上我是通过迭代使用这个功能的。不在其他方面,但在迭代的第一步中,我发现该字符串为"A",但strlen计算的长度为4

所以我进入调试器并打印出值,字符串是正确的,但值是'\xef''\xbb'之类的字符。似乎存在内存损坏。

LLVM调试器也无法正确解释堆栈变量(我想),0x0是什么意思?我知道它指的是0x0000000000000000,但它是怎么来的?它也无法分辨数组的元素。

#ifndef BUFSIZ
#define BUFSIZ 1024
#endif

char **componentsSeparatedByString(const char *string, const char *delimiter) {
    if (strcmp(string, "")) {
        char **components = new char*[BUFSIZ + 1]();

        //  Copying string because strtok is destructive
        char *input = new char[strlen(string) + 1]();
        strcpy(input, string);

        unsigned long count = 0;

        char *token = strtok(input, delimiter);
        while (token != NULL) {
            components[count] = new char[strlen(token) + 1]();
            strcpy(components[count++], token);

            token = strtok(NULL, delimiter);
        }

        //  Releasing that temporary string
        delete input;

        return components;
    } else {
        return nullptr;
    }
}

以下是调试器的一些结果:

首先,linesArraychar ***,表示字符串数组的数组。它包含通过迭代由此函数解析的字符串。由于此函数返回一个字符串数组,linesArray包含所有这些结果。

提到的断言是strlen(linesArray[i][0]) == 1。这个断言只在迭代的第一步失败,其中i = 0。之后没有错,所以我先尝试迭代的第二步:

(lldb) po linesArray[1][0]
"P"

(lldb) po linesArray[1][0][0]
'P'

(lldb) po linesArray[1][0][0] == 'P'
true

一切看起来都很棒。让我们为第一个做:

(lldb) po linesArray[0][0]
"A"

(lldb) po linesArray[0][0][0]
'\xef'

(lldb) po linesArray[0][0][0] == '\xef'
false

(lldb) po linesArray[0][0][0] == 'A'
false

如你所见lldb与自身矛盾。我无法找出发生这种情况的原因。是否存在内存损坏?

以下是我从文件中获取原始字符串的代码:

char ***linesArray = new char**[BUFSIZ + 1]();
char **lines = new char*[BUFSIZ + 1]();
lines[0] = new char[BUFSIZ + 1]();
unsigned long count = 0;
std::ifstream file("whoo.mmp");

while (file.getline(lines[count], BUFSIZ)) {
    lines[count][strlen(lines[count]) - 1] = '\0';
    lines[++count] = new char[BUFSIZ + 1]();
}

for (CFUInteger i = 0; lines[i]; ++i) {
    linesArray[i] = componentsSeparatedByString(lines[i], ";");

    for (CFUInteger b = 0; linesArray[i][b]; ++b) {
        std::cout << "line: " << i << ", command: " << b << " -> \"" << linesArray[i][b] << "\" : " << strlen(linesArray[i][b]) << '\n';
    }

    delete lines[i];
} 

delete[] lines;

该断点处的内存十六进制转储,显示0x100300340linesArray[0][0][0]指向的地址。

Memory hex dump

如有任何进一步的信息,可以根据要求添加,谢谢你的帮助。

更新

将行结束字符从Unix更改为Windows,现在一切正常,除了最后一行。这也可以通过另一种解决方法来解决。

尽管如此,我还是无法说服自己那个解决方案,这是混淆的。我使用libstdc++(GNU C ++标准库)作为标准库,gnu++11作为C ++语言方言。

1 个答案:

答案 0 :(得分:0)

你应该添加更好的边界检查一件事。我不认为strcmp(字符串,“”)将测试字符串是否为空,如果这是预期的。它只会测试一个空字符串。此外,使用分隔符而不进行检查。

我也希望你的代码可以删除在这个函数中用new分配的所有代码。您需要担心字符串数组以及正在创建的每个元素。

否则我不会立即看到任何错误,但如果你开始使用三指针,我会质疑我的设计。那就是说你知道你想要做的比我做得更好,所以我会告诉你。祝你好运。