字符串中如果有一个地方由一个或多个连续的空格组成,就把它们改成单个空格字符。注意当遍历整个字符串时要确保它以NUL字符结尾。
此处的空格的含义包括但不限于空格字符,为什么呢?空格、水平制表、垂直制表、换页、换行、回车在控制台输出的时候都会让我们感觉字符之间由空格隔开了,所以,在遍历字符串的时候,应该对上述特殊字符进行处理。只有这样,才更符合我们的习惯。
#include<stdio.h> #include<assert.h> #define NUL '\0' int is_white(int ch) { return ' ' == ch || '\t' == ch || '\v' == ch || '\f' == ch || '\n' == ch || '\r' == ch; } void deblank(char *str) { assert(NULL != str); /* **将两个指针都指向字符串的首部。 */ char *src = str; char *dest = str; /* **遍历整个字符数组 */ for (; *src != NUL;) { /* **首次出现空格,进行复制, **紧接着再次出现,直接跳过。 */ if (is_white(*src)) { *dest++ = ' '; src++; while (is_white(*src)) { src++; } } /* **如果不是空格的话,后面的值复制到前面去。 */ else { *dest++ = *src++; } } /* **添加结束符 '\0'。 */ *dest = NUL; } int main() { char str[] = "I\t\t\tlike it !"; printf("删除多余的空格前:\n%s\n", str); deblank(str); printf("删除多余的空格后:\n%s\n", str); return 0; }
处于对程序健壮性的考虑,我在删除多余空格函数deblank函数体最前面加上了断言,
只有输入的指针参数非空进行后续操作才是合法的,不然会产生不可预料的后果。
本程序在VS2017下编译运行通过。
对程序进行分析,我们可以发现,判断是否首次是否为“空格”,出现了两重循环,我在第一次创作这篇博客的半个月后,突然想到了改进版本:
- 新的版本只出现了一重循环。
#include<stdio.h> #include<assert.h> #define NUL '\0' int is_white(int ch) { return ' ' == ch || '\t' == ch || '\v' == ch || '\f' == ch || '\n' == ch || '\r' == ch; } void deblank(char* str) { assert(NULL != str); /* **将两个指针都指向字符串的首部。 */ int tag = false;//判断是否为首次出现空格。 char *src = str; char *dest = src; /* **遍历整个字符数组 */ for (; *src != NUL;) { /* **首次出现空格,进行复制, **紧接着再次出现,直接跳过。 */ if (is_white(*src)) { *dest = ' '; if (tag) { dest++; tag = false; } src++; } else { tag = true; *dest++ = *src++; } } /* **添加结束符 '\0'。 */ *dest = NUL; } int main() { char str[] = "I\t\t\tlike it !"; printf("删除多余的空格前:\n%s\n", str); deblank(str); printf("删除多余的空格后:\n%s\n", str); return 0; }