关于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

字符串文字具有静态范围; 也就是说,它们的存储器在程序启动时被搁置并保持到程序终止。 试图修改字符串文字的内容会调用未定义的行为; 底层平台可能允许也可能不允许,标准对编译器没有限制。 最好表现为文字总是不可写的。

在上面的内存映射中,字符串文字的地址在某种程度上与string1string2的地址相关,以说明这一点。

无论如何,你可以看到具有指针类型的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是一个编译器函数,因此它可以知道堆栈变量的大小。

数组不是指针。 指针是指向内存位置的变量,而数组是分配的顺序内存的起始点

这是因为

  1. string1保存指针,其中指针具有连续的字符及其不可变。
  2. string2是你的字符所在的位置。

基本上C编译器以不同的方式对它们进行了解释。 在这里精美解释http://c-faq.com/aryptr/aryptr2.html 。