源实现如下:
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
/*****************************************************************
-
*函数功能:去除字符串左右两边的空格
-
-
*传入参数:str:需要处理的字符串
-
-
*传出参数:无(由于传入的是指针,形参指向元素的改变将影响实参)
-
-
*返回值:无
-
-
*******************************************************************/
-
void trim( char *str )
-
{
-
char *copied, *tail = NULL;
-
-
/*判空*/
-
if ( str == NULL )
-
return;
-
-
/*去除字符串左边空格,并找到字符串右边的第一个空格*/
-
for( copied = str; *str; str++ )
-
{
-
/*当前字符不为空格时,将当前字符拷贝到新的字符串中,并更新tail指针指向的空间
-
为新字符串的尾部*/
-
if ( *str != ' ' && *str != '\t' )
-
{
-
*copied++ = *str;
-
tail = copied;
-
}
-
else
-
{
-
/*当tail不为空时,将当前字符拷贝到新的字符串中:由于tail初值为NULL,
-
找到第一个非空格字符时才会将其值更新,所以能够保证去除字符串左边
-
的空格,而保留中间和右边的空格*/
-
if ( tail )
-
*copied++ = *str;
-
}
-
}
-
-
/*去除字符串右边的空格:如果tail非空,则将tail赋'\0'(将其后的字符截断);
-
否则将字符串清空(即传入字符串全为空格)*/
-
if ( tail )
-
*tail = 0;
-
else
-
*copied = 0;
-
-
return;
-
}
-
-
int main(void)
-
{
-
char string[100] = "
abcd ef gh -- ijk ";
-
trim(string);
-
printf(string);
-
printf("\n");
-
-
return 0;
- }
由于上面的代码需要移动字符串中元素,可能效率较慢,本人的思路是将第一个非空格字符处做一
标记(将一局部指针指向此处),找到右边第一个空格并将其赋值为字符串结束符。最后返回局部指针。程序实现如下:
-
#include <stdio.h>
-
#include <stdlib.h>
-
/*************************************************
-
*函数功能:去除字符串左右两边的空格
-
-
*传入参数:str:需要处理的字符串
-
-
*传出参数:无
-
-
*返回值:处理后的字符串
-
-
************************************************/
-
char * trim( char *str )
-
{
-
char *head, *tail = NULL;
-
-
if ( str == NULL )
-
return str;
-
-
for( head = str; *str; str++ )
-
{
-
if ( *str != ' ' && *str != '\t' )
-
{
-
if (tail == NULL)
-
{
-
head = str;//tail为NULL时,此处为第一个非空格字符,将此位置保存下来
-
}
-
tail = str+1;//更新tail指针的指向为非空格字符的下一个位置
-
}
-
}
-
/*由于tail始终指向非空格字符的下一个位置,当循环退出时,tail指向右边第一个空格*/
-
if ( tail )
-
*tail = 0;
-
else
-
*head = 0;
-
-
return head;
-
}
-
-
int main(void)
-
{
-
char string[100] = "
abcd ef gh -- ijk ";
-
char * p = trim(string);
-
printf(p);
-
printf("\n");
-
-
return 0;
- }
除了上面这种思路,还有一种思路是“从前往后数掉前面的空格”,再“从后往前数掉后面的空格”,等“数”出了实际有效的第一个字符和最后一个字符之后,再用 strcpy 或者 memcpy 拷贝过去。
本人思路:
char *trim(char *str)
{
int i = 0;
int j = 0;
int len = strlen(str);
assert(str !=NULL && len>0);
for (i = 0; i<len; i++)
{
if (*(str+i) != ' ' && *(str+i) != '\t')
{
break;
}
}
for (j = len-1; j>=0; j--)
{
if (*(str+j) !=' ' && *(str+j) != '\t')
{
break;
}
}
*(str+j+1) = '\0';
return str+i;//等价于return memmove(str,str+i,j-i+2);此处其实亦可以用memcpy(参考其实现)
}
事实上,Trim 从算法上来讲,也就这两个思路,大多数人采用的是后面的这个思路,好像依赖于 strlen、memcpy 等库函数的效率后,反而要更快些。而上面的那个思路,似乎没有多少人去想,结果就吃亏在“效率”问题上了。
关于第二种思路在此不再继续探讨,如果有兴趣可以参照文章:
上面这边文章中的不足是,最后的memcpy函数源和目的地址存在重叠情况,结果依赖于实现,应该使用memmove。