c - 从堆栈上的字符串中修剪字符?
问题描述
我需要一个 C 函数,它接受一个字符串(分配在堆栈上,而不是在堆上),它的正面和背面可能具有相同的字符;我想剪掉那些字符。我可能不知道有多少页眉/页脚字符,也不一定总是知道有问题的字符是什么。
换句话说,如果我的原始字符串是:
xxxThis is a string.xxxx
……那我想要……</p>
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, 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;
}
推荐阅读
- android - 我们可以从 WebApp 发出通知吗?
- javascript - 如何使用javascript验证输入是否为可读日期格式
- docker - Docker 将驱动程序和中间件安装到容器中
- amazon-web-services - AWS 每个项目是否提供免费套餐?
- clojure - Clojure 中带有映射的函数参数
- laravel - laravel 验证器未验证图像图像尺寸是否正确
- git - git - 致命:您当前的分支似乎已损坏(可能来自中断的拉动)
- php - 我想将图像上传到 laravel 中的公共文件夹和数据库中,但我遇到了一些问题
- flutter - 如何在特定位置在字符串中添加空格
- git - 我可以删除历史记录并保留最近 git 提交的 sha 吗?