Arrays 理解高级指针算术语法有困难
假设我们获得了下一个设置:Arrays 理解高级指针算术语法有困难,arrays,c,pointers,pointer-arithmetic,Arrays,C,Pointers,Pointer Arithmetic,假设我们获得了下一个设置: int (*p)[9]; 它是一个常规指针,还是指向9*sizeof(int)大的内存块的某种特殊指针 我如何引用这种语法 假设我有一个给定的矩阵: 例如,如果我们增加p,指针算术将如何工作 我该如何投出这样的类型 下一个代码的输出是25,我认为它与上面显示的特殊语法有一个链接。有人能给我解释一下为什么输出不是21 你应该读书 int (*p)[9]; 作为指向int[9](9个整数)数组的指针。它是一个常规指针,类型为int[9] 指针算法的工作原理
int (*p)[9];
9*sizeof(int)
大的内存块的某种特殊指针
25
,我认为它与上面显示的特殊语法有一个链接。有人能给我解释一下为什么输出不是21
int (*p)[9];
作为指向int[9]
(9个整数)数组的指针。它是一个常规指针,类型为int[9]
指针算法的工作原理与其他指针相同,取决于指针的大小,即sizeof(int[9])
也就是说,对于另一个问题,如果有疑问,请检查数据类型
int main()
{
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a+1);
printf("%d %d", *(a+1), *(ptr-1));
return 0;
}
&a
是if类型int(*)[5]
,因此指针算法将遵循该类型&a+1
指向整个数组后的第一个元素
因此,自然地,
ptr
指向最后一个元素地址之后的一个。因此,通过说*(ptr-1)
可以得到最后一个元素的值,即5
可以将&a看作是指向sizeof(int)的“项”的指针*5所以当你加1的时候,它会把你发送到数组后面的下一个元素,这个元素会被提升20字节的偏移量,所以你做-1,然后把它转换成int,得到数组的最后一个变量
9*sizeof(int)
大的内存块的某种特殊指针int[9]
的数组的指针。这实际上是9*sizeof(int)
bytes大
p
被分配给int[200][9]
数组中第一个元素的点。第一个元素是数组int[9]
,指向这样一个数组的指针是int(*)[9]
int*
不兼容
25
,我认为它与上面显示的特殊语法有一个链接。有人能给我解释一下为什么输出不是21
*(a+1)
,a
衰减为int*
,指针算术+1让我们指向第二个元素
此数组衰减规则的极少数例外之一是运算符的&
地址的操作数。因此,在表达式&a
中,数组a
不会衰减。相反,我们以指向数组int(*)[5]
的指针的形式获取它的地址
&a+1
然后给出指向数组的指针的指针算法。与任何指针算法一样,1
表示指向项目的一个指针的大小,在本例中为sizeof(int[5])
。因此,我们最终指向原始数组中的一个超出边界-这很好,我们可以指向那里,只要我们不去引用指针
由于
(int*)
与int(*)[5]
不兼容,因此(int*)
的演员阵容非常可疑且不好。但是,C允许我们进行任意和可疑的转换,只要我们不通过错误的类型取消引用数据。但是*(ptr-1)
然后转到数组的最后一项并取消引用它。这滥用了C指针/类型系统中的一条特殊规则,该规则允许我们通过不同的指针类型访问(“左值访问”)实际对象,只要存储在该内存位置的内容实际上是用于访问的类型。由于实际存储在物理内存地址上的5
是一个int
,因此它可以工作。以下是指针声明的基本规则:
T *p; // p is a pointer to T
T *ap[N]; // ap is an array of pointers to T
T *fp(); // fp is a function returning a pointer to T
T (*pa)[N]; // pa is a pointer to an array of T
T (*pf)(); // pf is a function returning a pointer to T
T * const p; // p is a const pointer to T - *p is writable, but p is not
const T *p; // p is a non-const pointer to const T - p is writable, but *p is not
T const *p; // same as above
const T * const p; // p is a const pointer to const T - neither p nor *p are writable
T const * const p; // same as above
要阅读一个毛茸茸的声明,请找到最左边的标识符,并按照上面的规则解决问题,将它们递归地应用于任何函数参数。例如,以下是C标准库中信号
函数的声明如何分解:
signal -- signal
signal( ) -- is a function taking
signal( sig ) -- parameter sig
signal(int sig ) -- is an int
signal(int sig, func ) -- parameter func
signal(int sig, (*func) ) -- is a pointer to
signal(int sig, (*func)( )) -- a function taking
signal(int sig, (*func)( )) -- unnamed parameter
signal(int sig, (*func)(int)) -- is an int
signal(int sig, void (*func)(int)) -- returning void
(*signal(int sig, void (*func)(int))) -- returning a pointer to
(*signal(int sig, void (*func)(int)))( ) -- a function taking
(*signal(int sig, void (*func)(int)))( ) -- unnamed parameter
(*signal(int sig, void (*func)(int)))(int) -- is an int
void (*signal(int sig, void (*func)(int)))(int); -- returning void
您可以通过替换构建更复杂的指针类型。例如,如果要声明一个返回数组指针的函数,可以将其构建为
T a [N]; // a is an array of T
|
+---+----+
| |
T (* pa )[N]; // pa is a pointer to an array of T
|
++--+
| |
T (* fpa() )[N]; // fpa is a function returning a pointer to an array of T
T * p ; // p is a pointer to T
|
+----------+
| |
T * fp (); // fp is a function returning pointer to T
|
+---+-----+
| |
T * (* pf ) (); // pf is a pointer to a function returning pointer to T
|
++---+
| |
T * (* apf[N] ) (); // apf is an array of pointers to functions returning pointer to T
如果需要指向返回指向T
的指针的函数的指针数组,则可以将其构建为
T a [N]; // a is an array of T
|
+---+----+
| |
T (* pa )[N]; // pa is a pointer to an array of T
|
++--+
| |
T (* fpa() )[N]; // fpa is a function returning a pointer to an array of T
T * p ; // p is a pointer to T
|
+----------+
| |
T * fp (); // fp is a function returning pointer to T
|
+---+-----+
| |
T * (* pf ) (); // pf is a pointer to a function returning pointer to T
|
++---+
| |
T * (* apf[N] ) (); // apf is an array of pointers to functions returning pointer to T
指针运算是根据对象而不是字节来完成的。如果
p
存储类型为T
的对象的地址,则p+1
生成该类型的下一个对象的地址。如果pa
存储T
的N元素数组的地址,则pa+1
产生T
的下一个N元素数组的地址
在代码中
int main()
{
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a+1);
printf("%d %d", *(a+1), *(ptr-1));
return 0;
}
表达式&a+1
产生a
后面的int
的下一个5元素数组的地址。此地址值被强制转换为int*
,因此它被视为a
最后一个元素之后的第一个int
的地址。图表可能有助于:
int[5] int int *
------ --- -----
+---+ +---+ +---+
a: | | a[0]: | 1 | ptr: | |
+ - + +---+ +---+
| | a[1]: | 2 | |
+ - + +---+ |
| | a[2]: | 3 | |
+ - + +---+ |
| | a[3]: | 4 | |
+ - + +---+ |
| | a[4]: | 5 | |
+---+ +---+ |
a + 1: | | | ? | <--------+
+ - + +---+
| | | ? |
+ - + +---+
... ...
在表达式和声明中,后缀运算符[]
和()
的优先级都高于un
int[5] int int *
------ --- -----
+---+ +---+ +---+
a: | | a[0]: | 1 | ptr: | |
+ - + +---+ +---+
| | a[1]: | 2 | |
+ - + +---+ |
| | a[2]: | 3 | |
+ - + +---+ |
| | a[3]: | 4 | |
+ - + +---+ |
| | a[4]: | 5 | |
+---+ +---+ |
a + 1: | | | ? | <--------+
+ - + +---+
| | | ? |
+ - + +---+
... ...
printf( "indexed value = %d\n", (*pa)[i] );
int (*pa)[N];
Expression Type
---------- ----
pa int (*)[N];
*pa int [N];
(*pa)[i] int
*p == *(p + 0) == p[0]
int mat[200][9];
int (*p)[9] = mat;
(*p)[j] == (*(p + 0))[j] == p[0][j]