【问题标题】:Segmentation fault occurring when modifying a string using pointers?使用指针修改字符串时发生分段错误?
【发布时间】:2011-01-08 15:17:48
【问题描述】:

上下文

我正在学习 C,我正在尝试使用指针反转字符串。 (我知道你可以使用数组;这更多是关于学习指针。)

问题

尝试运行以下代码时,我不断收到分段错误。 GCC 似乎不喜欢 *end = *begin; 行。 为什么会这样?

特别是因为我的代码与the non-evil C function already discussed in another question 几乎相同

#include <stdio.h>
#include <string.h>

void my_strrev(char* begin){
    char temp;
    char* end;
    end = begin + strlen(begin) - 1;

    while(end>begin){
        temp = *end;
        *end = *begin;
        *begin = temp;
        end--;
        begin++;
    }
}

main(){
    char *string = "foobar";
    my_strrev(string);
    printf("%s", string);
}

【问题讨论】:

标签: c string pointers reverse


【解决方案1】:

一个问题在于你传递给函数的参数:

char *string = "foobar";

这是一个分配在只读部分的静态字符串。当您尝试用

覆盖它时
*end = *begin;

你会得到段错误。

试试

char string[] = "foobar";

您应该会注意到不同之处。

关键点是,在第一种情况下,字符串存在于只读段中,只使用指向它的指针,而在第二种情况下,堆栈中保留了具有适当大小的字符数组,静态字符串(始终存在)被复制到其中。之后你就可以随意修改数组的内容了。

【讨论】:

  • char *string = strdup( "foobar" ); 这样的东西会起作用。
  • 非常感谢 Remo.D。就是这样!
  • @x4u。是的,但是您应该在完成后释放 strdup() 返回的内存。我承认在这种情况下并不重要,但我仍然不建议使用 strdup() ,除非它是唯一明智的选择。
  • @brice: yw :) 从只读存储器中读取是什么意思?
  • 为了清楚起见,char *s = "blah" 为 5 个字符分配存储空间,这些字符可能是只读的,也可能不是只读的。在大多数情况下,存储位于程序指令的机器代码旁边的只读内存段中。另一方面,char s[] = "blah"; 在堆栈(即本地存储)上分配一个可修改的 5 个字符数组。这总是可以修改的。查看 (stackoverflow.com/questions/2036096/…) 了解有关文字字符串的更多详细信息。
【解决方案2】:

您还可以利用字符串末尾的空字符来交换字符串中的字符,从而避免使用任何额外的空间。代码如下:

#include <stdio.h>

void reverse(char *str){    
    int length=0,i=0;

    while(str[i++]!='\0')
        length++;

    for(i=0;i<length/2;i++){
        str[length]=str[i];
        str[i]=str[length-i-1];
        str[length-i-1]=str[length];
    }

    str[length]='\0';
}

int main(int argc, char *argv[]){

    reverse(argv[1]);

    return 0;
}

【讨论】:

    【解决方案3】:

    在您的代码中,您有以下内容:

    *end--;
    *begin++;
    

    这只是纯粹的运气,这样做是正确的(实际上,原因是运算符优先级)。看起来您打算让代码实际执行

    (*end)--;
    (*begin)++;
    

    这是完全错误的。你拥有它的方式,操作发生在

    • 递减end 然后取消引用它
    • 增加begin 然后取消引用它

    在这两种情况下,取消引用都是多余的,应该删除。您可能希望这种行为是

    end--;
    begin++;
    

    这些东西让开发者大发雷霆,因为它们很难追踪。

    【讨论】:

    • 感谢您的关注。编辑了它。
    【解决方案4】:

    这将就位并使用指针

     #include<stdio.h>
     #include<string.h>
     #include<stdlib.h>
    
     void reve(char *s)
     {
        for(char *end = s + (strlen(s) - 1); end > s ; --end, ++s)
        {
            (*s) ^= (*end);
            (*end) ^= (*s);
            (*s) ^= (*end);
        }
     }
    
    int main(void)
    {
        char *c = malloc(sizeof(char *) * 250);
        scanf("%s", c);
        reve(c);
        printf("\nReverse String %s", c);
    }
    

    【讨论】:

      【解决方案5】:

      将char *string = "foobar"; 更改为char string[] = "foobar";。问题是 char * 指向只读内存,然后您尝试修改它导致分段错误。

      【讨论】:

        【解决方案6】:

        这构成了一个小的(ish)递归函数,并通过在堆栈向下的过程中存储值并在返回(返回)的过程中递增指向字符串开头的指针(*s)来工作。

        看起来很聪明的代码,但在堆栈使用方面很糟糕。

        #include <stdio.h>
        
        char *reverse_r(char val, char *s, char *n)
        {
            if (*n)
                s = reverse_r(*n, s, n+1);
           *s = val;
           return s+1;
        }
        
        int main(int argc, char *argv[])
        {
            char *aString;
        
            if (argc < 2)
            {
                printf("Usage: RSIP <string>\n");
                return 0;
            }
        
            aString = argv[1];
            printf("String to reverse: %s\n", aString );
        
            reverse_r(*aString, aString, aString+1); 
            printf("Reversed String:   %s\n", aString );
        
            return 0;
        }
        

        【讨论】:

          【解决方案7】:

          这是我的就地 C 字符串反转版本。

          #include <stdio.h>
          #include <string.h>
          
          int main (int argc, const char * argv[])
          {
              char str[] = "foobar";
              printf("String:%s\n", str);
              int len = (int)strlen(str);
              printf("Lenth of str: %d\n" , len);
              int i = 0, j = len - 1;
              while(i < j){
                  char temp = str[i];
                  str[i] = str[j];
                  str[j] = temp;
                  i++;
                  j--;
              }
          
              printf("Reverse of String:%s\n", str);
              return 0;
          }
          

          【讨论】:

            【解决方案8】:

            下面,你可以看到我解决这个问题的代码:

            #include <string>
            #include <iostream>
            
            char* strRev(char* str)
            {
                char *first,*last;
            
                if (!str || !*str)
                    return str;
            
                size_t len = strlen(str);
                for (first = str, last = &str[len] - 1; first < last ; first++, last--)
                {
                    str[len] = *first;
                    *first = *last;
                    *last = str[len];
                }
                str[len] = '\0';
                return str;
            }
            
            int main()
            {
                char test[13] = "A new string";
                std::cout << strRev(test) << std::endl;
                return 0;
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-11-21
              • 1970-01-01
              • 2015-03-25
              相关资源
              最近更新 更多