在C中反转一个字符串

qwe*_*wer 10 c string undefined-behavior

我知道这已被问过几千次,但我在代码中找不到错误.有人可以指出我做错了什么吗?

#include <stdlib.h>
#include <string.h>

void reverseString(char *myString){
  char temp;
  int len = strlen(myString);

  char *left = myString;
  //  char *right = &myString[len-1];                                                                                        
  char *right = myString + strlen(myString) - 1;

  while(left < right){
    temp = *left;
    *left = *right; // this line seems to be causing a segfault                                                              
    *right = temp;
    left++;
    right--;
  }
}

int main(void){
  char *somestring = "hello";
  printf("%s\n", somestring);
  reverseString(somestring);

  printf("%s", somestring);

}
Run Code Online (Sandbox Code Playgroud)

小智 13

最终,在适当的位置反转它会更清晰,如下所示:

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

void
reverse(char *s)
{
    int a, b, c;
    for (b = 0, c = strlen(s) - 1; b < c; b++, c--) { 
        a = s[b]; 
        s[b] = s[c]; 
        s[c] = a; 
    }

    return; 
}

int main(void)
{
    char string[] = "hello";
    printf("%s\n", string);
    reverse(string);
    printf("%s\n", string);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您的解决方案本质上是这个版本的语义上更大的版本.理解指针和数组之间的区别.该标准明确指出,这种操作的行为(字符串文字内容的修改)是未定义的.您还应该看到eskimo的这段摘录:

使用字符串常量初始化字符数组时:

char string[] = "Hello, world!";
Run Code Online (Sandbox Code Playgroud)

你最终得到一个包含字符串的数组,你可以修改数组内容到你内心的内容:

string[0] = 'J';
Run Code Online (Sandbox Code Playgroud)

但是,可以在代码中的其他位置使用字符串常量(正式术语是字符串文字).由于它们是数组,因此编译器会像往常一样在表达式中使用时生成指向其第一个元素的指针.也就是说,如果你说

char *p1 = "Hello";
int len = strlen("world");
Run Code Online (Sandbox Code Playgroud)

这几乎就像你说的那样

char internal_string_1[] = "Hello";
char internal_string_2[] = "world";
char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);
Run Code Online (Sandbox Code Playgroud)

这里,名为internal_string_1和internal_string_2的数组应该表明,每次在代码中使用字符串常量时,编译器实际上都会生成很少的临时数组.然而,细微的事实是,字符串常量"后面"的数组不一定是可修改的.特别是,编译器可以将它们存储在只读存储器中.因此,如果你写

char *p3 = "Hello, world!";
p3[0] = 'J';
Run Code Online (Sandbox Code Playgroud)

您的程序可能会崩溃,因为它可能会尝试将值(在本例中为字符"J")存储到不可写入的内存中.

道德是每当你构建或修改字符串时,你必须确保你正在构建或修改它们的内存是可写的.该内存应该是您已分配的数组,或者是您通过我们将在下一章中看到的技术动态分配的内存.确保程序的任何部分都不会尝试修改一个字符串,该字符串实际上是编译器为响应您的一个字符串常量而为您生成的未命名的,不可写的数组之一.(唯一的例外是数组初始化,因为如果你写入这样的数组,你要写入数组,而不是你用来初始化数组的字符串文字.)"


Joh*_*ler 12

问题出在这里

char *somestring = "hello";
Run Code Online (Sandbox Code Playgroud)

somestring指向字符串文字"hello".C++标准并不保证这一点,但在大多数机器上,这将是只读数据,因此不允许您修改它.

以这种方式宣布它

char somestring[] = "hello";
Run Code Online (Sandbox Code Playgroud)

  • 如果应用程序的性能关键部分是在紧密循环中反转字符串,我认为您应该重新考虑您的设计. (3认同)
  • @John:你必须扭转的所有这些弦都来自哪里?你怎么能比你可以反转它们更快地生成它们,以便逆转成为瓶颈?我确信有些情况下,逆转字符串是一个瓶颈,但它们可能非常罕见. (3认同)

dir*_*tly 5

您正在通过尝试修改可能的只读内存区域来调用未定义的行为(字符串文字是隐式的const- 可以读取它们但不能写它们).创建一个新字符串并将其返回,或者传递足够大的缓冲区并将反向字符串写入其中.