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

时间:2010-12-07 18:15:12

标签: c arrays string pointers

  

可能重复:
  What is the difference between char s[] and char *s in C?
  Difference between char *str = “…” and 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;
}

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

7 个答案:

答案 0 :(得分:13)

数组不是指针。在某些情况下,数组名衰减指向数组的第一个元素的指针:将它传递给函数时,将它指定给指针时等等。但是否则数组是数组 - 它们存在于堆栈,具有可以使用sizeof确定的编译时大小,以及所有其他好东西。

答案 1 :(得分:5)

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

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

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

字符串文字“this is a test”是一个15个元素的char数组。在声明中


    char *string1 = "this is a test";

string1被声明为指向char的指针。根据上述语言,表达式的类型“这是一个测试”从char [15]转换为char *,并将得到的指针值分配给{{1} }。


在宣言中

string1


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

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

在这种情况下, char string2[] = "this is a test"; 被声明为string2的数组,其大小是根据初始化程序的长度和字符串文字的内容计算的被复制到数组。

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

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

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

在上面的内存映射中,字符串文字的地址与charstring1的地址略有不同,以说明这一点。

无论如何,您可以看到具有指针类型的string2包含字符串文字的地址。作为数组类型的string1包含字符串文字的内容的副本。

由于string2的大小在编译时是已知的,string2返回数组中的大小(字节数)。

sizeof转换说明符不适合用于%i类型的表达式。如果您在C99工作,请使用size_t。在C89中,您将使用%zu并将表达式转换为%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); 运算符,而不是函数调用;当操作数是表示对象的表达式时,括号不是必需的(尽管它们不会受到伤害)。

答案 2 :(得分:4)

string1是一个指针,但string2是一个数组。

第二行类似于int a[] = { 1, 2, 3};,它将a定义为长度为3的数组(通过初始值设定项)。

string2的大小为15,因为初始化程序是以nul结尾的(因此15是字符串的长度+ 1)。

答案 3 :(得分:4)

未知大小的数组相当于用于sizeof目的的指针。 static 大小的数组为sizeof目的计为其自己的类型,sizeof报告数组所需的存储大小。即使string2的分配没有明确的大小,C编译器也会神奇地处理它,因为带引号的字符串直接初始化并将其转换为具有静态大小的数组。 (由于内存没有以任何其他方式分配,毕竟它没有别的东西。)静态大小数组是与指针(或动态数组!)不同的类型,用于sizeof行为,因为这就是C的方式。

This似乎是对sizeof行为的一个不错的参考。

答案 4 :(得分:2)

编译器知道test2是一个数组,因此它打印出分配给它的字节数(14个字母加上空终止符)。请记住,sizeof是一个编译器函数,因此它可以知道堆栈变量的大小。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

因为

  1. string1保存指针,其中指针具有连续的字符&amp;它的 不可改变的。
  2. string2是你的角色所在的位置。
  3. 基本上C编译器以不同的方式对这两个进行了解释。这里精美地解释http://c-faq.com/aryptr/aryptr2.html