char a =?string?有什么区别? 和char * p =?string?;?
如标题所示,有什么区别
char a[] = ?string?; and char *p = ?string?;
这个问题是在面试时问我的。 我甚至不明白这个说法。
char a[] = ?string?
这是什么?
运营商? 它是一个string的一部分,还是有一些特定的含义?
第一个是数组,另一个是指针。
数组声明
char a[6];
要求留出6个字符的空间,以名字a
。 也就是说,有一个名字为a的位置,可以放六个字符。 指针声明char *p;
另一方面,请求一个持有指针的地方。 该指针被称为p
,可以指向任何字符(或连续的字符数组)。声明
char a[] = "string"; char *p = "string";
会导致这样的数据结构:
+---+---+---+---+---+---+----+ a: | s | t | r | i | n | g | \0 | +---+---+---+---+---+---+----+ +-----+ +---+---+---+---+---+---+---+ p: | *======> | s | t | r | i | n | g |\0 | +-----+ +---+---+---+---+---+---+---+
认识到像
x[3]
这样的引用根据x
是数组还是指针产生不同的代码是很重要的。 给定上面的声明,当编译器看到expression式a[3]
,它会发出代码,从位置a
开始,移动三个元素,并在那里获取字符。 当它看到expression式p[3]
,它会发出代码,从位置p
开始,在那里获取指针值,向指针添加三个元素大小,最后获取指向的字符。 在上面的例子中,a[3]
和p[3]
碰巧都是字符l
,但是编译器不同。
资料来源: comp.lang.c常见问题列表·问题6.2
这个?
似乎是一个错字,它不是语义上的有效。 所以答案是假设?
是一个错字,并解释了可能是面试官实际上要问的。
两者截然不同,首先是:
- 第一个创build一个指针。
- 第二个创build一个数组。
阅读更详细的解释:
arrays版本:
char a[] = "string";
创build一个足够大的数组来保存stringstring“string”,包括NULL
终止符。 数组string
使用stringstring“string”进行初始化。 该数组可以稍后修改 。 此外,数组的大小即使在编译时也是已知的,所以sizeof
运算符可以用来确定它的大小。
指针版本:
char *p = "string";
创build一个指向string文字“string”的指针。 这比数组版本快, 但指针指向的string不应该被改变 ,因为它位于只读的实现定义的内存中。 修改这样的string会导致未定义的行为 。
实际上C ++ 03弃用了[Ref 1]没有使用const
关键字的string。 所以声明应该是:
const char *p = "string";
另外,你需要使用strlen()
函数,而不是sizeof
来查找string的大小,因为sizeof
运算符只会给你指针variables的大小。
哪个版本更好,哪个版本可以使用?
取决于使用情况。
- 如果不需要对string进行任何更改,请使用指针版本。
- 如果您打算更改数据,请使用arrays版本。
注意:这不是C ++,但是这是C特定的。
请注意,使用不带const
关键字的string文字在C中是完全有效的。但是,修改string文字仍然是C [参考文献2]中的未定义行为。
这提出了一个有趣的问题,
与C中的string文字一起使用时,char *和const char *有什么区别?
对于Standerdese粉丝:
[参考文献1] C ++ 03标准:§4.2/ 2
不是宽string文字的string文字(2.13.4)可以转换为“指向char的指针”types的右值。 一个宽string文字可以被转换为“指向wchar_t的指针”types的右值。 无论哪种情况,结果都是指向数组的第一个元素的指针。 只有在有明确的适当的指针目标types时,才会考虑这种转换,而不是当一般需要将左值转换为右值时。 [ 注意:此转换已被弃用 。 见附录D.]为了在重载分辨率(13.3.3.1.1)中进行sorting,这个转换被认为是一个数组到指针的转换,然后是一个资格转换(4.4)。 [例如:“abc”被转换为“指向const char的指针”,作为数组到指针的转换,然后到“指向char的指针”作为限定转换。 ]
C ++ 11只是删除上面的引用,这意味着它是C ++ 11中的非法代码。
[参考2] C99标准6.4.5 / 5“string文字 – 语义”:
在翻译阶段7,一个字节或值为零的代码被附加到每个多字节字符序列,这是由一个或多个string产生的。 然后使用多字节字符序列来初始化静态存储持续时间和长度的数组,以便足以包含该序列。 对于string文字,数组元素的types为char,并且用多字节字符序列的单个字节进行初始化; 对于宽string文字,数组元素的types为wchar_t,并用宽字符序列初始化…
没有说明这些数组是否是不同的,只要它们的元素具有适当的值。 如果程序试图修改这样一个数组,行为是不确定的。
char a[] = "string";
这将分配堆栈上的string。
char *p = "string";
这会在堆栈上创build一个指向进程数据段文字的指针。
?
是谁写的不知道他们在做什么。
堆栈,堆,数据分段(和BSS)和文本分段是进程内存的四个部分。 所有定义的局部variables都将被堆栈。 dynamic分配内存使用malloc
和calloc
将在堆中。 所有的全局和静态variables将在数据段中。 文本段将有程序的汇编代码和一些常量。
在这4个段中,文本段是READ ONLY
段,其余三个段是READ
和WRITE
。
char a[] = "string";
– 这个statemnt会为堆栈中的7个字节(因为是局部variables)分配内存,并且会在最后保留所有6个字符( s, t, r, i, n, g
)加NULL字符( \0
)。
char *p = "string";
– 这个语句将为堆栈中的4个字节(如果是32位的机器)分配内存(因为这也是一个局部variables),它将保存值为"string"
的常量string的指针。 这6个字节的常量string将在文本段中。 这是一个恒定的价值。 指针variablesp
只是指向那个string。
现在a[0]
(索引可以是0到5)表示它将访问堆栈中的string的第一个字符。 所以我们也可以在这个位置写。 a[0] = 'x'
。 这个操作是允许的,因为我们在堆栈中有READ WRITE
权限。
但p[0] = 'x'
会导致崩溃,因为我们只有READ
访问文本segement。 如果我们对文本段进行任何写操作,就会发生分段错误。
但是你可以改变variablesp
的值,因为它的局部variables在栈中。 如下所示
char *p = "string"; printf("%s", p); p = "start"; printf("%s", p);
这是允许的。 这里我们改变存储在指针variablesp
中的地址作为stringstart
地址(再次start
也是文本段中的只读数据)。 如果你想修改*p
值,就意味着去dynamic分配内存。
char *p = NULL; p = malloc(sizeof(char)*7); strcpy(p, "string");
现在允许p[0] = 'x'
操作,因为现在我们正在写入堆。
char *p = "string";
创build一个指向存储stringstring"string"
只读存储器的指针。 试图修改string,指出导致未定义的行为。
char a[] = "string";
创build一个数组并通过使用stringstring"string"
来初始化它的内容。
它们在内存的存储位置上有所不同。 理想情况下,第二个应该使用const char *。
第一个
char buf[] = "hello";
创build一个足够大的自动缓冲区来保存字符并将其复制(包括空终止符)。
第二个
const char * buf = "hello";
应该使用const,并简单地创build一个指向通常存储在静态空间的内存中的指针,以修改它是非法的。
相反的(你可以安全地修改第一个,而不是第二个)的事实是从函数返回第二个指针是安全的,但不是第一个。 这是因为第二个将保持有效的内存指针超出函数的范围,第一个不会。
const char * sayHello() { const char * buf = "hello"; return buf; // valid } const char * sayHelloBroken() { char buf[] = "hello"; return buf; // invalid }
a
声明char
数组的数组 – 一个char
数组被终止。
p
声明了一个指针,指向一个不可变的,终止的Cstring,其确切的存储位置是实现定义的。 请注意,这应该是const
限定的(例如const char *p = "string";
)。
如果使用std::cout << "a: " << sizeof(a) << "\np: " << sizeof(p) << std::endl;
,你会看到他们的大小差异(注:价值可能会因系统而异):
a: 7 p: 8
这是什么? 运营商? 它是一个string的一部分,还是有一些特定的含义?
char a[] = ?string?
我假设他们曾经有过双引号的"string"
,有可能被转换为“精明的引号”,那么就不能一直这样表示,转换成?
。
C和C ++有非常相似的指针数组关系…
我不能说出你所询问的两个语句的确切内存位置,但是我发现他们的文章对于理解char指针声明和char数组声明之间的一些区别很有意思。
为了清楚:
C指针和数组的关系
指向数组的C ++指针
我认为重要的是要记住,C和C ++中的数组是一个指向数组第一个元素的常量指针 。 因此你可以在数组上执行指针运算。
char * p =“string”; <—这是一个指向string的第一个地址的指针。
以下也是可能的:
char *p; char a[] = "string"; p = a;
此时,p现在引用第一个内存地址(第一个元素的地址)
所以* p =='s'
*(p ++)=='t'等。 (或*(p + 1)=='t')
而同样的事情会对a:*(a ++)或*(a + 1)也等于't'
char [] arr =“hello”; char * p =“hello”;
现在我们可以做arr [2] ='x';
但是p [2] ='c'会产生运行时错误:)