为什么在这里*(str+i) = *(str+j)不起作用?

4

void reverse(char *str){
    int i,j;
    char temp;
    for(i=0,j=strlen(str)-1; i<j; i++, j--){
     temp = *(str + i);
     *(str + i) = *(str + j);
     *(str + j) = temp;
     printf("%c",*(str + j));
    }
}



int main (int argc, char const *argv[])
{
    char str[] = "Shiv";
    reverse(str);
    printf("%s",str);
    return 0;
}

如果我使用char *str = "Shiv",则反转函数中的交换部分即str[i]=str[j]似乎不起作用,但是如果我将str声明为char str [] = "Shiv",则交换部分有效吗?这个行为的原因是什么?当我尝试运行程序时,一直收到“总线错误”的消息,这让我有些困惑。


元问题...为什么一些在这个主题上本来有效的答案被投票否决了?它们可能没有得到最高票数的答案那么完整,但也不一定是错误的。 - shoover
8个回答

16
当你使用char *str = "Shiv";时,你不拥有指向的内存,并且不允许对其进行写入。字符串实际的字节可能是程序代码内部的常量。
当你使用char str[] = "Shiv";时,4(+1)个字符字节和数组本身在你的堆栈上,并且你可以随意写入它们。

4

char *str = "Shiv"获取了一个指向字符串常量的指针,该常量可能被加载到受保护的内存区域中(例如可执行代码的一部分),该区域为只读。


4
char *str = "Shiv";

This should be :

const char *str = "Shiv";

现在,您将会遇到一个错误 ;)



1

尝试

int main (int argc, char const *argv[])
{
    char *str = malloc(5*sizeof(char)); //4 chars + '\0'
    strcpy(str,"Shiv");
    reverse(str);
    printf("%s",str);
    free(str); //Not needed for such a small example, but to illustrate
    return 0;
}

使用指针而不是[]符号分配空间可以获得读写内存。使用[]符号直接在堆栈中分配空间,但使用const指针则不会。


1

字符串字面值在C和C++中都是不可修改的对象。试图修改一个字符串字面值总是导致未定义的行为。这正是当你遇到“总线错误”时所观察到的情况。

char *str = "Shiv";

变量。在这种情况下,你的“reverse”函数将尝试修改一个字符串常量。因此,行为是未定义的。

这个

char str[] = "Shiv";

variant将在可修改的数组'str'中创建字符串文字的副本,然后'reverse'将对该副本进行操作。这将正常工作。

P.S.不要创建指向字符串字面值的非const限定符指针。您的第一个变量应该是

const char *str = "Shiv";

(注意额外的“const”)。


1

字符串字面量(例如“Shiv”)是不可修改的。
如果你将指针赋值为这样一个字符串字面量的地址,然后尝试通过解引用指针来更改字符串字面量的内容,那么这是绝对不可以的。

相反,应该将str声明为一个数组:

char str[] = "Shiv";

这将创建一个由5个字符组成的数组str,并将字符'S'、'h'、'i'、'v'和'\0'复制到str[0]、str[1]、...、str[4]中。每个str元素中的值都是可修改的。

当我想要使用指向字符串字面量的指针时,我通常声明它为const。这样,编译器可以通过发出消息来帮助我,当我的代码想要更改字符串字面量的内容时。

const char *str = "Shiv";

想象一下,你可以对整数做同样的事情。

/* Just having fun, this is not C! */
int *ptr = &5;                      /* address of 5   */
*ptr = 42;                          /* change 5 to 42 */
printf("5 + 1 is %d\n", *(&5) + 1); /* 6? or 43?  :)  */

标准中的引用:

6.4.5 字符串字面量
...
6 ... 如果程序试图修改这样的数组[字符串字面量],则行为是未定义的。


0

char *str是指向字符块(字符串)的指针/引用。但它位于内存块中,因此您不能像那样直接分配它。


0

有趣的是我从未注意到这一点。我能够在VS2008 C++中复制这个条件。

通常,在常量的原地修改是一个坏主意。

无论如何,this post相当清楚地解释了这种情况。

第一个(char[])是您可以编辑的本地数据 (因为数组是本地数据)。

第二个(char *)是指向全局、静态(常量)数据的本地指针。您不允许修改常量数据。

如果您使用GNU C,则可以使用-fwritable-strings编译,以防止全局字符串被设置为常量,但这并不推荐。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接