C复合文字,指向数组的指针

时间:2011-03-31 06:21:28

标签: c compound-literals

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

  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值。

提前致谢。

5 个答案:

答案 0 :(得分: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位小端机器,但我是在iPad上输入此内容,目前无法对其进行验证。再次,请不要使用它;我甚至把它弄得一团糟。

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

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

答案 1 :(得分:13)

首先要明白“数组不是指针”。

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

在上面的例子中,p是一个整数数组。将元素{1,2,3,4,5,6}复制到p。这里不需要进行类型转换,rvaluelvalue类型都匹配,这是一个整数数组,所以没有错误。

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动态分配内存是解决方案。

希望它有所帮助!

答案 2 :(得分: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}}不是类型int*[]的有效初始值设定项(因为{1,2,3}不是int*的有效初始值设定项) 。请注意,它是 int[2][3] - 它只是一个无效的表达式。

它适用于字符串的原因是因为"one"char[]char[N]的有效初始值设定项(对于某些N> 3)。作为表达式,它的大约等同于(const char[]){'o','n','e','\0'},除了编译器在失去constness时不会抱怨太多。

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

与指针混淆的原因:

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

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

答案 3 :(得分:1)

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

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

查看this答案了解更多详情。

答案 4 :(得分:1)

看来你混淆了指针和数组。他们不是一回事!数组是列表本身,而指针只是一个地址。然后,使用指针算法,您可以假装指针是数组,并且事实上数组的名称是指向第一个元素的指针,所有内容总结得很乱。 ;)

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

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

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”,...)不是真正的字符串而是指向这些字符串的指针,所以你要将p [1]分配给字符串文字的地址“一”。
顺便说一下,这和做char abc[]; abc = "abc";一样。这将无法编译,因为您无法为数组指定指针,而char *def; def = "def";可以解决问题。