【问题标题】:Passing an array of characters as function arguments将字符数组作为函数参数传递
【发布时间】:2018-10-03 20:03:43
【问题描述】:

我试图将字符串作为参数传递给函数,但它会引发分段错误(核心转储)错误。你能告诉我我在这里犯了什么错误吗?代码如下:

replaceChars(char str[], char sChar[], char rChar)
{
int i,j;
printf("rChar is %c", rChar);
printf("sChar is %s", sChar);

for(i = 0; i <= strlen(str); i++)
{
    for(j = 0; j <= strlen(sChar); j++)
    {
     if(str[i] == sChar[j])  
     {
        str[i] = rChar;
        //printf("The New String is %c", str[i]);
     }
    }
}

printf("The New String is %s", str);
}
void main()
{
char myString[36], schar[36], rchar;

printf("Please enter a string:");

scanf("%[^\n]s", &myString);

printf("Which characters to replace?");
scanf(" %[^\n]c", &schar);
printf("With which character?");
scanf(" %[^\n]c", &rchar);

replaceChars(myString, schar, rchar);

}

【问题讨论】:

  • 在你的循环中用&lt;替换&lt;=
  • 请使用Tour 并阅读How to Ask。请edit您的帖子并修复您的代码缩进。如果minimal reproducible example 包含一个调用您正在调试的函数的main 函数,那就太好了。
  • 另外,学习使用开发环境中可用的任何调试器。通过单步执行您自己的代码并观察您的局部变量,很容易检测到缓冲区溢出。
  • 感谢@kerrytazi 的建议!但是,在我进行上述更改后,str 值将打印为 null。你能帮我解决这个问题吗?
  • scanf(" %[^\n]c", &amp;rchar); 不好

标签: c arrays string function


【解决方案1】:

这里有两个问题。

首先,当您循环访问strsChar 时:

我试图将字符串作为参数传递给函数,但它会引发分段错误(核心转储)错误。你能告诉我我在这里犯了什么错误吗?代码如下:

for(i = 0; i <= strlen(str); i++)
{
    for(j = 0; j <= strlen(sChar); j++)
    {

您使用&lt;= 作为退出条件。数组索引从 0 开始,因此有效索引是从 0 到 length-1。您将从 0 变为长度,因此您正在步进数组的末尾。读取数组末尾会调用undefined behavior

更改使用&lt;的条件:

for(i = 0; i < strlen(str); i++)
{
    for(j = 0; j < strlen(sChar); j++)
    {

第二个问题是你如何读取值:

scanf("%[^\n]s", &myString);
...
scanf(" %[^\n]c", &schar);
...
scanf(" %[^\n]c", &rchar);

%[] 格式说明符后面不需要任何字符,它需要一个 char * 作为参数,它指向 char 数组的第一个元素。在前两种情况下,您传递的是数组的地址而不是数组本身(衰减为指针),并且在不需要的 %[] 格式之后有一个额外的字符。在第三种情况下,当格式需要指向多个字符的指针时,您将指针传递给单个 char。因为要读取单个字符,所以要改用 %c 格式说明符。

scanf("%35[^\n]", myString);
...
scanf(" %35[^\n]", schar);
...
scanf(" %c", &rchar);

另请注意,前两个字段的宽度会限制读取的字符数,以免超出数组。

【讨论】:

    【解决方案2】:

    你能告诉我我在这里犯了什么错误吗?

    除了@dbush 的好答案,OP 的代码不必要地低效。

    使用下面的更正代码,并假设str, sChar的初始长度分别为S,C

    for(i = 0; i < strlen(str); i++) {
      for(j = 0; j < strlen(sChar); j++) {
        if(str[i] == sChar[j]) {
          str[i] = rChar;
        }
      }
    }
    

    for(i = 0; i &lt; strlen(str); i++) { 和后面的str[i] = rChar; 要求代码查找str 的长度最多S 次,每个strlen(str) 需要O(S) 次操作。

    如果S 是一个重要的值,比如 1000,那么这个 1000*1000 很容易影响整体性能。一个简单的解决方案是计算一次长度或查找 null 字符

    // for(i = 0; i < strlen(str); i++) {
    S = strlen(str);
    for(i = 0; i < S; i++) {
    // or
    for(i = 0; str[i]; i++) {
    

    内循环也会发生同样的事情。然而,聪明的编译器可以看到sChar 没有改变,并且可以利用理解strlen() 没有会导致不同结果的副作用。通过这样的优化,strlen(sChar) 可以真正调用一次,即使strlen(sChar) 在更高的for (i...) 循环内。

    只测试 null 字符 仍然很容易和惯用。

        // for(j = 0; j < strlen(sChar); j++)
        // better as
        for(j = 0; sChar[j]; j++)
    

    但为什么这不适用于for(i = 0; i &lt; strlen(str); i++) 循环?

    在该循环中,代码可以修改str[],因此编译器无法像for(j = 0; sChar[j]; j++)那样进行优化。

    这也引出了一个问题,如果替换字符rChar空字符,代码应该怎么做?

    在我看来,代码可以继续,多次替换为'\0,也可以在此之后简单地返回。

           str[i] = rChar;
           if (rChar == '\0') return; // Possible way to handle \0
    

    【讨论】:

      最近更新 更多