【问题标题】:Question about pointers and strings in C [duplicate]关于C中的指针和字符串的问题[重复]
【发布时间】:2011-05-21 18:34:27
【问题描述】:

可能重复:
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一样吧?那么为什么它会为同一种类型的数据(指针)打印出两种不同的大小呢?

【问题讨论】:

  • 另外,sizeof 返回一个 size_t,与 %i 预期的 int 不同,它是未签名的。 size_t 变量的正确格式是 %zu
  • Array 不是 pinter!记住这一点!

标签: c arrays string pointers


【解决方案1】:

数组不是指针。数组名称 decay 在某些情况下指向指向数组第一个元素的指针:当您将其传递给函数时,当您将其分配给指针时,等等。但除此之外,数组就是数组 - 它们存在于堆栈,具有可以通过sizeof 确定的编译时大小,以及所有其他好东西。

【讨论】:

    【解决方案2】:

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

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

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

    字符串文字“这是一个测试”是一个 15 元素数组 char。在声明中

    
        char *string1 = "this is a test";
    

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

    在声明中

    
        char string2[] = "this is a test";
    


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

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

    在这种情况下,string2 被声明为 char 的数组,它的大小是根据初始化器的长度计算的,并且字符串文字的 内容 被复制到大批。

    这是一个假设的内存映射来说明正在发生的事情:

    项目地址 0x00 0x01 0x02 0x03 ---- -------- ---- ---- ---- ---- 没有名字 0x08001230 't' 'h' 'i' 's' 0x08001234 ' ' '我' 's' ' ' 0x08001238 'a' ' ' 't' 'e' 0x0800123C 's' 't' 0 ... 字符串1 0x12340000 0x08 0x00 0x12 0x30 string2 0x12340004 't' 'h' 'i' 's' 0x12340008 ' ' '我' 's' ' ' 0x1234000C 'a' ' ' 't' 'e' 0x1234000F 's' 't' 0

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

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

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

    由于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是一个操作符,而不是一个函数调用;当操作数是一个表示 object 的表达式时,括号不是必需的(尽管它们不会造成伤害)。

    【讨论】:

    • 哇!谢谢你的详细解答!这真的帮助了我。
    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      一个未知大小的数组等价于一个用于 sizeof 目的的指针。 static 大小的数组算作它自己的类型,用于 sizeof 目的,sizeof 报告数组所需的存储大小。即使string2 的分配没有明确的大小,C 编译器也会神奇地对待它,因为带引号的字符串直接初始化并将其转换为具有静态大小的数组。 (因为内存没有以任何其他方式分配,毕竟它无能为力。)出于sizeof 行为的目的,静态大小数组与指针(或动态数组!)的类型不同,因为那只是C 怎么样。

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

            因为

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

            基本上,C 编译器以不同的方式解释这两个。这里解释得很漂亮http://c-faq.com/aryptr/aryptr2.html

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2017-08-10
              • 1970-01-01
              • 1970-01-01
              • 2021-08-12
              • 1970-01-01
              • 2013-03-11
              • 1970-01-01
              相关资源
              最近更新 更多