【问题标题】:C String parsing errors with strtok(),strcasecmp()使用 strtok()、strcasecmp() 的 C 字符串解析错误
【发布时间】:2014-03-15 22:20:08
【问题描述】:

所以我是 C 和整个字符串操作的新手,但我似乎无法让 strtok() 工作。似乎每个人都有相同的 strtok 模板:

char* tok = strtok(source,delim);
do
{
 {code}
 tok=strtok(NULL,delim);
}while(tok!=NULL);

所以我 try 用分隔符作为空格键来执行此操作,似乎 strtok() 不仅在第一次运行后读取 NULL(第一次进入 while/do-while ) 不管字符串有多大,但它似乎也破坏了源,将源字符串变成了与 tok 一样的东西。

这是我的代码的 sn-p:

char* str;
scanf("%ms",&str);
char* copy = malloc(sizeof(str));
strcpy(copy,str);
char* tok = strtok(copy," ");
if(strcasecmp(tok,"insert"))
{
 printf(str);
 printf(copy);
 printf(tok);
}

然后,这里是输入“insert a b c d e f g”的一些输出

aaabbbcccdddeeefffggg

“插入”似乎完全消失了,我认为这是 strcasecmp() 的错。另外,我想指出,我意识到 strcasecmp() 似乎将我的源字符串全小写,我不介意。 Anyhoo,输入“插入插入插入”绝对不会产生任何输出。就好像这些功能只是吞噬了“插入”这个词,无论它出现多少次。我可能*最终只使用了一些按字符读取字符串的 C 函数,但如果可能的话,我想避免这种情况。谢谢百万人,感谢您的帮助。

【问题讨论】:

  • 您可以使用char* copy = strdup(str); 复制str,而不是错误地使用malloc,而忘记实际执行复制。
  • 您不应使用未知字符串作为第一个参数调用printf。第一个参数是一个格式字符串,它使用% 分隔格式说明符来解释后续参数。如果您的任何未知字符串包含%,就会发生不好的事情。请改用puts(str)、fputs(str, stdout) 或printf("%s", str)。
  • strtok 通过用NUL 终止符替换分隔符来改变它正在扫描的字符串。如果你打印copy,在上面运行strtok 之后,你只会看到第一个标记,因为NUL 终止符在插入后永远不会被删除。但是,每次使用NULL 第一个参数对strtok 的调用都将在上一次调用停止的地方(就在现在是NUL 的分隔符之后),并从那里向前扫描,返回从那个位置。
  • strcmp 和 strcasecmp 返回两个字符串之间的字典顺序差异。当字符串相等时,它返回0,它在C 中是一个假值。如果您希望if 的主体在tok 等于"insert" 时执行,那么您应该显式检查返回0 的值。即if(strcasecmp(tok, "insert") == 0).
  • %s scanf 格式说明符读取以空格分隔的字符串,因此您只会在缓冲区中获得"insert"。输入的其余部分仍将位于标准输入缓冲区中。

标签: c string strtok


【解决方案1】:

使用第二个 sn-p 代码,您有 五个 问题:第一个是您的 scanf 函数格式不标准,@ 是什么987654324@应该怎么办? (参见例如标准函数的here for a good reference。)

第二个问题是您在指针上使用了地址运算符,这意味着您将指向char(例如char**)的指针传递给@ 987654327@ 功能。如您所知,scanf 函数希望其参数作为指针,但由于字符串(以指向字符形式的指针或数组形式)已经是指针,因此您不必对字符串参数使用地址运算符。

第三个问题,一旦你解决了前面的问题,指针str 是未初始化。您必须记住,未初始化的局部变量是真正未初始化的,它们的值是不确定的。实际上,这意味着它们的值看起来是随机的。所以str 将指向一些“随机”内存。

第四个问题是malloc 调用,您在指针上使用sizeof 运算符。这将返回指针的大小,而不是它指向的大小。

第五个问题,当你对指针copy 执行strtok 时,copy 指向的内存内容未初始化。您为其分配内存(通常为 4 或 8 个字节,具体取决于您在 32 位或 64 位平台上,请参阅第四个问题),但您从未对其进行初始化。

因此,只需四行代码即可解决五个问题。这很不错! ;)

【讨论】:

  • 非常感谢您的快速和彻底的依赖。我忘记了“m”代表什么,但它本质上允许我为 str 动态分配内存。我不知道为什么,但是对于整个 scanf("%ms"... 行,这是我似乎可以读取字符串而不会出现分段错误的唯一方法。那部分实际上是老师给我的.我可以尝试解决这个问题,但我不确定你所说的第三个问题是什么意思。scanf 不将 str 初始化为通过 stdin 获得的值吗?毕竟,str 似乎至少包含部分它是在...之后给出的值
  • @user3118524 第一个、第二个和第三个问题是相关的。如果 'm' 代码为字符串分配内存,您可能可以忽略这些点。其他两点仍然有效。
  • strcasecmp 和 strtok。我认为我理解的部分问题是我认为“初始化”与“定义”是同义词,但它似乎不是(别担心,我现在要去研究了:))。至于第四个问题,这是我似乎可以在新字符串中为 strcpy 命令分配足够空间的唯一方法(我发布的 sn-p 中缺少该空间)。这实际上不是复制粘贴,因为我正在使用某种应用程序连接到我的 uni 的 linux 平台。非常感谢您迄今为止的帮助。我会根据您所说的情况尽我所能更正并发布结果。
  • 哇,你真快 :D ... 至于第四个问题,如果我不调用 strtok,那么 copy 似乎工作得非常好,就像 str 对 printf 等一样。它们甚至与 strcmp 相同。
  • @user3118524 关于第四点,你知道strlen函数吗?实际上,您可以通过使用(实际上是非标准但无处不在)strdup 函数来解决第四个和第五个问题(在我的答案中)。
【解决方案2】:

您似乎正尝试在“插入”一词之后打印 3 次空格分隔的标记。这符合你的要求吗?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    char str[BUFSIZ] = {0};
    char *copy;
    char *tok;
    int i;

    // safely read a string and chop off any trailing newline
    if(fgets(str, sizeof(str), stdin)) {
        int n = strlen(str);
        if(n && str[n-1] == '\n')
            str[n-1] = '\0';
    }

    // copy the string so we can trash it with strtok
    copy = strdup(str);

    // look for the first space-delimited token
    tok = strtok(copy, " ");

    // check that we found a token and that it is equal to "insert"
    if(tok && strcasecmp(tok, "insert") == 0) {
        // iterate over all remaining space-delimited tokens
        while((tok = strtok(NULL, " "))) {
            // print the token 3 times
            for(i = 0; i < 3; i++) {
                fputs(tok, stdout);
            }
        }
        putchar('\n');
    }

    free(copy);

    return 0;
}

【讨论】:

  • 我不在家里的电脑上,但我肯定会在回家后尝试一下。非常感谢您的回复,抱歉让您久等了=)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
  • 1970-01-01
相关资源
最近更新 更多