Trim 堆栈中字符串中的字符?
Trim Characters off a String on the Stack?
我需要一个C函数,它接受一个字符串(分配在栈上,而不是堆上),前后可能有相同的字符;我想 trim 关闭那些字符。我可能不知道有多少 header/footer 个字符,也不一定总是知道冒犯性字符是什么。
换句话说,如果我的原始字符串是:
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] = '[=14=]';
printf("%s\n", trimString( str1, 'x' ) );
printf("END OF PROGRAM.\n");
return 0;
}
这是输出:
This is a stringing.xxxx
END OF PROGRAM.
有两个明显的问题。首先,我认为我正确地去掉了 'x' 字符,但是当我将 trimmed 字符串复制回“str1”变量时,我只用新字符串覆盖了旧字符串的前 n 个字符细绳。原始字符串的剩余部分仍然存在。
更严重的是,我离这样调用这个函数的目标还很远:
str1 = trimString( str1, ‘x’ );
我可以这样调用我的函数:
char tmpStr[50] = trimString( str1, ‘x’ );
memcpy( str1, tmpStr );
但这很痛苦,现在我不得不担心临时字符串的大小。另外,我认为我必须调用 trimString()
很多很多次,所以如果我可以用一行代码就可以了,而不必担心管理临时字符串等,那就太好了。
有什么建议或建议吗?
您需要在移位后的字符串末尾添加一个空终止符。
您还需要使用 memmove()
而不是 strncpy()
,因为后者不允许在重叠字符串之间进行复制。
并且您复制的长度有 off-by-one 错误。
#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, str1+i, (j-i+1) );
str1[j - i + 1] = '[=10=]'; // add null terminator
return str1;
}
int main(){
char str1[50] = "xxxThis is a string.xxxx";
str1[25] = '[=10=]';
printf("%s\n", trimString( str1, 'x' ) );
printf("END OF PROGRAM.\n");
return 0;
}
你做不到
str1 = trimString(...);
因为你不能给数组赋值。你所能做的就是修改它们的内容。
由于函数修改了给定的数组,因此您不需要赋值。你可以写:
trimString(str1, 'x');
printf("%s\n", str1);
给你。
#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] = '[=10=]';
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 != '[=15=]' )
{
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] = '[=15=]';
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;
}
我需要一个C函数,它接受一个字符串(分配在栈上,而不是堆上),前后可能有相同的字符;我想 trim 关闭那些字符。我可能不知道有多少 header/footer 个字符,也不一定总是知道冒犯性字符是什么。
换句话说,如果我的原始字符串是:
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] = '[=14=]';
printf("%s\n", trimString( str1, 'x' ) );
printf("END OF PROGRAM.\n");
return 0;
}
这是输出:
This is a stringing.xxxx
END OF PROGRAM.
有两个明显的问题。首先,我认为我正确地去掉了 'x' 字符,但是当我将 trimmed 字符串复制回“str1”变量时,我只用新字符串覆盖了旧字符串的前 n 个字符细绳。原始字符串的剩余部分仍然存在。
更严重的是,我离这样调用这个函数的目标还很远:
str1 = trimString( str1, ‘x’ );
我可以这样调用我的函数:
char tmpStr[50] = trimString( str1, ‘x’ );
memcpy( str1, tmpStr );
但这很痛苦,现在我不得不担心临时字符串的大小。另外,我认为我必须调用 trimString()
很多很多次,所以如果我可以用一行代码就可以了,而不必担心管理临时字符串等,那就太好了。
有什么建议或建议吗?
您需要在移位后的字符串末尾添加一个空终止符。
您还需要使用 memmove()
而不是 strncpy()
,因为后者不允许在重叠字符串之间进行复制。
并且您复制的长度有 off-by-one 错误。
#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, str1+i, (j-i+1) );
str1[j - i + 1] = '[=10=]'; // add null terminator
return str1;
}
int main(){
char str1[50] = "xxxThis is a string.xxxx";
str1[25] = '[=10=]';
printf("%s\n", trimString( str1, 'x' ) );
printf("END OF PROGRAM.\n");
return 0;
}
你做不到
str1 = trimString(...);
因为你不能给数组赋值。你所能做的就是修改它们的内容。
由于函数修改了给定的数组,因此您不需要赋值。你可以写:
trimString(str1, 'x');
printf("%s\n", str1);
给你。
#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] = '[=10=]';
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 != '[=15=]' )
{
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] = '[=15=]';
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;
}