【问题标题】:Issues with strtok in CC 中 strtok 的问题
【发布时间】:2018-01-30 01:09:16
【问题描述】:

我的代码中有以下函数来提取名称:

void student_init(struct student *s, char *info) {
    char *name;
    char *name2;
    char a[] = { *info };
    name = strtok(a, "/");
    strcpy(s->first_name, name);
    name2 = strtok(NULL, "/");
    strcpy(s->last_name, name2);
}

当我运行它时,我看到:

Please enter a student information or enter "Q" to quit.
Daisy/Lee
A student information is read.: Daisy/Lee
Please enter a row number where the student wants to sit.
1
Please enter a column number where the student wants to sit.
2
The seat at row 1 and column 2 is assigned to the student: D . �
?.?. ?.?. ?.?.
?.?. ?.?. D.�.
?.?. ?.?. ?.?.

我正在尝试在 c 程序中使用 strtok 函数用“/”分割字符串以分隔拳头和姓氏,并将它们存储在学生结构的 first_name 和 last_name 变量中。我可以获取存储在相应变量中的名字,但正如您从上面链接中的图像中看到的那样,我得到了一个 ?输出中姓氏的第一个首字母应该是的符号。

【问题讨论】:

  • 欢迎来到 SO!请阅读tour 然后How to Ask 然后minimal reproducible example 然后编辑您的问题。
  • 请不要张贴代码和输出的图片,我们不能从图片中复制粘贴代码并自行复制。
  • char a[] = { *info }; 不会像您认为的那样做。由于infochar **info 是单个字符。

标签: c strtok


【解决方案1】:
char a[] = { *info };

这是你的问题。这将创建一个单字节字符数组,其中包含 info 的第一个字符,仅此而已。

由于strtok 需要一个字符串,它可能会从那个单字节数组的末尾运行并使用内存中发生的任何内容。这就是为什么您看到第一个字符没问题,而其他的不多(尽管从技术上讲,作为未定义的行为,实际上 anything 是允许发生的)。

与其构造一个单字节数组,不如直接使用传入的字符串:

name = strtok(info, "/");

您制作本地副本的唯一原因是您要标记的字符串不允许更改(例如,如果它是字符串文字,或者如果您想保留它以供以后使用)。由于您的示例运行显示您正在此字符串读入,因此它不能是字符串文字。

而且,如果您想保留它以供以后使用,这可能是调用者而不是函数所产生的最佳成本(当关于它是否需要的信息时,函数总是重复复制是很浪费的 只有调用者知道)。

为了制作一个用于标记化的副本,它很简单:

char originalString[] = "pax/diablo";

scratchString = strdup(originalString);
if (scratchString != NULL) {
    student_init (struct student *s, scratchString);
    free (scratchString);
} else {
    handleOutOfMemoryIssue();
}

useSafely (originalString);

如果您的实现没有 strdup(它是 POSIX 而不是 ISO),请参阅 here

在我看来,“更清洁”的实现应该是:

void student_init (struct student *s, char *info) {
    // Default both to empty strings.

    *(s->first_name) = '\0';
    *(s->last_name) = '\0';

    // Try for first name, exit if none, otherwise save.

    char *field = strtok (info, "/");
    if (field == NULL) return;
    strcpy (s->first_name, field);

    // Try for second name, exit if none, otherwise save.

    if ((field = strtok (NULL, "/")) == NULL) return;
    strcpy (s->last_name, field);
}

【讨论】:

  • 问题在于strtok 修改了它的输入。调用者可能没有预料到这一点,因此先将输入复制到堆栈会更安全。
猜你喜欢
  • 1970-01-01
  • 2011-03-11
  • 1970-01-01
  • 1970-01-01
  • 2012-10-16
  • 1970-01-01
  • 1970-01-01
  • 2011-12-04
相关资源
最近更新 更多