【问题标题】:Why strtok() splits string that i didn't even passed to it?为什么 strtok() 会拆分我什至没有传递给它的字符串?
【发布时间】:2017-05-26 23:27:59
【问题描述】:

我需要将字符串与文件分开。字符串 = "21:12:36 14:45:25 08:17:24" 当我执行 strtok() 并将所有标记放入数组时,一切正常,但是当我第二次执行 strtok() 时,一切都搞砸了。 示例:

char *p = strtok (code, " ");
while (p != NULL){
    dal[i++] = p;
    p = strtok (NULL, " ");
}

输出:

dal[0] = 21:12:36
dal[1] = 14:45:25
dal[2] = 08:17:24

我复制 dal 数组,当我第二次执行 strtok 时,我更改了原始字符串(代码)和 dal 副本,即使我传递了 dal 数组仅适用于 strtok()。我尝试将 dal 发送到 LinkedList,但在第二次 strtok 之后,甚至 LinkedList 都被更改了。

声明:

char *dal[20], *dalcopy[20];
//copying below
for(int k = 0; k<i; k++){
    dalcopy[v] = dal[k];
    v = v+1;
}

例子:

for (int j = 0; j<i; j++){
    char *o = strtok(dal[j], ":");
    while (o != NULL){
        for(int h = 0; h<3; h++){
            if(h == 0){vienas[b].Hour = atoi(o);}
            if(h == 1){vienas[b].Min = atoi(o);}
            if(h == 2){vienas[b].Sec = atoi(o);}
            o = strtok (NULL, ":");
        }            
        b = b+1;
    }

链表示例:

char *p = strtok (code, " ");
while (p != NULL){
    dal[i++] = p;
    put(head, p); //puts each element to list end
    p = strtok (NULL, " ");
}
printf("%s\n", show_by_index(&head, 0)); **Output == 21 after second strtok**

输出:

original string = 21
dal[0] = 21
dal[1] = 14
dal[2] = 08
dalcopy[0] = 21
etc...

为什么会这样?

【问题讨论】:

  • 您的问题似乎缺少关键的代码。 daldalcopy 是如何声明的? 如何 dalcopy 创建?复制指针数组不会复制这些指针指向的数据。我怀疑dalcopy 是一个别名数组。
  • char *dal[20], *dalcopy[20]; - dal 声明dalcopy[0] = dal[0];
  • 请给minimal reproducible example。没有显示太多。
  • 顺便说一句,dalcopy[0] = dal[0]; 表明我的预感是正确的。您正在为同一字符串创建别名,而不是字符串的副本。您需要malloc 存储副本,然后使用strcpystrtok 是一种破坏性功能,您创建的不是真正的副本,不会受到这种破坏。
  • 这可能会有所帮助。但是为什么这个函数会触及 LinkedList 项呢?

标签: c string split linked-list strtok


【解决方案1】:

您要记住的两个主要事项是:

  1. strtok 是一个破坏性函数,正如 @JohnColeman 在 cmets 中所说的那样。这意味着 strtok 修改了传递给它的字符串(第一个参数)
  2. strtok 为您提供指针,它们指向字符串的不同部分,然后您将它们存储在数组dal 中。现在,您创建另一个类似的指针数组 dalcopy(假设您修复了 what @David told you)并让它们指向字符串 code 的相同部分,就像 dal 一样。

daldalcopy 指向字符串 code 的相同标记。因此,您对它们所做的任何更改也会影响code,因为它们指向它。

strtok 之前的所有内容:

+--------+--------+--------+--------+
| dal[0] | dal[1] | dal[2] | dal[3] | ... = dal
+--------+--------+--------+--------+

+------------------------------+
| "21:12:36 14:45:25 08:17:24" | = code
+------------------------------+

strtok 和“复制”之后:

+--------+--------+--------+--------+
| dal[0] | dal[1] | dal[2] | dal[3] | ... = dal
+--------+--------+--------+--------+
   ↓         ↓          ↓
+---------------------------------+
| "21:12:36\0014:45:25\008:17:24" | = code
+---------------------------------+
   ↑         ↑          ↑
   |          \         \----\
+------------+------------+------------+------------+
| dalcopy[0] | dalcopy[1] | dalcopy[2] | dalcopy[3] | ... = dalcopy
+------------+------------+------------+------------+

如您所见,您并没有复制它,而只是创建了一个别名。

解决方案是strdup/malloc+strcpy 令牌。

【讨论】:

  • +rep 干得好!非常感谢。
【解决方案2】:
char *dal[20], dalcopy[20];
//copying below
for(int k = 0; k<i; k++){
    dalcopy[v] = dal[k];
    v = v+1;
 }

这不可能。因为dalcopy 是一个字符数组,所以dalcopy[v] 是一个字符。但是dal[k] 不是一个字符(因为dal 是一个指向字符的指针数组),所以这个赋值完全没有意义。

【讨论】:

  • 修复声明只会遇到别名问题。
  • 这就是为什么您应该始终发布完整的、可编译的代码,这些代码您已确认复制了您所询问的问题。
  • 您的回答现在没有意义,因为 OP 更改了他/她的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-04
  • 2023-03-16
相关资源
最近更新 更多