C语言 使用指针修改字符串时发生分段错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2124600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:13:37  来源:igfitidea点击:

Segmentation fault occurring when modifying a string using pointers?

cstringpointersreverse

提问by brice

Context

语境

I'm learning C, and I'm trying to reverse a string in place using pointers. (I know you can use an array; this is more about learning about pointers.)

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

Problem

问题

I keep getting segmentation faults when trying to run the code below. GCCseems not to like the *end = *begin;line. Why is that?

尝试运行下面的代码时,我不断收到分段错误。GCC好像不太喜欢*end = *begin;行。这是为什么?

Especially since my code is nearly identical to the non-evil C function already discussed in another question

特别是因为我的代码与另一个问题中已经讨论过的非邪恶 C 函数几乎相同

#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);
}

回答by Remo.D

One problem lies with the parameter you pass to the function:

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

char *string = "foobar";

This is a static string allocated in the read-only portion. When you try to overwrite it with

这是在只读部分分配的静态字符串。当你尝试用它覆盖它时

*end = *begin;

you'll get the segfault.

你会得到段错误。

Try with

试试

char string[] = "foobar";

and you should notice a difference.

你应该注意到一个区别。

The key point is that in the first case the string exists in the read-only segment and just a pointer to it is used while in the second case an array of chars with the proper size is reserved on the stack and the static string (which always exists) is copied into it. After that you're free to modify the content of the array.

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

回答by user720694

You can also utilize the null character at the end of a string in order to swap characters within a string, thereby avoiding the use of any extra space. Here is the code:

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

#include <stdio.h>

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

    while(str[i++]!='
*end--;
*begin++;
') 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]='
(*end)--;
(*begin)++;
'; } int main(int argc, char *argv[]){ reverse(argv[1]); return 0; }

回答by ezpz

In your code you have the following:

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

end--;
begin++;

It is only pure luck that this does the correct thing (actually, the reason is operator precedence). It looks like you intended the code to actually do

这样做是完全靠运气的(实际上,原因是运算符优先级)。看起来您打算将代码实际执行

 #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);
}

Which is entirely wrong. The way you have it, the operations happen as

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

  • decrement endand then dereference it
  • increment beginand then dereference it
  • 递减end然后取消引用它
  • 增加begin然后取消引用它

In both cases the dereference is superfluous and should be removed. You probably intended the behavior to be

在这两种情况下,取消引用都是多余的,应该删除。您可能打算将行为变成

#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;
}

These are the things that drive a developer batty because they are so hard to track down.

这些是推动开发人员疯狂的事情,因为它们很难追踪。

回答by nmd

This would be in place and using pointers

这将就位并使用指针

#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;
}

回答by Kyle Lutz

Change char *string = "foobar";to char string[] = "foobar";. The problem is that a char *points to read only memory which you then try to modify causing a segmentation fault.

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

回答by dushshantha

Here's my version of in-place C string reversal.

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

#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] = '##代码##';
    return str;
}

int main()
{
    char test[13] = "A new string";
    std::cout << strRev(test) << std::endl;
    return 0;
}

回答by Simon Peverett

This makes for a small(ish) recursive function and works by storing the values on the way down the stack and incrementing the pointer to the start of the string (*s) on the way back up (return).

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

Clever looking code but awful in terms of stack usage.

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

##代码##

回答by Reza

Below, you can see my code for this problem:

在下面,您可以看到我针对此问题的代码:

##代码##