从C中删除字符串中的空格?

Tyl*_*eat 45 c string spaces

在C中从字符串中删除空格的最简单,最有效的方法是什么?

Aar*_*ron 76

最简单,最有效率通常不会一起......

这是一个可能的解决方案(未经测试):

void remove_spaces(char* s) {
    const char* d = s;
    do {
        while (*d == ' ') {
            ++d;
        }
    } while (*s++ = *d++);
}
Run Code Online (Sandbox Code Playgroud)

  • @Suppressingfire:假设你的意思是'RemoveSpaces("blah");`,而不是`char a [] ="blah"; RemoveSpaces(a);`,然后是未定义的行为.但这不是这段代码的错.建议不要将只读字符串传递给记录的函数,以修改传递给它的字符串(例如,通过删除空格);-) (9认同)
  • ***i = 0**和***i ='\ 0'**是相同的:) (7认同)
  • 我想你应该做*i ='\ 0'; 到底. (4认同)
  • 如果输入源是从字符串文字初始化会发生什么? (3认同)
  • @strikersps 赋值通常在 C 等语言中返回分配的值,因此当您到达字符串末尾并分配空字符时,它将被解释为假值并且循环将中断。我喜欢这段代码。它是如此密集和美丽! (3认同)
  • 怎么...这如何运作?我是C和指针的新手,因此不胜感激。 (2认同)
  • @starscream_disco_party 将两个指针指向同一地址。当传入函数的指针指向空格字符时,只需增加 s 即可。这实际上会移动超过 1 个或多个空格字符,但这不会触及我们创建的另一个指针 (d)。然后在该操作之后,将 d 的值(它仍然指向最后一个非空格或开始元素)分配给 s 的值,我们使其“跳过”所有空格字符。分配完成后,我们将增加两个指针。聪明的。不过,在分配周围需要双括号 (2认同)
  • @JoeMcDonagh 你能告诉我 while 循环在什么条件下会中断吗?每次迭代后,s 和 d 指针都会递增。当 d 到达 '\0' 时,它会将 '\0' 分配给 s 所指向的位置,之后 s 和 d 都递增一个位置,之后 while 如何终止? (2认同)

Kor*_*nel 18

这是一个非常紧凑但完全正确的版本:

do while(isspace(*s)) s++; while(*d++ = *s++);
Run Code Online (Sandbox Code Playgroud)

在这里,仅仅为了我的娱乐,代码高尔夫版本并不完全正确,并让评论者感到不安.

如果你可以冒一些未定义的行为,并且永远不会有空字符串,你可以摆脱身体:

while(*(d+=!isspace(*s++)) = *s);
Run Code Online (Sandbox Code Playgroud)

哎呀,如果按空间你的意思只是空间特征:

while(*(d+=*s++!=' ')=*s);
Run Code Online (Sandbox Code Playgroud)

不要在生产中使用它:)


Lun*_*din 11

正如我们从发布的答案中看到的那样,这绝对不是一项微不足道的任务.当面对这样的任务时,似乎许多程序员选择将常识抛到窗外,以便产生他们可能想出的最隐蔽的片段.

需要考虑的事项:

  • 您将需要复制字符串,并删除空格.修改传递的字符串是不好的做法,它可能是一个字符串文字.此外,有时将字符串视为不可变对象也有好处.
  • 您不能假设源字符串不为空.它可能只包含一个空终止字符.
  • 调用函数时,目标缓冲区可以包含任何未初始化的垃圾.检查它是否为空终止没有任何意义.
  • 源代码文档应说明目标缓冲区需要足够大以包含修剪后的字符串.最简单的方法是使其与未修剪的字符串一样大.
  • 当函数完成时,目标缓冲区需要保持一个空终止字符串,不带空格.
  • 考虑是否要删除所有空格字符或仅删除空格' '.
  • C编程不是一场竞争,因为谁可以尽可能多地挤压一条线路上的运营商.相反,一个好的C程序包含可读代码(总是最重要的质量),而不会牺牲程序效率(有点重要).
  • 因此,通过让它成为复制代码的一部分,您无法获得隐藏目标字符串的空终止插入的奖励积分.相反,将null终止插入显式化,以表明您不是偶然设法使其正确.

我会怎么做:

void remove_spaces (char* restrict str_trimmed, const char* restrict str_untrimmed)
{
  while (*str_untrimmed != '\0')
  {
    if(!isspace(*str_untrimmed))
    {
      *str_trimmed = *str_untrimmed;
      str_trimmed++;
    }
    str_untrimmed++;
  }
  *str_trimmed = '\0';
}
Run Code Online (Sandbox Code Playgroud)

在此代码中,源字符串"str_untrimmed"保持不变,这通过使用适当的const正确性得到保证.如果源字符串只包含空终止,则不会崩溃.它始终为null终止目标字符串.

内存分配留给调用者.算法应该只专注于完成预期的工作.它删除所有空格.

代码中没有任何细微的技巧.它不会尝试在一条线上挤入尽可能多的运算符.它将成为IOCCC的一个非常差的候选人.然而,它将产生与更加模糊的单线版本相同的机器代码.

在复制某些东西时,你可以通过将两个指针都声明为restrict程序员和编译器之间的契约来优化一点,程序员保证目标和源不是同一个地址(或者更确切地说,他们指向的数据)只能通过那个指针而不是通过其他指针访问.这允许更有效的优化,因为编译器然后可以直接从源复制到目的地,而在它们之间没有临时存储器.

  • 这是我见过的最明智的答案。内容清晰、简洁、初学者容易理解!谢谢。 (2认同)

And*_*mar 8

在C中,您可以就地替换一些字符串,例如strdup()返回的字符串:

char *str = strdup(" a b c ");

char *write = str, *read = str;
do {
   if (*read != ' ')
       *write++ = *read;
} while (*read++);

printf("%s\n", str);
Run Code Online (Sandbox Code Playgroud)

其他字符串是只读的,例如在代码中声明的字符串.您必须将这些内容复制到新分配的内存区域,并通过跳过空格来填充副本:

char *oldstr = " a b c ";

char *newstr = malloc(strlen(oldstr)+1);
char *np = newstr, *op = oldstr;
do {
   if (*op != ' ')
       *np++ = *op;
} while (*op++);

printf("%s\n", newstr);
Run Code Online (Sandbox Code Playgroud)

你可以看到为什么人们发明了其他语言;)