【问题标题】:strsep() causing Segmentation faultstrsep() 导致分段错误
【发布时间】:2020-12-31 09:14:39
【问题描述】:

我的程序有问题,我从 strsep() 收到分段错误,该错误是从 GDB 获得的,并且有错误消息

Program received signal SIGSEGV, Segmentation fault.
0x00002aaaaad64550 in strsep () from /lib64/libc.so.6

我的代码如下:

int split(char *string, char *commands, char *character) {
    char **sp = &string;
    char *temp;
    temp = strdup(string);
    sp = &temp;
    for (int i = 0; i < 100; i++) {
        commands[i] = strsep(sp, character);
        if (commands[i] == '\0') {
            return 0;
        }
        if (strcasecmp(commands[i], "") == 0) {
            i--;
        }
        printf("%d", i);
    }
    return 0;
}

任何帮助都将不胜感激,因为我花了几个小时试图解决这个问题

函数的参数是("Hello World", "@", "&amp;")

编辑

所以我设法通过将代码更改为来摆脱段错误

int split(char* string, char* commands, char* character) {
        for(int i = 0; i < 100; i++) {
                commands[i] = strsep(&string, character);
                if(commands[i] == '\0') {
                        return 0;
                }
                if(strcasecmp(&commands[i], "") == 0) {
                        i--;
                }
        }
        return 0;
}

但是现在我遇到了一个新问题,即返回每个索引都超出范围的空数组的命令。

编辑 2

我还应该澄清一下我正在尝试做的事情,所以基本上命令的类型是char* commands[100],我想在修改原始指针数组并存储时将它传递给函数并说“Hello World”进入 commands[0] 然后我想在函数之外修改这个值。

【问题讨论】:

  • 什么是commands?请发布一个重现问题的整个程序,包括对该函数的调用。
  • 您将一个指向字符的指针分配给commands[i],它是一个char。您可能正在做的事情会覆盖 strsep 所作用的指针。
  • 我现在不能尝试这个,所以我不会发布答案,但看起来你想摆脱前 4 行(sptemp 变量) , 并将其称为strsep(&amp;string, character)。还要检查 string 是否设置为 null
  • AFAICS,段错误来自写入字符串文字。 strsep() 尝试修改 Hello World(至少如果您传递了一个空格而不是 @ 符号),然后也尝试修改 command。我认为你也在滥用strsep()。我希望将&amp;string 作为第一个参数传递,而不是sp,即使sp 中的值是&amp;string。至少,这是它更传统的用法。
  • 是的,很抱歉我看到 docs.oracle.com/cd/E19048-01/chorus401/806-4422/6jdgkltde/… 作为如何使用 strsep 的示例的混乱

标签: c segmentation-fault strsep


【解决方案1】:

你对commands的使用与函数原型不一致:调用者传递了一个100个数组char*commands应该是指向char *数组的指针,因此是char **commands或@的类型987654326@。为了让调用者确定存储在数组中的令牌数量,您应该在末尾存储一个 NULL 指针或返回此数字或两者兼而有之。

存储commands[i] = strsep(...) 不正确,因为commands 被定义为char *,而不是char **

令人惊讶的是,strsep() 中出现分段错误,因为参数似乎正确,除非 character 恰好是无效指针。

相反,您的未定义行为很可能导致strcasecmp(commands[i], "") 中的分段错误,因为commands[i]char 值,而不是有效指针。

这是修改后的版本:

// commands is assumed to point to an array of at least 100 pointers
// return the number of tokens or -1 is case of allocation failure
int split(const char *string, char *commands[], const char *separators) {
    char *dup = strdup(string + strcspn(string, separators));
    if (temp == NULL)
        return -1;
    char *temp = dup;
    char **sp = &temp;
    int i = 0;
    while (i < 99) {
        char *token = strsep(sp, separators);
        if (token == NULL) // no more tokens
            break;
        if (*token == '\0') // ignore empty tokens
            continue;
        commands[i++] = token;
    }
    commands[i] = NULL;
    if (i == 0) {
        free(dup);
    }
    return i;
}

可以通过释放commands 数组中的第一个指针来释放为令牌分配的内存。复制这些令牌可能更简单,以便以更通用的方式释放它们。

【讨论】:

  • 通过temp 分配的内存泄漏——不能保证第一个标记从字符串的开头开始(通常;样本数据在该分数上是安全的)。
  • 总的来说它可以工作,但是它并没有解决我的新问题,即每个命令索引都超出范围。
  • @JonathanLeffler:我修复了内存泄漏问题。我在发布后就注意到了,但我不在报道范围内:)
  • @JustinHaindel:你的函数还有不正确的原型吗?
猜你喜欢
  • 2018-06-09
  • 2021-03-26
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 2019-07-21
  • 2018-07-28
  • 2014-04-25
相关资源
最近更新 更多