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

发布于 2024-08-18 22:01:18 字数 780 浏览 3 评论 0原文

上下文

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

问题

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

特别是因为我的代码几乎与非邪恶的代码相同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);
}

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.)

Problem

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

Especially since my code is nearly identical to 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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

第七度阳光i 2024-08-25 22:01:18

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

char *string = "foobar";

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

*end = *begin;

你会得到段错误。

尝试一下

char string[] = "foobar";

,您应该会注意到差异。

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

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.

梦明 2024-08-25 22:01:18

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

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

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++]!='\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;
}
谢绝鈎搭 2024-08-25 22:01:18

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

*end--;
*begin++;

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

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

此操作,这是完全错误的。按照您的方式,操作发生时

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

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

end--;
begin++;

这些让开发人员抓狂的事情,因为它们很难追踪。

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

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

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

  • decrement end and then dereference it
  • increment begin and then dereference it

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

end--;
begin++;

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

看轻我的陪伴 2024-08-25 22:01:18

这将就位并使用指针

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

This would be in place and using pointers

 #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);
}
南街九尾狐 2024-08-25 22:01:18

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

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.

饮湿 2024-08-25 22:01:18

这构成了一个小型递归函数,其工作原理是在堆栈中存储值,并在返回(返回)时将指针递增到字符串的开头(*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;
}

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).

Clever looking code but awful in terms of stack usage.

#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;
}
坏尐絯 2024-08-25 22:01:18

这是我的就地 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;
}

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

#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;
}
百合的盛世恋 2024-08-25 22:01:18

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

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

Below, you can see my code for this problem:

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文