C 中 strtok 的问题

Issues with strtok in C

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

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 函数以“/”拆分字符串以分隔拳头和姓氏并将它们存储在 a 的 first_name 和 last_name 变量中学生结构。我可以获取存储在相应变量中的名字,但正如您从上面 link 中的图像中看到的那样,我得到的是 ?输出中姓氏的第一个首字母所在的符号。

char a[] = { *info };

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

因为 strtok 需要一个 字符串, 它可能会 运行 离开那个单字节数组的末尾并使用那里发生的任何事情在记忆中。这就是为什么您看到第一个字符没问题而没有其他字符的原因(尽管从技术上讲,作为未定义的行为,字面上 任何事情 都允许发生)。

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

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

在我看来,"cleaner" 的实现方式如下:

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

    *(s->first_name) = '[=13=]';
    *(s->last_name) = '[=13=]';

    // 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);
}