我试图学习C中的指针,但与以下概念混淆:
char *string = "hello" char *string2;
字符串以下两者的主要区别是什么:
A.) *string2 = string;
型然后
B.) string2 = "bye";
型
oyt4ldly1#
一些照片可能会有所帮助。假设下面的内存Map(地址是完全任意的,不反映任何已知的架构):
Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- "hello" 0x00501234 'h' 'e' 'l' 'l' 0x00501238 'o' 0x00 "bye" 0x0050123A 'b' 'y' 0x0050123C 'e' 0x00 0x?? 0x?? ... string 0x80FF0000 0x00 0x50 0x12 0x34 string2 0x80FF0004 0x?? 0x?? 0x?? 0x??
字符串"hello"和"bye"是字符串字面值,作为char的数组存储在内存中的“某处”,这样它们在程序的生命周期内都是可用的。注意,试图修改字符串字面值的内容会调用未定义的行为;你不想把字符串字面量(或像string这样的指针表达式,它的值是字符串字面量的地址)作为参数传递给像scanf,strtok,fgets等函数。string是指向char的指针,包含字符串"hello"的地址。string2也是指向char的指针,其值是不确定的(0x??表示未知字节值)。当你写
"hello"
"bye"
char
string
scanf
strtok
fgets
string2
0x??
string2 = "bye";
型你将"bye"(0x 0050123 A)的地址分配给string2,所以我们的内存Map现在看起来像这样:
Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- "hello" 0x00501234 'h' 'e' 'l' 'l' 0x00501238 'o' 0x00 "bye" 0x0050123A 'b' 'y' 0x0050123C 'e' 0x00 0x?? 0x?? ... string 0x80FF0000 0x00 0x50 0x12 0x34 string2 0x80FF0004 0x00 0x50 0x12 0x3A
型看起来很简单,对吧?现在让我们看看声明
*string2 = string;
型这里有几个问题。首先,一个题外话-C中的声明是围绕 * 表达式 * 的类型,而不是对象。string2是一个指向字符的指针;要访问字符值,我们必须用一元*运算符 * 解引用 * string2:
*
char x = *string2;
*string2
char *string2;
型通过扩展,* 表达式 * string2的类型是char *,或者指向char的指针。所以当你写的时候
char *
型你试图将char *(string)类型的值赋给char(*string2)类型的表达式。这是行不通的,因为char *和char是不兼容的类型。这个错误在翻译(编译)时出现。如果你写了
*string2 = *string;
型那么两个表达式都有char类型,并且赋值是法律的。然而,如果你还没有给string2赋值,它的值是不确定的;它包含一个随机的位串,可能对应于一个有效的、可写的地址,也可能不对应。它可能看起来工作正常,也可能完全崩溃,也可能做任何介于两者之间事情。这个问题直到运行时才会出现。更好的是,如果你把字符串文字"bye"赋值给string2,那么你就会遇到上面描述的问题;你试图修改一个字符串文字的内容。同样,这个问题在运行时才会出现。
m1m5dgzv2#
有一些微妙的推断正在作出其他回答,错过了一个新手的经验。
char *string = "hello";
字符串声明一个指针变量,它被初始化为指向一个字符数组(传统上是一个很好的类型匹配)。声明
*string = "hello";
型取消引用应该是指针变量的内容,并为指向的位置赋值。(它不是变量声明;但是,由于string的类型为char *-因此*string的类型为char-并且赋值的右侧是一个带有指针值的表达式,因此存在类型不匹配。这可以通过两种方式修复,根据声明的意图:
*string
string = "hello"; /* with "char *" expressions on both sides */
型或
*string = 'h'; /* with "char" expressions on both sides */
型第一个赋值将string重新赋值为指向包含字符序列(hello\000)的内存。第二个赋值将string指向的字符更改为char值h。诚然,这是一个有点令人困惑的主题,* 所有 * C程序员都经历了一点痛苦来学习掌握。* 指针声明语法与语句中的相同文本相比,效果略有不同(尽管相关)。* 获得更多的实践和经验,编写和编译涉及指针的表达式,最终我的话会变得非常有意义。
hello\000
h
C
wko9yo5t3#
*string可以读作“whatever string points to”,这是一个char。
6g8kf2rb4#
一个C字符串只是一个字符数组。像上面的"hello"这样的C字符串字面量可以被看作是“返回”一个指向字符数组的第一个元素{ 'h', 'e', 'l', 'l', 'o' }的指针。因此,char *string = "bye"有意义,而char string = "bye"没有意义。
{ 'h', 'e', 'l', 'l', 'o' }
char *string = "bye"
char string = "bye"
2ledvvac5#
char *是一个指向字符的指针。像"hello"这样的文字返回一个指向字符串的第一个字符的指针。因此,string = "bye"是有意义的,使string指向字符串"bye"的第一个字符。另一方面,*string是string所指向的字符。它不是指针,而是一个8位整数。这就是为什么赋值*string = "bye"没有意义,并且可能会导致分段错误,因为存储"bye"的内存段是只读的。
string = "bye"
*string = "bye"
zzoitvuj6#
编辑后:区别在于A)不会编译,如果编译了,那就是undefined行为,因为你解引用了一个未初始化的指针。另外,请不要在发布后大幅改变您的问题。
wxclj1h57#
在C中,char*只是一个指向char数组的字符(通常是第一个)的指针。我们不知道你在哪里声明了这个变量。如果它们位于函数体中,则会分配到堆栈中,否则会分配到.bss的.data部分中这个表达式分配char指针,并将其值转换为指向字符串字面量“hello”。字符串字面量通常存储在.rodata部分。
char*
.bss
.data
.rodata
char *string = "hello"
字符串这只是分配字符指针而不初始化它的值。所以它可以指向任何地方。
型这是赋值,没有太大意义,因为取消引用的char指针具有单个字符的值(或操作),而不是字符串指针:
型所以我们的任务应该是这样的才有意义:
*string2 = 'A';
型但是这个赋值很好,这意味着我们将char指针赋值给一个可能在.rodata部分分配的字符串“bye”:
7条答案
按热度按时间oyt4ldly1#
一些照片可能会有所帮助。
假设下面的内存Map(地址是完全任意的,不反映任何已知的架构):
字符串
"hello"
和"bye"
是字符串字面值,作为char
的数组存储在内存中的“某处”,这样它们在程序的生命周期内都是可用的。注意,试图修改字符串字面值的内容会调用未定义的行为;你不想把字符串字面量(或像string
这样的指针表达式,它的值是字符串字面量的地址)作为参数传递给像scanf
,strtok
,fgets
等函数。string
是指向char
的指针,包含字符串"hello"
的地址。string2
也是指向char
的指针,其值是不确定的(0x??
表示未知字节值)。当你写
型
你将
"bye"
(0x 0050123 A)的地址分配给string2
,所以我们的内存Map现在看起来像这样:型
看起来很简单,对吧?
现在让我们看看声明
型
这里有几个问题。
首先,一个题外话-C中的声明是围绕 * 表达式 * 的类型,而不是对象。
string2
是一个指向字符的指针;要访问字符值,我们必须用一元*
运算符 * 解引用 *string2
:型
*string2
的类型是char
,因此声明变为型
通过扩展,* 表达式 *
string2
的类型是char *
,或者指向char
的指针。所以当你写的时候
型
你试图将
char *
(string
)类型的值赋给char
(*string2
)类型的表达式。这是行不通的,因为char *
和char
是不兼容的类型。这个错误在翻译(编译)时出现。如果你写了型
那么两个表达式都有
char
类型,并且赋值是法律的。然而,如果你还没有给
string2
赋值,它的值是不确定的;它包含一个随机的位串,可能对应于一个有效的、可写的地址,也可能不对应。它可能看起来工作正常,也可能完全崩溃,也可能做任何介于两者之间事情。这个问题直到运行时才会出现。更好的是,如果你把字符串文字"bye"
赋值给string2
,那么你就会遇到上面描述的问题;你试图修改一个字符串文字的内容。同样,这个问题在运行时才会出现。m1m5dgzv2#
有一些微妙的推断正在作出其他回答,错过了一个新手的经验。
字符串
声明一个指针变量,它被初始化为指向一个字符数组(传统上是一个很好的类型匹配)。
声明
型
取消引用应该是指针变量的内容,并为指向的位置赋值。(它不是变量声明;但是,由于
string
的类型为char *
-因此*string
的类型为char
-并且赋值的右侧是一个带有指针值的表达式,因此存在类型不匹配。这可以通过两种方式修复,根据声明的意图:型
或
型
第一个赋值将
string
重新赋值为指向包含字符序列(hello\000
)的内存。第二个赋值将string
指向的字符更改为char
值h
。诚然,这是一个有点令人困惑的主题,* 所有 *
C
程序员都经历了一点痛苦来学习掌握。* 指针声明语法与语句中的相同文本相比,效果略有不同(尽管相关)。* 获得更多的实践和经验,编写和编译涉及指针的表达式,最终我的话会变得非常有意义。wko9yo5t3#
*string
可以读作“whateverstring
points to”,这是一个char
。6g8kf2rb4#
一个C字符串只是一个字符数组。像上面的
"hello"
这样的C字符串字面量可以被看作是“返回”一个指向字符数组的第一个元素{ 'h', 'e', 'l', 'l', 'o' }
的指针。因此,
char *string = "bye"
有意义,而char string = "bye"
没有意义。2ledvvac5#
char *
是一个指向字符的指针。像"hello"
这样的文字返回一个指向字符串的第一个字符的指针。因此,string = "bye"
是有意义的,使string
指向字符串"bye"
的第一个字符。另一方面,
*string
是string
所指向的字符。它不是指针,而是一个8位整数。这就是为什么赋值*string = "bye"
没有意义,并且可能会导致分段错误,因为存储"bye"
的内存段是只读的。zzoitvuj6#
编辑后:
区别在于A)不会编译,如果编译了,那就是undefined行为,因为你解引用了一个未初始化的指针。
另外,请不要在发布后大幅改变您的问题。
wxclj1h57#
C没有字符串数据类型
在C中,
char*
只是一个指向char数组的字符(通常是第一个)的指针。我们不知道你在哪里声明了这个变量。
如果它们位于函数体中,则会分配到堆栈中,否则会分配到
.bss
的.data
部分中这个表达式分配
char
指针,并将其值转换为指向字符串字面量“hello”。字符串字面量通常存储在.rodata
部分。字符串
这只是分配字符指针而不初始化它的值。所以它可以指向任何地方。
型
这是赋值,没有太大意义,因为取消引用的
char
指针具有单个字符的值(或操作),而不是字符串指针:型
所以我们的任务应该是这样的才有意义:
型
但是这个赋值很好,这意味着我们将
char
指针赋值给一个可能在.rodata
部分分配的字符串“bye”:型