C中strtok的问题

时间:2018-01-30 01:09:17

标签: c strtok

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

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变量中。我可以将第一个名称存储在相应的变量中,但正如您从上面链接中的图像中看到的那样,我得到了一个?输出中的符号应该是姓氏的第一个首字母。

1 个答案:

答案 0 :(得分:0)

char a[] = { *info };

这是你的问题。这创建的是一个单字节字符数组,其中包含info的第一个字符,而不包含任何其他内容。

由于strtok需要字符串,它可能会在该单字节数组的末尾运行并使用内存中发生的任何事情。这就是为什么你看到第一个角色没问题而且没有其他的东西(尽管从技术上来说,作为未定义的行为,字面意思任何是允许发生的。)

不应该构造一个单字节数组,而应该只使用传入的字符串:

name = strtok(info, "/");

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

并且,如果你想保留它以供日后使用,这可能是调用者而不是函数所带来的最佳成本(当关于是否需要所需的信息时,该函数总是复制它是浪费的/ em>或者只有来电者才知道。

为了制作令牌化的副本,它就像:

一样简单
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);
}