33

我正在尝试将复合文字分配给变量,但它似乎不起作用,请参阅:

  int *p[] = (int *[]) {{1,2,3},{4,5,6}};

我在 gcc 中遇到错误。

但如果我只写这个:

  int p[] = (int []) {1,2,3,4,5,6};

然后就没事了。

但这不是我想要的。

我不明白为什么会发生错误,因为如果我像数组一样初始化它,或者将它与字符数组的指针一起使用,没关系,请参阅:

  int *p[] = (int *[]) {{1,2,3},{4,5,6}}; //I got a error
  int p[][3] = {{1,2,3},{4,5,6}}; //it's okay
  char *p[] = (char *[]) {"one", "two"...}; // it's okay!

注意我不明白为什么我在第一个中出现错误,请我不能,或者我不想像第二种形式那样写,因为它需要是复合文字,我不想说编译器的数组有多大。我想要第二个类似的东西,但是对于 int 值。

提前致谢。

4

5 回答 5

31

首先,强制转换在您的所有示例中都是多余的,可以删除。其次,您正在使用初始化多维数组的语法,这需要定义第二维以分配连续的内存块。相反,请尝试以下两种方法之一:

  • 多维数组:

    int p[][3] = {{1,2,3},{4,5,6}};
    
  • 指向一维数组的指针数组:

    int p1[] = {1,2,3};
    int p2[] = {4,5,6};
    int *p[] = {p1,p2};
    

后一种方法具有允许不同长度的子阵列的优点。而前一种方法确保内存是连续布局的。

我强烈建议您不要使用的另一种方法是将整数编码为字符串文字。这是一个非便携式黑客。此外,字符串文字中的数据应该是恒定的。你的数组需要是可变的吗?

int *p[] = (int *[]) {
    "\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00",
    "\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00"
};

该示例可能适用于 32 位 little-endian 机器,但我是从 iPad 输入的,目前无法验证。同样,请不要使用它;甚至提出来我都觉得很脏。

您发现的转换方法似乎也适用于指向指针的指针。这也可以像多维数组一样被索引。

int **p = (int *[]) { (int[]) {1,2,3}, (int[]) {4,5,6} };
于 2011-03-31T06:31:22.203 回答
13

首先了解“数组不是指针”。

int p[] = (int []) {1,2,3,4,5,6};

在上述情况下p是一个整数数组。将元素复制{1,2,3,4,5,6}p. 这里不需要进行类型转换,rvalue并且 和lvalue类型都匹配,这是一个整数数组,因此没有错误。

int *p[] = (int *[]) {{1,2,3},{4,5,6}};

“请注意,我不明白为什么我在第一个中遇到错误,..”

在上述情况下,p一个整数指针数组。但它{{1,2,3},{4,5,6}}是一个二维数组(即 [][] )并且不能被类型转换为指针数组。您需要初始化为 -

int p[][3] = { {1,2,3},{4,5,6} };
  // ^^ First index of array is optional because with each column having 3 elements
  // it is obvious that array has two rows which compiler can figure out.

但是为什么这个语句编译了?

char *p[] = {"one", "two"...};

字符串文字不同于整数文字。在这种情况下,p也是一个字符指针数组。实际上"one"它既可以被复制到一个数组中,也可以指向它的位置,认为它是只读的

char cpy[] = "one" ;
cpy[0] = 't' ;  // Not a problem

char *readOnly = "one" ;
readOnly[0] = 't' ;  // Error because of copy of it is not made but pointing
                     // to a read only location.

使用字符串文字,上述任何一种情况都是可能的。所以,这就是编译语句的原因。但 -

char *p[] = {"one", "two"...}; // All the string literals are stored in 
                               // read only locations and at each of the array index 
                               // stores the starting index of each string literal.

我不想说编译器的数组有多大。

使用动态分配内存malloc是解决方案。

希望能帮助到你 !

于 2011-03-31T06:54:37.480 回答
5

因为没有人说过:如果你想要一个指向二维数组的指针,你可以(可能)做类似的事情

int (*p)[][3] = &(int[][3]) {{1,2,3},{4,5,6}};

编辑:或者你可以有一个指向它的第一个元素的指针

int (*p)[3] = (int[][3]) {{1,2,3},{4,5,6}};

您的示例不起作用的原因{{1,2,3},{4,5,6}}是不是 type 的有效初始化程序int*[](因为{1,2,3}不是 的有效初始化程序int*)。请注意,它不是一个int[2][3]— 它只是一个无效的表达式。

它适用于字符串的原因是因为它是and"one"的有效初始化程序(对于某些 N>3)。作为一个表达式,它大致相当于除了编译器在失去常量时不会抱怨太多。char[]char[N](const char[]){'o','n','e','\0'}

是的,初始化程序和表达式之间存在很大差异。我很确定char s[] = (char[]){3,2,1,0};是 C99 中的编译错误(可能还有 C++ pre-0x)。还有很多其他的东西,但是T foo = ...;是变量初始化,而不是赋值,即使它们看起来很相似。(它们在 C++ 中特别不同,因为没有调用赋值运算符。)

以及与指针混淆的原因:

  • 必要时,类型T[]会隐式转换为类型T*(指向其第一个元素的指针)。
  • T arg1[]在函数参数列表中实际上意味着T * arg1. 由于各种原因,您不能将数组传递给函数。这不可能。如果你尝试,你实际上是在传递一个指向数组的指针。(但是,您可以将包含固定大小数组的结构传递给函数。)
  • 它们都可以用相同的(我认为)语义取消引用和下标。

编辑:观察者可能会注意到我的第一个示例在语法上大致等同于int * p = &1;,这是无效的。这在 C99 中有效,因为函数内的复合文字“具有与封闭块相关的自动存储持续时间”(ISO/IEC 9899:TC3)。

于 2011-04-12T00:52:29.227 回答
1

您正在使用的是 int 指针数组。您应该使用指向数组的指针:

int (*p)[] = (int *) {{1,2,3}, {4,5,6}}

查看答案以获取更多详细信息。

于 2011-04-08T07:15:18.443 回答
1

看来您混淆了指针和数组。他们不是一回事!数组就是列表本身,而指针只是一个地址。然后,使用指针算法,您可以假装指针是数组,而事实上,数组的名称是指向第一个元素的指针,所以一切都一团糟。;)

int *p[] = (int *[]) {{1,2,3},{4,5,6}};      //I got a error

这里, p 是一个指针数组,因此您尝试将地址为 1、2、3 的元素分配给第一个数组,将 4、5、6 的元素分配给第二个数组。发生段错误是因为您无法访问这些内存位置。

int p[][3] = {{1,2,3},{4,5,6}};              //it's okay

没关系,因为这是一个数组数组,所以这次 1、2、3、4、5 和 6 不是地址,而是元素本身。

char *p[] = (char *[]) {"one", "two"...};    // it's okay!

这没关系,因为字符串文字(“one”,“two”,...)不是真正的字符串,而是指向这些字符串的指针,因此您将字符串文字“one”的地址分配给 p[1] .
顺便说一句,这与做char abc[]; abc = "abc";. 这不会编译,因为您不能将指针分配给数组,同时char *def; def = "def";解决了问题。

于 2011-04-08T12:25:35.397 回答