【问题标题】:How to replace characters by strtok function - C?如何用strtok函数替换字符-C?
【发布时间】:2020-05-30 23:55:13
【问题描述】:

我真的想将我的 char 数组中的所有空格 ' ' 更改为 NULL -

#include <string.h>

void ReplaceCharactersInString(char *pcString, char *cOldChar, char *cNewChar) {
    char *p = strtok(pcString, cOldChar);
    strcpy(pcString, p);
    while (p != NULL) {
        strcat(pcString, p);
        p = strtok(cNewChar, cOldChar);
    }          
}

int main() {
    char pcString[] = "I am testing";
    ReplaceCharactersInString(pcString, " ", NULL);
    printf(pcString);
}

输出:Iamtesting

如果我只是把printf(p)函数放在前面:

p = strtok(cNewChar, cOldChar);

结果我得到了我需要的东西——但问题是如何将它存储在pcString(直接)?

或者有更好的解决方案来简单地做到这一点?

【问题讨论】:

  • 只是为了学习,为什么要将空格转换为空字符?
  • 我想解码特定类型的令牌 - 字符串、数字 - 下一个函数需要这个。
  • 如果p 最初是NULL 怎么办?你不检查这个,strcpy 会出现段错误。
  • @CraigEstey 你说得对,我在调试器的确切strcpy() 行上收到了段错误消息。我不确定到底出了什么问题。
  • @AlwaysDissapointed:你不想得到字符串 INULLamNULLtestingNULL,你想要"I\0am\0testing\0" 和字符串实际结尾的一些指示。您可能想要分配一个指针数组并让它们指向单词。

标签: c string strtok


【解决方案1】:

虽然某些函数期望 [single] 字符串被预解析为:I\0am\0testing,但很少见

而且,如果您有 多个 个空格/分隔符,您会得到(例如)foo\0\0bar,这可能是您不想要的。

而且,main 中的 printf 只会打印字符串中的 first 标记,因为它将在 first EOS 上停止(即 '\0' )。

(即)你可能不想要strcpy/strcat

更有可能的是,您想要填充指向您解析的标记的 char * 指针数组。

所以,你想要传递char **argv,然后执行:argv[argc++] = strtok(...);,然后执行:return argc


以下是我将如何重构您的代码:

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

#define ARGMAX  100

int
ReplaceCharactersInString(int argmax,char **argv,char *pcString,
    const char *delim)
{
    char *p;
    int argc;

    // allow space for NULL termination
    --argmax;

    for (argc = 0;  argc < argmax;  ++argc, ++argv) {
        // get next token
        p = strtok(pcString,delim);
        if (p == NULL)
            break;

        // zap the buffer pointer
        pcString = NULL;

        // store the token in the [returned] array
        *argv = p;
    }

    *argv = NULL;

    return argc;
}

int
main(void)
{
    char pcString[] = "I am testing";
    int argc;
    char **av;
    char *argv[ARGMAX];

    argc = ReplaceCharactersInString(ARGMAX,argv,pcString," ");

    printf("argc: %d\n",argc);
    for (av = argv;  *av != NULL;  ++av)
        printf("'%s'\n",*av);

    return 0;
}

这是输出:

argc: 3
'I'
'am'
'testing'

【讨论】:

  • 我不同意你对 OP 想要什么或不想要什么的假设。
  • @Cheatah 很好,但是以什么方式?仅将 00 放入字符串中而无法获取单个标记并不是非常有用。但是,/proc/self/cmdline 就是这样做的,所以这是可能的。做我所做的 确实 将 EOS 嵌入到原始字符串中。其他人采用了char ** 方法——这就是 chrqlie 在他的回答中所做的。由于 OP 的帖子有点含糊,因此 OP 必须回应/澄清他/她是否没有得到他/她想要的东西。并且 OP 确实说过:或者可能有更好的解决方案来简单地做到这一点? 如果 OP 想要 删除 空格,他/她需要这么说,但代码完全是不同的
  • 如果 OP 声明他们“真的想将我的 char 数组中的所有空格 ' ' 更改为 NULL”,我会相信他们的话。因此,我也不同意 OP 对此含糊其辞。
  • @Cheatah 这不是 OP 帖子的一部分,只是最近的评论(在我的帖子后 16 小时)而且,它仍然含糊不清,因为 NULL 表示 #define NULL (void *) 0 为反对嵌入式'\0' 那么,OP 如何才能真正使用 结果?这开始看起来像一个 XY 问题:mywiki.wooledge.org/XyProblem
【解决方案2】:

当源和目标在内存中重叠时,不应使用strcat strcpy

遍历数组并将匹配的字符替换为所需的字符。
由于零是字符串的一部分,printf 将在第一个零处停止,strlen 不能用于打印长度。 sizeof 可以作为pcString 定义在同一个作用域内。
请注意,ReplaceCharactersInString 不会再次工作,因为它会在第一个零处停止。可以编写该函数以接受长度参数并使用长度进行循环。

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

void ReplaceCharactersInString(char *pcString, char cOldChar,char cNewChar){
    while ( pcString && *pcString) {//not NULL and not zero
        if ( *pcString == cOldChar) {//match
            *pcString = cNewChar;//replace
        }
        ++pcString;//advance to next character
    }
}

int main ( void) {
    char pcString[] = "I am testing";
    ReplaceCharactersInString ( pcString, ' ', '\0');
    for ( int each = 0; each < sizeof pcString; ++each) {
        printf ( "pcString[%02d] = int:%-4d char:%c\n", each, pcString[each], pcString[each]);
    }
    return 0;
}

【讨论】:

    【解决方案3】:

    您希望将字符串拆分为由空格分隔的单个标记,例如"I\0am\0testing\0"。您可以为此使用strtok(),但此功能容易出错。我建议你分配一个指针数组并让它们指向单词。请注意,拆分源字符串是草率的,并且不允许标记相邻,例如1+1。您可以改为分配字符串。

    这是一个例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char **split_string(const char *str, char *delim) {
        size_t i, len, count;
        const char *p;
    
        /* count tokens */
        p = str;
        p += strspn(p, delim);      // skip initial delimiters
        count = 0;
        while (*p) {
            count++;
            p += strcspn(p, delim); // skip token
            p += strspn(p, delim);  // skip delimiters
        }
    
        /* allocate token array */
        char **array = calloc(sizeof(*array, count + 1);
        p = str;
        p += strspn(p, delim);      // skip initial delimiters
        for (i = 0; i < count; i++) {
            len = strcspn(p, delim); // token length
            array[i] = strndup(p, len); // allocate a copy of the token
            p += len;               // skip token
            p += strspn(p, delim);  // skip delimiters
        }
        /* array ends with a null pointer */
        array[count] = NULL;
        return array;
    }
    
    int main() {
        const char *pcString = "I am testing";
        char **array = split_string(pcString, " \t\r\n");
        for (size_t i = 0; array[i] != NULL; i++) {
            printf("%zu: %s\n", i, array[i]);
        }
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      strtok 函数几乎完全符合您的要求。它基本上用'\0' 字符替换下一个分隔符并返回指向当前标记的指针。下次您调用strtok 时,您应该传递一个NULL 参数(请参阅strtok 的文档),它将指向下一个标记,该标记将再次由'\0' 分隔。阅读更多正确使用 strtok 的示例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-16
        • 1970-01-01
        • 2014-12-22
        • 2019-03-25
        相关资源
        最近更新 更多