首页 > 解决方案 > 为什么不能使用指针更改字符?

问题描述

最近我得到了一本 C 编程语言书。在第 95 页有一个 strcpy 函数的实现。

void strcopy(char *s, char *t) {
    while(*s++ = *t++) 
        ;
}

int main(int argc, char *argv[]) {
    char *hello = "hello";
    char *world = "world";

    strcopy(hello, world);
    return 0;
}

我试图自己实现它,但是在(成功)编译之后

gcc -o c_lang c_programming_lang_exercises.c

并尝试运行它

./c_lang

我收到以下错误消息:

zsh: bus error

我尝试了不同的实现,但不知何故这对我不起作用。

也许有人知道为什么?

谢谢您的帮助 :)


编辑:出于我自己的理解,如果我错了,请纠正我。在函数中调用“strcopy(hello, world);” 我在这里传递指针本身的值,所以我用这样的东西调用函数:strcopy(0x123a4,0x234859b)。现在 C 不认为 this 是变量,因此它的值被复制并传递给函数。在 strcopy 函数本身中我不能取消引用它,因为我只是得到指针的值。

我应该做的是传递地址,指针引用,以便我可以取消引用 strcopy 函数中的值并访问正确的内存地址。

另一个错误可能在我声明的主函数char *hello = "hello"中,据我所知,它称为字符串常量,因此不可修改。

所以,如果我的假设是正确的,下面的代码应该可以工作:

void strcopy(char *s, char *t) {
    //code goes here...
}
int main(int stringc, char *argv[]) {
    char hello[] = "hello";
    char world[] = "world";
    strcopy(&hello, &world);
    return 0;
}

它有效,但我收到以下编译器警告:

 incompatible pointer types passing 'char (*)[6]' to parameter of type 'char **' [-Wincompatible-pointer-types]
    strcopy(&hello, &world);

标签: cpointers

解决方案


C 在类型方面做出了非常糟糕的让步,这与历史原因有关。

main()中,您将字符串声明为:

char *hello = "hello";

您应该做的是将警告级别调高并重新编译。问题是这"hello"是一个字符串文字——它不能被修改。它应该声明为:

const char *hello = "hello";

(打开警告会告诉你这一点。)

因此,您试图将字符复制到只读内存中,这在现代处理器和现代编译器上是不允许的——它会产生访问冲突。Zsh 为你抱怨。

相反,请确保您对从只读内存复制的本地数组具有写访问权限:

char hello[] = "hello";

是的,这产生了一个本地的、可变的数组,它有六个字符长(五个字符用于单词“hello”加上一个用于空终止符)并从只读内存自动初始化。

这是在 C 中声明的东西经常使初学者感到困惑的微妙症结之一:

  • const char * s = "Hello world!";— 指向 ROM 的指针
  • char s[] = "Hello world!";— 从 ROM 初始化的本地可变数组

而已!


推荐阅读