理解C中的指针

我正在尝试学习C中的指针,但是它与以下概念混淆:

char *string = "hello" char *string2; 

有什么区别:

 A.) *string2 = string; 

然后

 B.) string2 = "bye"; 

一些图片可能有帮助。

假设以下内存映射(地址完全是任意的,并不反映任何已知的体系结构):

项目地址0x00 0x01 0x02 0x03
 ---- ------- ---- ---- ---- ----
 “你好”0x00501234'h''e''l''l'
                 0x00501238'o'0x00   
 “再见”0x0050123A'b''y'
                 0x0050123C'e'0x00 0x ??  0X?
                 ...
字符串0x80FF0000 0x00 0x50 0x12 0x34
 string2 0x80FF0004 0x ??  0X?  0X?  0X?

这显示了声明后的情况。 "hello""bye"是字符串文字,在内存中存储为char “somewhere”的数组,以便它们在程序的生命周期内可用。 请注意,尝试修改字符串文字的内容会调用未定义的行为; 你不想传递字符串文字(或像string那样计算字符串文字地址的指针表达式)作为scanfstrtokfgets等函数的参数。

string是指向char的指针,包含字符串文字"hello"的地址。 string2也是一个指向char的指针,它的值是不确定的( 0x??代表一个未知的字节值)。

当你写作

 string2 = "bye"; 

你将"bye" (0x0050123A)的地址分配给string2 ,所以我们的内存映射现在看起来像这样:

项目地址0x00 0x01 0x02 0x03
 ---- ------- ---- ---- ---- ----
 “你好”0x00501234'h''e''l''l'
                 0x00501238'o'0x00   
 “再见”0x0050123A'b''y'
                 0x0050123C'e'0x00 0x ??  0X?
                 ...
字符串0x80FF0000 0x00 0x50 0x12 0x34
 string2 0x80FF0004 0x00 0x50 0x12 0x3A

看起来很简单吧?

现在让我们来看看声明

 *string2 = string; 

这里有几个问题。

首先,C中的题外话 – 声明以表达式的类型为中心,而不是对象。 string2是一个指向字符的指针; 要访问字符值,我们必须使用unary *运算符取消引用 string2

 char x = *string2; 

表达式 *string2的类型是char ,因此声明变为

 char *string2; 

通过扩展, 表达式 string2的类型是char * ,或指向char指针。

所以当你写作

 *string2 = string; 

您正在尝试将char *string )类型的值赋给char*string2 )类型的表达式。 这不会起作用,因为char *char不是兼容的类型。 此错误显示在转换(编译)时。 如果你写过

 *string2 = *string; 

然后两个表达式都有char类型,并且赋值是合法的。

但是,如果尚未向string2分配任何内容,则其值不确定; 它包含一个随机位字符串,可能对应于有效的可写地址,也可能不对应。 尝试遵循随机的,可能无效的指针值会调用未定义的行为; 它似乎工作正常,它可能彻底崩溃,它可能在两者之间做任何事情。 直到运行时才会显示此问题。 更好的是,如果你将字符串文字"bye"分配给string2 ,那么你会遇到上述问题; 您正在尝试修改字符串文字的内容。 同样,这是一个直到运行时才会出现的问题。

其他回答者做出了一些微妙的推论,错过了新手的POV。

 char *string = "hello"; 

声明一个指针变量,它被初始化为指向一个字符数组(传统上一个好的类型匹配)。

该声明

 *string = "hello"; 

取消引用应该是指针变量的内容并为指向的位置赋值。 (它不是变量声明;必须在某处完成。)但是,因为string类型为char * -so *string类型为char ,而赋值的右侧是带有指针值的表达式,是一种类型不匹配。 这可以通过两种方式修复,具体取决于语句的意图:

 string = "hello"; /* with "char *" expressions on both sides */ 

要么

 *string = 'h'; /* with "char" expressions on both sides */ 

第一个重新指定string以指向包含一系列字符的内存( hello\000 )。 第二个赋值将字符串指向的字符更改为charh

不可否认,这是一个有点令人困惑的主题, 所有 C程序员都会经历一些有点痛苦的学习。 指针声明语法与语句中的相同文本具有略微不同(但相关)的效果。 获得更多的练习和经验,编写和编写涉及指针的表达式,最终我的话语将非常有意义。

*string可以读作“任何string指向”,这是一个char 。 为它分配"bye"是没有意义的。

AC字符串只是一个字符数组。 上面的"hello"类的C字符串文字可以被视为“返回”指向字符数组的第一个元素的指针, { 'h', 'e', 'l', 'l', 'o' }

因此, char *string = "bye"是有意义的,而char string = "bye"则没有。

char *是指向字符的指针。 诸如"hello"之类的文字返回指向字符串第一个字符的指针。 因此, string = "bye"是有意义的,使string指向字符串"bye"的第一个字符。

另一方面, stringstring指向的string 。 它不是指针而是8位整数。 这就是为什么赋值*string = "bye"没有意义,并且可能会导致分段错误,因为"bye"存储的内存段是只读的。

编辑后:

不同之处在于A)不会编译,如果确实如此,则它是未定义的行为 ,因为您正在取消引用未初始化的指针。

此外,发布后请不要大幅改变您的问题。