关于C中指针和字符串的问题

Joh*_*uay 5 c arrays string pointers

可能重复:
C中的char s []和char*s有什么区别?
char*str ="..."和char str [N] ="......"之间的区别?

我有一些令我困惑的代码.

#include <stdio.h>
#include <stdlib.h>

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;
}
Run Code Online (Sandbox Code Playgroud)

当它输出string1的大小时,它打印4,这是预期的,因为指针的大小是4个字节.但是当它打印string2时,它输出15.我认为数组是一个指针,所以string2的大小应该与string1相同吗?那么为什么它为相同类型的数据(指针)打印出两种不同的大小呢?

Chr*_*utz 13

数组不是指针.在某些情况下,数组名称会衰减到指向数组第一个元素的指针:当你将它传递给函数时,将它分配给指针等等.但是否则数组是数组 - 它们存在于堆栈中,具有编译时可以确定的尺寸sizeof,以及所有其他好东西.


Joh*_*ode 5

数组和指针是完全不同的动物.在大多数情况下,指定数组的表达式被视为指针.

首先,一点标准语言(n1256):

6.3.2.1左值,数组和函数指示符
...
3除非它是运算sizeof符或一元运算&符的操作数,或者是用于初始化数组的字符串文字,否则类型为"数组类型 " 的表达式是转换为表达式,类型为"指针输入指向该阵列对象的初始元素,不是左值".如果数组对象具有寄存器存储类,则行为未定义.

字符串文字"这是一个测试"是一个15元素的数组char.在宣言中


    char *string1 = "this is a test";
Run Code Online (Sandbox Code Playgroud)
string1被声明为指向char.根据上面的语言,表达式 "this is a test"的类型将转换char [15]char *,并将结果指针值赋值给string1.


在宣言中


    char string2[] = "this is a test";
Run Code Online (Sandbox Code Playgroud)


发生了不同的事情 更标准的语言:

6.7.8初始化
...
14字符类型数组可以用字符串文字初始化,可选择用大括号括起来.字符串文字的连续字符(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素.
...
22如果初始化未知大小的数组,则其大小由具有显式初始值设定项的最大索引元素确定.在其初始化列表的末尾,该数组不再具有不完整的类型.

在这种情况下,string2声明为数组char,其大小是从初始化程序的长度计算的,字符串文字的内容被复制到数组中.

这是一个假设的记忆图来说明正在发生的事情:

Item          Address       0x00  0x01  0x02  0x03
----          -------       ----  ----  ----  ----
no name       0x08001230    't'   'h'   'i'   's'
              0x08001234    ' '   'i'   's'   ' '
              0x08001238    'a'   ' '   't'   'e'
              0x0800123C    's'   't'    0
              ...
string1       0x12340000    0x08  0x00  0x12  0x30
string2       0x12340004    't'   'h'   'i'   's'
              0x12340008    ' '   'i'   's'   ' '
              0x1234000C    'a'   ' '   't'   'e'
              0x1234000F    's'   '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);
Run Code Online (Sandbox Code Playgroud)

注意,这sizeof是一个操作符,而不是函数调用; 当操作数是表示对象的表达式时,括号不是必需的(尽管它们不会受到伤害).