在 C 中操作字符串时非常相似的函数出错
Error in very similar functions while manipulating strings in C
我正在学习 C,在处理字符串时遇到了一个问题。
在我正在解决的一个问题中,我应该编写一个函数来获取一个字符串和一个字符并删除所有出现的给定字符,然后我必须 return 修改后的字符串。
我写的函数是这样的:
char *strdelc3(char *s, char ch){
for(int i=0,j=0; i!=strlen(s)+1; ++i)
if(s[i]!=ch){
s[j]=s[i];
++j;
}
return s;
}
当我传递一个字符串和一个字符作为参数时:
main(){
char s[20]="mary";
puts(strdelc3(s,'r'));
}
The output is: Segmentation fault(core dumped),
根据我的研究,这意味着我正在访问不属于我的内存。
解决方案具有以下代码:
char *strdelc4(char *s, char ch){ /*Correct*/
int i,j;
for(i=0, j=0; s[i]!='[=12=]'; ++i)
if(s[i]!=ch){
s[j]=s[i];
++j;
}
s[j]='[=12=]';
return s;
}
基本和我的差不多,不过这块做工不错!
由于这两个代码非常相似,所以我看不出有什么问题......
我已经研究了两者,但我不明白我的问题是什么...有人可以帮忙吗?
问题出在你的循环条件中:
i!=strlen(s)+1
您试图在此处使用 strlen(s)+1
以避免必须添加空字节。但是在这样做时,strlen(s)
会在您移动终止空字节后发生变化。
在循环的前 4 次迭代中,strlen(s)
为 4。在下一次迭代中,i
为 4,strlen(s)+1
为 5,因此您再次进入循环。然后移动空字节。现在在接下来的迭代中,strlen(s)
是 3,i
是 5。条件仍然为真,因此您继续前进,离开字符串的末尾。这会调用 undefined behavior,在这种情况下会导致崩溃。
第二段代码通过根据 i
的索引显式查找空字节并在循环后将空字节附加到结果字符串来解决此问题。
代码的更简单版本将使用 do - while
循环而不是 for()
:
char *strdelc5idx(char *s, char ch){
int i=0, j=0;
do {
if (s[i] != ch)
s[j++] = s[i];
} while (s[i++] != 0);
return s;
}
这将在 测试之前复制字符串终止 NUL 字符 ,因此您不需要单独的指令。但是,这需要推迟 i++
递增,以便迭代结束时的循环条件测试在迭代中复制的相同字符。因此 i++
和 j++
不再一起出现,这可能会使这段代码乍一看不太清晰。
等效指针版本:
char *strdelc5ptr(char *s, char ch){
char *d = s, *f = s;
do {
if (*f != ch)
*d++ = *f;
} while (*f++);
return s;
}
我正在学习 C,在处理字符串时遇到了一个问题。 在我正在解决的一个问题中,我应该编写一个函数来获取一个字符串和一个字符并删除所有出现的给定字符,然后我必须 return 修改后的字符串。 我写的函数是这样的:
char *strdelc3(char *s, char ch){
for(int i=0,j=0; i!=strlen(s)+1; ++i)
if(s[i]!=ch){
s[j]=s[i];
++j;
}
return s;
}
当我传递一个字符串和一个字符作为参数时:
main(){
char s[20]="mary";
puts(strdelc3(s,'r'));
}
The output is: Segmentation fault(core dumped),
根据我的研究,这意味着我正在访问不属于我的内存。 解决方案具有以下代码:
char *strdelc4(char *s, char ch){ /*Correct*/
int i,j;
for(i=0, j=0; s[i]!='[=12=]'; ++i)
if(s[i]!=ch){
s[j]=s[i];
++j;
}
s[j]='[=12=]';
return s;
}
基本和我的差不多,不过这块做工不错! 由于这两个代码非常相似,所以我看不出有什么问题...... 我已经研究了两者,但我不明白我的问题是什么...有人可以帮忙吗?
问题出在你的循环条件中:
i!=strlen(s)+1
您试图在此处使用 strlen(s)+1
以避免必须添加空字节。但是在这样做时,strlen(s)
会在您移动终止空字节后发生变化。
在循环的前 4 次迭代中,strlen(s)
为 4。在下一次迭代中,i
为 4,strlen(s)+1
为 5,因此您再次进入循环。然后移动空字节。现在在接下来的迭代中,strlen(s)
是 3,i
是 5。条件仍然为真,因此您继续前进,离开字符串的末尾。这会调用 undefined behavior,在这种情况下会导致崩溃。
第二段代码通过根据 i
的索引显式查找空字节并在循环后将空字节附加到结果字符串来解决此问题。
代码的更简单版本将使用 do - while
循环而不是 for()
:
char *strdelc5idx(char *s, char ch){
int i=0, j=0;
do {
if (s[i] != ch)
s[j++] = s[i];
} while (s[i++] != 0);
return s;
}
这将在 测试之前复制字符串终止 NUL 字符 ,因此您不需要单独的指令。但是,这需要推迟 i++
递增,以便迭代结束时的循环条件测试在迭代中复制的相同字符。因此 i++
和 j++
不再一起出现,这可能会使这段代码乍一看不太清晰。
等效指针版本:
char *strdelc5ptr(char *s, char ch){
char *d = s, *f = s;
do {
if (*f != ch)
*d++ = *f;
} while (*f++);
return s;
}