【问题标题】:difference between character array and integer array字符数组和整数数组的区别
【发布时间】:2015-08-08 04:57:22
【问题描述】:
  1. char *s = "Hello"
  2. char s[6] = "Hello"

上述任何一种语法都可以正常工作。

但是跟随呢?

  1. int a[3] = {1,2,3}(这会很好用)
  2. 但为什么不这样呢,int *a = {1, 2, 3};

解释以及案例 [2] 和 [4] 之间的比较会有所帮助。

【问题讨论】:

  • 请注意,实际上情况 1 是例外,而不是其他情况。另请注意,特别是对于 C,最好对编译器进行额外的检查,因为您可以轻松创建相当复杂的表达式,只有专家才能轻松推断出语义。

标签: c arrays string pointers initialization


【解决方案1】:

这是因为"Hello" 被替换为“字符串文字 Hello 的地址”。 所以char *s = "Hello" 的意思是“分配给指针s 字符串文字Hello的地址”。

同时{1, 2, 3} 不构成地址,也不会被替换。除了地址之外,您不能为指针分配任何其他内容,因此您不能写int *a = {1, 2, 3}

【讨论】:

    【解决方案2】:
    1. char *s="Hello"

      这里,s 是一个指向char 的指针,它指向字符串文字"Hello" 的基地址。

    2. char s[6]="Hello"

      这里s 是一个数组,由 6 个chars 组成,有Hello\0 作为初始化程序价值。

    3. int a[3]={1,2,3}

      这里,a 是一个由 3 个元素组成的 int 数组,使用值 123 进行初始化。

    注意:以上三个都是合法有效

    1. int *a={1,2,3};无效。

      这里,a 的类型为 int *,而 大括号括起来的 列表不提供 int * 的值。所以,这不是一个定义的行为并且是无效的。

    【讨论】:

    • 如果's'指向字符数组"Hello"的基地址,那为什么'a'不指向整数数组{1,2,3}的基地址呢?有什么特别的吗?
    • @ravipandhi 是的,"Hello" 被称为 字符串文字,它返回文字的基地址。 {1,2,3} 不是 int lireal,它被称为 breace 封闭的初始化列表。
    • 就像 s++ 通过向基数添加 1 个字节(char 的大小)来遍历字符数组中的下一个元素一样,案例 4 似乎在逻辑上不正确,例如“a++ 遍历到中的下一个元素通过将机器相关的整数大小添加到基数来获得整数数组?
    • @ravipandhi 了解这里的基本问题,"Hello" 返回一个char *,您可以将其放入另一个char *,但{1,2,3}返回一个@首先是 987654351@。
    • @ravipandhi:这就是语言的设计方式。字符串字面量是特殊的,其处理方式与 {1, 2, 3} 等初始化程序不同。像"Hello" 这样的字符串文字是一个数组表达式,并且在大多数情况下,数组表达式“衰减”为指针表达式。初始化器{1,2,3}本身,不是数组表达式,因为语言定义是这样说的。正如余浩在下面指出的那样,(int[]){1,2,3}一个数组表达式(从 C99 开始),它衰减为一个指针表达式,所以你可以写成int *a = (int[]){1,2,3}。 .
    【解决方案3】:

    使用字符串初始化字符数组是一种特殊情况:char s[6] = "hello" 被视为编写代码char s[6] = { 'h', 'e', 'l', 'l', 'o', '\0'};。用字符串初始化字符数组是很常见的,所以这个习惯用法很有意义。

    【讨论】:

    • 这不能回答问题,IMO。
    • char s[6] = { 'h', 'e', 'l', 'l', 'o', '\0'}; 是否使它可写?我会这么认为。
    • @Eregrith,是的。 s 是一个局部数组,它的初始化方式不会改变它的可变性。
    • @WilliamPursell 啊,是的,对不起,我忘记了char s[6] = "hello"可写的。我的坏
    【解决方案4】:
    int *a = {1, 2, 3};
    

    语法不正确,因为{1, 2, 3} 不能用于初始化指针。

    不过,稍作修改就可以让它发挥作用:

    int *a = (int []){1, 2, 3};
    

    这是一个 C99 复合字面量。

    【讨论】:

      【解决方案5】:

      这不起作用的原因是初始值的数据类型没有定义。对于字符串文字,这是由语法隐式给出的。但{ 1,2,3} 可以是数组、结构或许多其他变体。

      你必须指定类型:

      int *ia = (int []){1,2,3};
      

      这使用复合文字 (C99)。

      请注意,这不仅适用于初始化,也适用于普通代码。

      【讨论】:

      • 你能具体给我一些“许多其他变体”的例子吗?
      • @ravipandhi:具有匿名联合的结构,依赖强制的浮点数组?足够了?发挥你的想象力。
      【解决方案6】:

      案例 4 不被支持但其他案例被支持的原因是历史性的。这些因素是一些早期有影响力的程序员和编译器供应商之间的游说和政治互动,而不是经过深思熟虑的合理技术决策。

      因此,如果您正在寻找可靠的技术理由,您将找不到。

      从历史上看,案例 2 和 3 在 C 演化的早期就得到了支持。您的案例 2 达到了与

      相同的效果
        char s[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
      

      除了char 类型之外,没有任何对应的字符串文字可以初始化数组。

      从历史上看,案例1是程序员想要实现的效果引入的异常

        char s_temp[] = "Hello";
        char *s = temp_s;
      

      输入更少(即作为单个语句)。支持案例 1 的游说最终获胜(它被引入主流编译器,后来被引入标准)。情况 1 是标准中唯一可以使用数组初始化程序直接初始化指针而无需类型转换的情况。

      从历史上看,程序员从未对案例 4 提出要求或游说。

      不管你喜不喜欢,这就是为什么支持案例 1、2、3 而不支持案例 4 的原因。

      案例 2 和 4 之间没有真正的比较,因为它们(寻求)实现不同的目标。与案例 2 一样,字符串字面量是一个数组初始化器,仅适用于 char 的数组 - 没有非char 类型的对应物。案例 4 尝试使用数组初始化器初始化指针。

      【讨论】:

      • 这是一个很好的解释,所以程序员从不想要像案例4这样的东西,所以它不存在?他们能否提供支持,例如“案例 4 想要初始化一个 int 数组,而要找到的下一个 int 是通过在基地址中添加整数的大小?这可能吗?
      • 从编译器的角度来看,实际上有充分的理由不支持这一点。编译器推断实际类型可能变得太复杂了。使用 C99 的复合文字,引入了一种优越的(更明确和通用的)替代方法。
      • @Olaf 好吧,过去支持这个变得太复杂了?使用 C99,他们提出了一种对特定类型进行类型转换的解决方案以提供支持?是吗?那么问题就解决了! :)
      • @ravipandhi:别傻了。这不是类型转换,而是复合文字。强制转换会将 on 类型转换/强制重新解释为另一种类型,而复合初始值设定项上的大括号会告诉编译器实际类型。您必须查看整个构造:带括号的类型加块,而不仅仅是第一部分。实际上,类型转换在块上没有意义。而且,是的,如果编译器必须从左侧推导出类型,或者如果它已经像任何其他表达式一样出现在右侧,这是完全不同的。正如彼得所写,实际上 `char *cp = "" 是 hack
      • 另请注意,我们谈论的是 80 年代的编译器;他们有足够的工作尝试优化代码,因此很高兴能够减少解析工作和内存占用。
      【解决方案7】:
      1. int a[3] = {1,2,3};

      这是数组的正常初始化语法。

      1. char s[6] = "Hello";

      这是一个特殊情况只用于字符数组的初始化语法,你可以在右边写一个字符串字面量,它会扩展为上面的正常初始化语法,即char s[6] = {'H','e','l','l','o','\0'};

      1. char *s = "Hello";

      这是标量变量的正常初始化语法,初始化为右侧的表达式。这里,"Hello" 是一个有效的 C 表达式。

      1. int *a = {1, 2, 3};

      这与上面的 (1) 不同,{1, 2, 3} 不是有效的 C 表达式。

      【讨论】:

        猜你喜欢
        • 2013-03-27
        • 1970-01-01
        • 2012-02-04
        • 1970-01-01
        • 2010-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-09
        相关资源
        最近更新 更多