问题描述
我需要一个C函数,该函数需要一个字符串(分配在堆栈上,而不是堆上),该字符串在正面和背面可能具有相同的字符;我要剪裁那些字符。我可能不知道有多少个页眉/页脚字符,也不一定总是知道有问题的字符。
换句话说,如果我的原始字符串是:
xxxThis is a string.xxxx
...然后我想要...
This is a string.
返回。理想情况下,我会喜欢这样的解决方案:
char str1[50] = “xxxThis is a string.xxxx”;
str1 = trimString( str1 );
printf(“Returned string is:: %s\n”,str1); // prints “This is a string.”
这是我的代码:
char* trimString( char* str1,char x ){
int i = 0;
int j = (int)strlen( str1 ) - 1;
printf("string is :: >>%s<<\n",str1);
while( str1[i] == x ){
i++;
}
while( str1[j] == x ){
j--;
}
str1 = strncpy( str1,str1+i,(j-i) );
return str1;
}
int main(){
char str1[50] = "xxxThis is a string.xxxx";
str1[25] = '\0';
printf("%s\n",trimString( str1,'x' ) );
printf("END OF PROGRAM.\n");
return 0;
}
以下是输出:
This is a stringing.xxxx
END OF PROGRAM.
有两个明显的问题。首先,我认为我正确地去除了'x'字符,但是当我将修剪后的字符串复制回“ str1”变量时,我只会用新字符串覆盖旧字符串的前n个字符。原始字符串的其余部分仍然存在。
更严重的是,我并没有达到像这样调用此函数的目标:
str1 = trimString( str1,‘x’ );
我可以用类似这样的方式调用我的函数:
char tmpStr[50] = trimString( str1,‘x’ );
memcpy( str1,tmpStr );
但这很痛苦,现在我不得不担心临时字符串的大小。另外,我认为我必须多次调用trimString()
,所以如果我能用一行代码来执行而不必担心管理临时字符串等,那将是很棒的。>
有什么建议或建议吗?
解决方法
您在这里。
#include <stdio.h>
#include <string.h>
char * trimString( char *s,char c )
{
size_t i = 0;
while ( s[i] == c ) i++;
size_t n = strlen( s + i );
while ( n && s[n + i - 1] == c ) --n;
s[n + i] = '\0';
if ( i != 0 )
{
memmove( s,s + i,n + 1 );
}
return s;
}
int main(void)
{
char s[50] = "xxxThis is a string.xxxx";
puts( s );
puts( trimString( s,'x' ) );
return 0;
}
程序输出为
xxxThis is a string.xxxx
This is a string.
对于您的函数实现,然后它可以在例如用户传递空字符串时调用未定义的行为。在这种情况下,变量j的值可以为负
int j = (int)strlen( str1 ) - 1;
并使用此负值,该函数将访问字符数组之外的内存。
while( str1[j] == x ){
j--;
}
此外,无法检查j
的当前值是否等于或小于0。
此外,您可能无法使用函数strncpy
str1 = strncpy( str1,str1+i,(j-i) );
无论如何,此调用都会忘记复制终止零。
请注意,只有在i
不等于0的情况下,才需要在字符数组内移动字符串。否则就足以正确设置终止零。
为使功能更安全,您可以在函数内检查所传递的字符(第二个参数)是否等于零。
例如
#include <stdio.h>
#include <string.h>
char * trimString( char *s,char c )
{
if ( c != '\0' )
{
size_t i = 0;
while ( s[i] == c ) i++;
size_t n = strlen( s + i );
while ( n && s[n + i - 1] == c ) --n;
s[n + i] = '\0';
if ( i != 0 )
{
memmove( s,n + 1 );
}
}
return s;
}
int main(void)
{
char s[50] = "xxxThis is a string.xxxx";
puts( s );
puts( trimString( s,'x' ) );
return 0;
}
,
您需要在移位的字符串的末尾添加一个空终止符。
您还需要使用memmove()
代替strncpy()
,因为后者不允许在重叠的字符串之间进行复制。
要复制的长度出现一个错误的错误。
#include <stdio.h>
#include <memory.h>
char* trimString( char* str1,char x ){
int i = 0;
int j = (int)strlen( str1 ) - 1;
printf("string is :: >>%s<<\n",str1);
while( str1[i] == x ){
i++;
}
while( str1[j] == x ){
j--;
}
memmove( str1,(j-i+1) );
str1[j - i + 1] = '\0'; // add null terminator
return str1;
}
int main(){
char str1[50] = "xxxThis is a string.xxxx";
str1[25] = '\0';
printf("%s\n",trimString( str1,'x' ) );
printf("END OF PROGRAM.\n");
return 0;
}
你不能做
str1 = trimString(...);
因为您不能分配给数组。您所能做的就是修改其内容。
由于该函数修改了给定的数组,因此不需要分配。您可以这样写:
trimString(str1,'x');
printf("%s\n",str1);