字符串中如果有一个地方由一个或多个连续的空格组成,就把它们改成单个空格字符。注意当遍历整个字符串时要确保它以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;
}