Answers:
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
第三个与第一个相同。
一般规则是运算符优先级。当函数指针进入图片时,它可能变得更加复杂。
( ) [ ]
从左到右关联,并且优先级高于*
读int* arr[8]
为大小8的数组(每个元素指向一个int)和int (*arr)[8]
指向大小为8的数组的指针,该数组保存整数
使用K&R建议的cdecl程序。
$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>
它也以其他方式起作用。
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
我不知道它是否有正式名称,但我称它为Right-Left Thingy(TM)。
从变量开始,然后向右,向左,向右...等等。
int* arr1[8];
arr1
是由8个指向整数的指针组成的数组。
int (*arr2)[8];
arr2
是指向8个整数的数组的指针(右括号为左括号)。
int *(arr3[8]);
arr3
是由8个指向整数的指针组成的数组。
这应该可以帮助您解决复杂的声明。
( ) [ ]
和从右到左的结合* &
int *a[4]; // Array of 4 pointers to int
int (*a)[4]; //a is a pointer to an integer array of size 4
int (*a[8])[5]; //a is an array of pointers to integer array of size 5
[5]
)表示内部尺寸。这意味着这(*a[8])
是第一维,因此是数组的外部表示。什么内的每个元素a
点是大小5的不同整数数组
最后两个答案也可以从C语言的黄金法则中推论得出:
使用后声明。
int (*arr2)[8];
如果取消引用会arr2
怎样?您将得到一个由8个整数组成的数组。
int *(arr3[8]);
如果从中获取元素会arr3
怎样?您将获得一个指向整数的指针。
这在处理指向函数的指针时也有帮助。以sigjuice为例:
float *(*x)(void )
取消引用后会发生什么x
?您将获得一个不带参数即可调用的函数。打电话时会发生什么?它将返回指向的指针float
。
但是,运算符优先级始终很棘手。但是,使用括号实际上也会造成混淆,因为声明是在使用之后进行的。至少对我来说,直观上arr2
看起来像是由8个指向int的指针组成的数组,但实际上是相反的。只是需要一些习惯。有足够的理由总是向这些声明添加评论,如果您问我:)
编辑:示例
顺便说一句,我偶然遇到了以下情况:一个具有静态矩阵并使用指针算术查看行指针是否超出范围的函数。例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))
int *
put_off(const int newrow[2])
{
static int mymatrix[3][2];
static int (*rowp)[2] = mymatrix;
int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);
memcpy(rowp, newrow, sizeof(*rowp));
rowp += 1;
if (rowp == border) {
rowp = mymatrix;
}
return *rowp;
}
int
main(int argc, char *argv[])
{
int i = 0;
int row[2] = {0, 1};
int *rout;
for (i = 0; i < 6; i++) {
row[0] = i;
row[1] += i;
rout = put_off(row);
printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
}
return 0;
}
输出:
0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]
请注意,border的值永远不会改变,因此编译器可以对其进行优化。这与您最初可能要使用的内容不同::const int (*border)[3]
声明border为指向3个整数数组的指针,只要变量存在,该整数就不会更改值。但是,该指针可以随时指向任何其他此类数组。我们希望参数具有这种行为(因为此函数不会更改任何这些整数)。使用后声明。
(ps:随时改进此示例!)
作为一个经验法则,右目运算符(如[]
,()
等)采取优先于左侧的。因此,int *(*ptr)()[];
将是一个指向一个函数的指针,该函数返回一个指向int的指针的数组(在括号中尽快获得正确的运算符)
error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];
在GCC 8下与$ gcc -std=c11 -pedantic-errors test.c
int *(*ptr)();
允许稍后使用诸如p()[3]
(或(*p)()[3]
)之类的表达式。
int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }
并这样称呼:foo(arr)[4];
哪个应该包含arr[2][4]
,对吗?
我认为我们可以使用简单的规则..
example int * (*ptr)()[];
start from ptr
“ ptr
是指向”向右..“ ”“” 的指针,现在向左走“(”出来向右“()”,因此“指向一个不带参数的函数”向左“并返回一个指针” go“向右“到数组”向左“整数”
)
,现在向左走...它是*
“指向”的指针向右走...它是)
,现在向左走...这是一个(
出来,向右走,()
所以“到一个不带参数的函数”,向右走…… []
并返回一个数组,向右走;
,所以向左走…… *
“指向”的指针向左走…… int
“整数”
这是一个有趣的网站,解释了如何在C语言中读取复杂类型:http : //www.unixwiz.net/techtips/reading-cdecl.html
这是我的解释方式:
int *something[n];
关于优先级的注意事项:数组下标运算符(
[]
)比取消引用运算符()具有更高的优先级*
。
因此,这里我们将应用[]
before *
,使该语句等效于:
int *(something[i]);
请注意声明的意义:
int num
meansnum
是一个int
,int *ptr
或int (*ptr)
Means(的值是ptr
)是一个int
,它ptr
指向int
。
可以理解为((某物的第i个索引处的值)的值)是一个整数。因此,(某物第ith个索引处的值)是一个(整数指针),这使某物成为整数指针数组。
在第二个中
int (*something)[n];
为了使此语句有意义,您必须熟悉以下事实:
关于数组的指针表示的注意:
somethingElse[i]
等同于*(somethingElse + i)
因此,替换somethingElse
为(*something)
,我们得到*(*something + i)
,它是每个声明的整数。因此,(*something)
给我们一个数组,它等于(指向数组的指针)。
我想第二个声明使许多人困惑。这是一种了解它的简单方法。
让我们拥有一个整数数组,即int B[8]
。
让我们还有一个指向B的变量A。现在,A处的值为B,即(*A) == B
。因此,A指向整数数组。在您的问题中,arr与A类似。
同样,在中int* (*C) [8]
,C是指向整数的指针数组的指针。
int *arr1[5]
在此声明中,arr1
是5个指向整数的指针的数组。原因:方括号的优先级高于*(取消引用的运算符)。在这种类型中,行数是固定的(此处为5),但列数是可变的。
int (*arr2)[5]
在此声明中,arr2
是指向5个元素的整数数组的指针。原因:这里()括号的优先级高于[]。在这种类型中,行数是可变的,但列数是固定的(此处为5)。