为什么int * ptr_arr_int = {1,2};在C / C ++中不起作用?

时间:2019-07-02 09:07:04

标签: c++ c pointers

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

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

7 个答案:

答案 0 :(得分:12)

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

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

尽管在某些情况下int[2]的衰变与int*类似,但{1, 2}既不是int[2]也不是const int[2]类型;而是 brace-initializer

答案 1 :(得分:7)

如上所述,该字符串是一个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

答案 2 :(得分:6)

一个字符串本身就已经意味着一个存储类-它是使用特殊语法声明的static(有效地constchar数组。

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

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

可以想象,您可以将其隐式化,但是您需要花多长时间呢?int ****x = {1,2};通过创建一个数组,指向该数组的指针,指向该数组的指针等进行初始化,可能会导致很多代码/数据并在一个简单的结构下隐藏大量代码/数据并不是C语言。大括号语法何时应初始化最终目标基本类型或某些中间指针还不清楚。

答案 3 :(得分:5)

这仅仅是因为语言语法如此表示。关于数组:

  • 我们必须使用大括号括起来的列表{...}初始化 array ,其中不再包含任何适合该数组的项。
  • 作为特殊规则,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

如果打算将指针指向仅存在于本地范围内的临时数组,则可以使用称为 compoundliteral 的C功能:

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

但是,除非您依靠非标准扩展名,否则这不是AFAIK在C ++中无法做到的。但是,无论使用哪种语言,您当然都可以这样做:

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

答案 4 :(得分:3)

您要声明一个指向intint*)的指针的数组。但是,您使用{12)初始化数组的值是 not 指向整数的指针,它们是普通的int egers。

答案 5 :(得分:3)

您不能这样做,因为int *不能像使用= {1,2};那样用两个值初始化。

您本可以通过以下方式初始化它:

int * ptr_arr_int = nullptr;


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

struct Point
{
    int a;
    int b;
};

那么你可能会写:

Point p = {1,2};

答案 6 :(得分:2)

否...不正确...初始化程序仅对数组有效。你写过吗?

int array[] = {1, 2};

这将是有效的...。但是您尝试初始化指针变量,因此这将是有效的(尽管有警告,因为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 *)进行比较,就会看到。