关于C中指针和字符串的问题
可能重复:
C中的char s []和char * s有什么区别?
char * str =“…”和char str [N] =“……”之间的区别?
我有一些令我困惑的代码。
#include #include int main(int argc, char *argv[]) { char* string1 = "this is a test"; char string2[] = "this is a test"; printf("%i, %i\n", sizeof(string1), sizeof(string2)); system("PAUSE"); return 0; }
当它输出string1的大小时,它打印4,这是预期的,因为指针的大小是4个字节。 但是当它打印string2时,它输出15.我认为数组是一个指针,所以string2的大小应该与string1相同吗? 那么为什么它为相同类型的数据(指针)打印出两种不同的大小呢?
数组和指针是完全不同的动物。 在大多数情况下,指定数组的表达式被视为指针。
首先,一点标准语言( n1256 ):
6.3.2.1左值,数组和函数指示符
…
3除非它是sizeof
运算符或一元&
运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为“array of type ”的表达式转换为类型为“指向类型的指针”的表达式指向数组对象的初始元素,而不是左值。 如果数组对象具有寄存器存储类,则行为未定义。
字符串文字“this is a test”是一个15元素的char
数组。 在宣言中
char *string1 = "this is a test";
string1
被声明为char
的指针。 根据上面的语言, 表达式 “this is a test”的类型从char [15]
转换为char *
,结果指针值分配给string1
。
在宣言中
char string2[] = "this is a test";
发生了不同的事情 更标准的语言:
6.7.8初始化
…
14字符类型数组可以由字符串文字初始化,可选地用大括号括起来。 字符串文字的连续字符(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素。
…
22如果初始化未知大小的数组,则其大小由具有显式初始值设定项的最大索引元素确定。 在其初始化列表的末尾,该数组不再具有不完整的类型。
在这种情况下, string2
被声明为char
数组,其大小是根据初始化程序的长度计算的,字符串文字的内容被复制到数组中。
这是一个假设的记忆图,用于说明正在发生的事情:
项目地址0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- 没有名字 0x08001230't''我''s' 0x08001234'''我'''' 0x08001238'一个'''''e' 0x0800123C''t'0 ... string1 0x12340000 0x08 0x00 0x12 0x30 string2 0x12340004't''h''我's' 0x12340008'''我'''' 0x1234000C'a'''t''e' 0x1234000F的't'0
字符串文字具有静态范围; 也就是说,它们的存储器在程序启动时被搁置并保持到程序终止。 试图修改字符串文字的内容会调用未定义的行为; 底层平台可能允许也可能不允许,标准对编译器没有限制。 最好表现为文字总是不可写的。
在上面的内存映射中,字符串文字的地址在某种程度上与string1
和string2
的地址相关,以说明这一点。
无论如何,你可以看到具有指针类型的string1
包含字符串文字的地址 。 string2
是一个数组类型,包含字符串文字内容的副本。
由于string2
的大小在编译时是已知的,因此sizeof
返回数组中的大小(字节数)。
%i
转换说明符不适用于size_t
类型的表达式。 如果您在C99工作,请使用%zu
。 在C89中,您将使用%lu
并将表达式转换为unsigned long
:
C89: printf("%lu, %lu\n", (unsigned long) sizeof string1, (unsigned long) sizeof string2); C99: printf("%zu, %zu\n", sizeof string1, sizeof string2);
请注意, sizeof
是一个运算符 ,而不是函数调用; 当操作数是表示对象的表达式时,括号不是必需的(尽管它们不会受到伤害)。
数组不是指针。 在某些情况下,数组名称会衰减到指向数组第一个元素的指针:将它传递给函数时,将它分配给指针时等等。但是否则数组是数组 – 它们存在于堆栈中,具有编译时尺寸可以用sizeof
和所有其他好东西来确定。
string1
是一个指针,但string2
是一个数组。
第二行类似于int a[] = { 1, 2, 3};
它将a
定义a
长度为3的数组(通过初始化器)。
string2
的大小为15,因为初始化程序是以nul结尾的(因此15是字符串的长度+ 1)。
未知大小的数组相当于用于sizeof目的的指针。 静态大小数组作为sizeof目的的自己的类型计数,sizeof报告数组所需的存储大小。 即使string2
的分配没有明确的大小,C编译器也会神奇地处理它,因为带引号的字符串直接初始化并将其转换为静态大小的数组。 (由于内存没有以任何其他方式分配,毕竟它没有别的东西可以做。)静态大小数组与指针(或动态数组!)的不同类型是出于sizeof
行为的目的,因为那只是C的方式是。
这似乎是对sizeof行为的一个不错的参考。
编译器知道test2
是一个数组,因此它打印出分配给它的字节数(14个字母加上空终止符)。 请记住, sizeof
是一个编译器函数,因此它可以知道堆栈变量的大小。
数组不是指针。 指针是指向内存位置的变量,而数组是分配的顺序内存的起始点
这是因为
- string1保存指针,其中指针具有连续的字符及其不可变。
- string2是你的字符所在的位置。
基本上C编译器以不同的方式对它们进行了解释。 在这里精美解释http://c-faq.com/aryptr/aryptr2.html 。