【问题标题】:Why does strtok warn against a const?为什么 strtok 对 const 发出警告?
【发布时间】:2020-05-19 13:30:36
【问题描述】:

我对strtok的理解是,它返回一个指向char数组(char*)中第一个分隔符的指针。

我收到了反对 const char* 作为参数的警告,但我不明白为什么这很重要 - strtok 根本不会修改参数。

我的理解:

const char* mystring = "this, is a test";
char* endstring = strtok(mystring, ',');
char* newstring = strdup(endstring);
printf("started with: %s\n now have: %s\n", mystring, newstring);

应该打印

started with: this, is a test 
now have: , is a test

mystring 完全没有受到影响,当然,我有一个指向它一半的指针,但这没关系。那么为什么 strtok 会抱怨我给它发送了一个 const char* 呢?

【问题讨论】:

  • strtok() 实际上确实修改了参数。再次阅读文档:)
  • 如果您使用该指针strcpyprintf,您会发现提供的字符串在下一个分隔符处以NUL 结尾。指针不是你说的,指向分隔符,而是指向记号的开头。
  • @DarkAtom 谢谢 - 基本的在线示例不是很清楚,但这实际上让我的生活变得轻松多了。
  • 也许strtok 没有正确找到分隔符,因为你传递了它',',它应该是","(可能也包括一个空格)。会有两个编译器警告。
  • @BrydonGibson 不要只看例子。也请查看文档。

标签: c string


【解决方案1】:

函数strtok() 修改它的参数。返回的指针在您的原始字符串内。分隔符(在您的情况下为 ,)被替换为 \0 字符。 strtok() 的下一个调用不应该有一个字符串参数,而是一个 NULL 指针。不过要小心:strtok() 将一串分隔符作为参数,而不是单个字符:

strtok(s, ','); //undefined behavior, interprets the ASCII value ',' as an address
strtok(s, ","); //correct

实际发生了什么?

我们来分析一下这个字符串:

"Hello magic world!\0"

我们如何在上面使用strtok()

char s[] = "Hello magic world!"
char* first = strtok(s, " ");
char* second = strtok(NULL, " ");
char* third = strtok(NULL, " ");

让我们看看它被标记化后的字符串:

"Hello\0magic\0world!\0"
 ^      ^      ^
 |      |      |
first  second  third

可以看到,这3个指针可以作为普通的以空结尾的字符串,但是在这个过程中原始字符串被破坏了。 puts(s) 现在只打印 `Hello"。

printf("%s\n", s);
printf("%s %s %s\n", first, second, third);

Output:
Hello
Hello magic world!

【讨论】:

    【解决方案2】:

    strtok() 不能在字符串文字上使用而不会导致潜在的未定义行为。当您将const char * 作为第一个参数传递时,编译器应该会发出警告。恕我直言,这是一个设计缺陷,这不被视为错误。

    您的代码还有另一个问题:您将字符常量 ',' 作为第二个参数传递,而不是字符串 ","

    要解析常量字符串,您可以使用 strspnstrcspn 来返回多个字符,而无需修改字符串参数。

    这是一个例子:

    const char *mystring = "this, is a test";
    size_t n1 = strcspn(mystring, ",");
    size_t n2 = strspn(mystring + n1, ",");
    char *newstring = strndup(mystring, n1);
    printf("started with: %s\n rest of the string: %s\n", newstring, mystring + n1 + n2);
    

    【讨论】:

      猜你喜欢
      • 2015-02-11
      • 1970-01-01
      • 2018-07-18
      • 1970-01-01
      • 2021-12-27
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 2018-07-09
      相关资源
      最近更新 更多