C语言中的指针

idfiyjo8  于 12个月前  发布在  其他
关注(0)|答案(7)|浏览(89)

我试图学习C中的指针,但与以下概念混淆:

char *string = "hello"
char *string2;

字符串
以下两者的主要区别是什么:

A.) *string2 = string;


然后

B.) string2 = "bye";

oyt4ldly

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这样的指针表达式,它的值是字符串字面量的地址)作为参数传递给像scanfstrtokfgets等函数。
string是指向char的指针,包含字符串"hello"的地址。string2也是指向char的指针,其值是不确定的(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;

  • expression* *string2的类型是char,因此声明变为
char *string2;


通过扩展,* 表达式 * string2的类型是char *,或者指向char的指针。
所以当你写的时候

*string2 = string;


你试图将char *string)类型的值赋给char*string2)类型的表达式。这是行不通的,因为char *char是不兼容的类型。这个错误在翻译(编译)时出现。如果你写了

*string2 = *string;


那么两个表达式都有char类型,并且赋值是法律的。
然而,如果你还没有给string2赋值,它的值是不确定的;它包含一个随机的位串,可能对应于一个有效的、可写的地址,也可能不对应。它可能看起来工作正常,也可能完全崩溃,也可能做任何介于两者之间事情。这个问题直到运行时才会出现。更好的是,如果你把字符串文字"bye"赋值给string2,那么你就会遇到上面描述的问题;你试图修改一个字符串文字的内容。同样,这个问题在运行时才会出现。

m1m5dgzv

m1m5dgzv2#

有一些微妙的推断正在作出其他回答,错过了一个新手的经验。

char *string = "hello";

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

*string = "hello";


取消引用应该是指针变量的内容,并为指向的位置赋值。(它不是变量声明;但是,由于string的类型为char *-因此*string的类型为char-并且赋值的右侧是一个带有指针值的表达式,因此存在类型不匹配。这可以通过两种方式修复,根据声明的意图:

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


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


第一个赋值将string重新赋值为指向包含字符序列(hello\000)的内存。第二个赋值将string指向的字符更改为charh
诚然,这是一个有点令人困惑的主题,* 所有 * C程序员都经历了一点痛苦来学习掌握。* 指针声明语法与语句中的相同文本相比,效果略有不同(尽管相关)。* 获得更多的实践和经验,编写和编译涉及指针的表达式,最终我的话会变得非常有意义。

wko9yo5t

wko9yo5t3#

*string可以读作“whatever string points to”,这是一个char

6g8kf2rb

6g8kf2rb4#

一个C字符串只是一个字符数组。像上面的"hello"这样的C字符串字面量可以被看作是“返回”一个指向字符数组的第一个元素{ 'h', 'e', 'l', 'l', 'o' }的指针。
因此,char *string = "bye"有意义,而char string = "bye"没有意义。

2ledvvac

2ledvvac5#

char *是一个指向字符的指针。像"hello"这样的文字返回一个指向字符串的第一个字符的指针。因此,string = "bye"是有意义的,使string指向字符串"bye"的第一个字符。
另一方面,*stringstring所指向的字符。它不是指针,而是一个8位整数。这就是为什么赋值*string = "bye"没有意义,并且可能会导致分段错误,因为存储"bye"的内存段是只读的。

zzoitvuj

zzoitvuj6#

编辑后:
区别在于A)不会编译,如果编译了,那就是undefined行为,因为你解引用了一个未初始化的指针。
另外,请不要在发布后大幅改变您的问题。

wxclj1h5

wxclj1h57#

C没有字符串数据类型

在C中,char*只是一个指向char数组的字符(通常是第一个)的指针。
我们不知道你在哪里声明了这个变量。
如果它们位于函数体中,则会分配到堆栈中,否则会分配到.bss.data部分中
这个表达式分配char指针,并将其值转换为指向字符串字面量“hello”。字符串字面量通常存储在.rodata部分。

char *string = "hello"

字符串
这只是分配字符指针而不初始化它的值。所以它可以指向任何地方。

char *string2;


这是赋值,没有太大意义,因为取消引用的char指针具有单个字符的值(或操作),而不是字符串指针:

*string2 = string;


所以我们的任务应该是这样的才有意义:

*string2 = 'A';


但是这个赋值很好,这意味着我们将char指针赋值给一个可能在.rodata部分分配的字符串“bye”:

string2 = "bye";

相关问题