【问题标题】:Why does int* ptr_arr_int = {1,2}; not work in C/C++?为什么 int* ptr_arr_int = {1,2};不能在 C/C++ 中工作?
【发布时间】:2019-11-12 21:28:49
【问题描述】:

为什么int* ptr_arr_int = {1,2}; 给出编译器错误,而char* ptr_arr_char = "amruth"; 编译正常?

int* ptr_arr_int = {1,2};         // ->ERROR
char* ptr_arr_char = "amruth";    // ->OK

【问题讨论】:

  • 那些不相等。 char* ptr_arr_char2 = {'a', 'b'}; 也不起作用。
  • @Blaze ,什么是等效的 char* ptr_arr_char = "amruth";整数?
  • 请注意,您正在尝试错误的事情,因为 C++ 中的初始化很糟糕,而不是因为任何智力限制 - 以防万一您想知道 ;)
  • @AmruthA 没有。
  • 我不推荐 c/c++,它只是未定义的行为。

标签: c++ c pointers


【解决方案1】:

"amruth" 在 C++ 中是 const char[7] 类型,在 C 中是 char[7] 类型(尽管尝试修改字符串的行为未定义)。

在某些情况下,这可能衰减const char*char* 类型,例如您的情况。

虽然int[2] 在某些情况下会类似地衰减为int*,但{1, 2} 既不是int[2] 也不是const int[2] 类型;而是一个大括号初始化器

【讨论】:

  • 一个int[2] 类型会很高兴地衰减为int*,但{1,2} 本身并不是int[2]。它只是一个大括号初始化器。使用正确的上下文,它很可能正在初始化,例如float[5]
  • @PSkocik:是的,我对我的最后一段也不满意。
  • 可能值得一提的是 C 复合文字,它完全能够像字符串文字一样生成对象,但在 C++ 中不存在。双语问题变得棘手的另一个例子。
【解决方案2】:

如前所述,字符串是一个const char[7] 数组,虽然它可以衰减为char*,但{1, 2} 不能衰减为int*(它是一个大括号初始化列表,类似地:std::initializer_list)。但请注意,还有数组 [] 声明,它允许您自动声明数组。将其与自 C++11 以来的 list-initialization 结合起来,您就可以通过 [] 进行初始化:

int ptr_arr_int[] = { 1,2 }; //OK
char ptr_arr_char[] = "amruth"; //OK

【讨论】:

  • {1, 2} 本身不是std::initializer_list,而是一个大括号初始化列表。这些是不同的东西,尽管它们有相似的名称。见:eel.is/c++draft/temp.deduct.type#5.6
【解决方案3】:

一个字符串本身就意味着一个存储类——它是一个static(+实际上是constchar数组,使用特殊语法声明。

与此相反,尚不清楚应该如何存储int *ptr_arr_int = {1, 2} 中的{1, 2}。应该是static 还是auto

如果您希望在本地范围内使用 auto 或在文件范围内使用 static,则在 C>=99 中您可以显式执行 int *ptr_arr_int = &(int[]){1,2}[0];&[0] 是可选的)。

你可以想象这个隐含的,但是你会走多远呢?int ****x = {1,2};通过创建一个数组、一个指向它的指针、一个指向那个的指针等来初始化,可能会产生相当多的代码/数据和在一个简单的结构下隐藏大量代码/数据并不是 C 的方式。大括号语法何时应该初始化最终目标基本类型或一些中间指针也不清楚。

【讨论】:

    【解决方案4】:

    这仅仅是因为语言语法是这样说的。关于数组:

    • 我们必须用大括号括起来的列表{...} 初始化一个数组,其中不再包含可以放入数组中的项目。
    • 作为一项特殊规则,char 数组可以使用字符串文字 "..." 进行初始化。

    但是,您的代码中没有数组,只有指针。

    char* 始终可以设置为指向字符串文字(在 C 中),因此 char* ptr_arr_char = "amruth"; 是有效的。但是,它是可疑的样式,因为无法修改字符串文字。正确的样式是使用const char*

    C++ 更严格,C++ 中的字符串文字类型为const char[]。如果您不使用const char*,C++ 编译器可能会给出类似“不推荐使用的转换”的警告。

    至于int* ptr_arr_int = {1,2};,有两个问题。

    • {1,2} 是一个初始化列表,但 ptr_arr_int 是一个单项,所以没有任何意义。有一个特殊的、奇怪的规则实际上允许我们在初始化单个变量时使用{},但是你必须只有一个初始化器。
    • 不能用整数初始化指针。见"Pointer from integer/integer from pointer without a cast" issues

    如果您想让指针指向一个仅存在于本地范围内的临时数组,那么您可以使用名为 compound literal 的 C 功能:

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

    这是 AFAIK 在 C++ 中无法做到的,除非您依赖非标准扩展。但是在任何一种语言中,您当然都可以简单地这样做:

    int arr[2] = {1,2};
    int* ptr_arr_int = arr;
    

    【讨论】:

      【解决方案5】:

      您正在声明一个指向int (int*) 的指针数组。但是你初始化数组的值(12)是不是指向整数的指针,它们是普通的integers。

      【讨论】:

        【解决方案6】:

        你不能,因为int * 不是一个可以像= {1,2}; 那样用两个值初始化的结构。

        你可以这样初始化它:

        int * ptr_arr_int = nullptr;
        


        另一种方法可能是使用一个需要两个构造值的对象:

        struct Point
        {
            int a;
            int b;
        };
        

        那么你可以写:

        Point p = {1,2};
        

        【讨论】:

          【解决方案7】:

          不...这不正确...初始化程序仅对数组有效。你写了吗:

          int array[] = {1, 2};
          

          这将是有效的....但是您正在尝试初始化一个 pointer 变量,所以这将是有效的(尽管有警告,因为0xf45 不是地址):

          int *pointer = { 0xf45 };
          

          (因为你只放了一个条目,它被认为是一个值)但是:

          int *pointer = { 0xf45, 0 };
          

          (您将收到关于excess elements in scalar initializer 的另一个警告)这意味着对于单个变量,您尝试使用两个初始化程序。大括号符号的诞生是为了能够初始化数组,但也允许与标量类型一起使用。这意味着这两个符号:

          { 0 }; /* a single value between braces */
          

          0;
          

          是等价的。

          解决您的问题的方法是多做一步,声明一个数组,然后从指针指向它:

          int array[] = {1, 2};
          
          int *pointer = array;
          

          但是认为您可以使指针指向与数组开头不同的位置,并且您不能将数组神奇地移动到其他地方。而&array 表示数组array 的地址,而&pointer 表示指针变量pointer 的地址。 pointer指向array的地址,而array是指向array[0]地址的常量指针。

          指针和数组有些混乱,但永远不要认为它们是同一回事。只需将sizeof(char[120])sizeof(char *) 进行比较,您就会看到。

          【讨论】:

            猜你喜欢
            • 2023-03-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-07-10
            • 2010-10-23
            • 2013-07-25
            • 1970-01-01
            相关资源
            最近更新 更多