理解作为参数传递的语法 *y[ ]
Understanding the syntax *y[ ] passed as parameter
我试图理解 C
代码,但我无意中发现了以下函数定义:
int foo(int n, double *y[]);
我无法理解如何处理和解释 *y[]
。此语法用于多个函数,但处理方式不同。在这个例子中,foo1()
它被用作一个二维数组:
int foo1(int n, double *y[]){
double var0 = 0;
double var1 = 0;
for (i = 0; i < n; i++) {
var1 += y[i][1] ;
var0 += y[i][0] ;
}
// do stuff
return 0;
}
和这里的语法一样,只是把*y[]
当成了数组,不过这里他们用的是指针*
表示法:
int foo2(int n, double *y[]){
double var0 = 0;
for (i = 0; i < n; i++) {
var0 += *y[i] ;
}
// do stuff
return 0;
}
您能否准确解释一下 *y[]
的含义以及为什么它可以如此灵活地用作函数参数?
在函数声明中,数组类型的参数被转换为指针。所以参数 double *y[]
正好等同于 double **y
.
关于 *y[i]
与 y[i][0]
的使用,来自数组索引运算符 []
与指针算术和取消引用的等价性。
表达式 E1[E2]
完全等同于 *((E1)+(E2))
这意味着 y[i][0]
与 *(y[i]+0)
或 *y[i]
相同。
这个参数声明
double *y[]
声明了一个未知大小的数组,其中的元素类型为 double *
。也就是说它是一个 double *
.
类型的指针数组
好像是这个函数的第一个参数
int foo(int n, double *y[]);
即变量n
指定数组中的元素个数
这个表达式
y[i]
给出数组的 i-th
元素。因为数组的元素是一个指针(例如指向具有两个元素的数组的第一个元素的指针),那么这些表达式
y[i][1]
y[i][0]
产生尖元素。
至于这个表达
*y[i]
则等同于表达式
y[i][0]
为了更清楚,我将提供一个演示程序,其中使用 char * []
.
类型的数组而不是 double * []
类型的数组
给你。
#include <stdio.h>
void f( size_t n, char * s[] )
{
for ( size_t i = 0; i < n; i++ )
{
for ( size_t j = 0; s[i][j] != '[=16=]'; j++ )
{
putchar( s[i][j] );
}
putchar( '\n' );
}
}
int main(void)
{
char * s[] =
{
"Hello",
"World"
};
f( sizeof( s ) / sizeof( *s ), s );
return 0;
}
程序输出为
Hello
World
根据foo1
中的用法,y
是指向double
1的2元数组的指针数组,有些东西像这样:
+---+ +---+
y: | | y[0] ------------------------------------------> | | y[0][0]
+---+ +---+ +---+
| | y[1] -------------------------> | | y[1][0] | | y[0][1]
+---+ +---+ +---+
... | | y[1][1]
+---+ +---+ +---+
| | y[n-1] ----> | | y[n-1][0]
+---+ +---+
| | y[n-1][1]
+---+
并且可能声明为
double *x[N]; // or some other name, just picking x for convenience
并使用现有数组的地址进行初始化:
double a[2], b[2], c[2], ...;
double *x[N] = { a, b, c, ... };
或者内存是动态分配的:
for ( size_t i = 0; i < N; i++ )
x[i] = malloc( sizeof *x[i] * 2 );
在调用函数中。
除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化字符类型数组的字符串文字,表达式“T
的 N 元素数组”类型的 将被转换或“衰减”为“指向 T
的指针”类型的表达式,并且表达式的值将为数组第一个元素的地址。
当您使用 x
作为参数调用 foo1
或 foo2
时,如
foo1( N, x );
foo2( N, x );
表达式x
从类型“指向double
的指针的N元素数组”类型转换为类型“指向[=18的指针的指针” =]",第一个元素的地址 (&x[0]
) 是实际传递给函数的地址。
在函数参数声明中,T a[N]
或 T a[]
形式的任何参数都被“调整”为 T *a
- IOW a
始终被视为指针T
,而不是数组。
因此,即使 y
在函数参数列表中被声明为 double *y[]
,它实际上被视为 double **y
。
数组下标操作a[i]
被定义为*(a + i)
——给定一个起始地址,偏移i
个元素(不是字节!)从该地址并取消引用结果。所以 y[i]
等价于 *(y + i)
而 y[i][j]
等价于 *(*(y + i) + j)
。这也意味着表达式 *y
等价于 y[0]
而 *y[i]
等价于 y[i][0]
.
*y == *(y + 0) == y[0]
*y[i] == *(y[i] + 0) == y[i][0]
- 更准确地说,每个
y[i]
指向 double
的 2 元素数组的第一个元素。
我试图理解 C
代码,但我无意中发现了以下函数定义:
int foo(int n, double *y[]);
我无法理解如何处理和解释 *y[]
。此语法用于多个函数,但处理方式不同。在这个例子中,foo1()
它被用作一个二维数组:
int foo1(int n, double *y[]){
double var0 = 0;
double var1 = 0;
for (i = 0; i < n; i++) {
var1 += y[i][1] ;
var0 += y[i][0] ;
}
// do stuff
return 0;
}
和这里的语法一样,只是把*y[]
当成了数组,不过这里他们用的是指针*
表示法:
int foo2(int n, double *y[]){
double var0 = 0;
for (i = 0; i < n; i++) {
var0 += *y[i] ;
}
// do stuff
return 0;
}
您能否准确解释一下 *y[]
的含义以及为什么它可以如此灵活地用作函数参数?
在函数声明中,数组类型的参数被转换为指针。所以参数 double *y[]
正好等同于 double **y
.
关于 *y[i]
与 y[i][0]
的使用,来自数组索引运算符 []
与指针算术和取消引用的等价性。
表达式 E1[E2]
完全等同于 *((E1)+(E2))
这意味着 y[i][0]
与 *(y[i]+0)
或 *y[i]
相同。
这个参数声明
double *y[]
声明了一个未知大小的数组,其中的元素类型为 double *
。也就是说它是一个 double *
.
好像是这个函数的第一个参数
int foo(int n, double *y[]);
即变量n
指定数组中的元素个数
这个表达式
y[i]
给出数组的 i-th
元素。因为数组的元素是一个指针(例如指向具有两个元素的数组的第一个元素的指针),那么这些表达式
y[i][1]
y[i][0]
产生尖元素。
至于这个表达
*y[i]
则等同于表达式
y[i][0]
为了更清楚,我将提供一个演示程序,其中使用 char * []
.
double * []
类型的数组
给你。
#include <stdio.h>
void f( size_t n, char * s[] )
{
for ( size_t i = 0; i < n; i++ )
{
for ( size_t j = 0; s[i][j] != '[=16=]'; j++ )
{
putchar( s[i][j] );
}
putchar( '\n' );
}
}
int main(void)
{
char * s[] =
{
"Hello",
"World"
};
f( sizeof( s ) / sizeof( *s ), s );
return 0;
}
程序输出为
Hello
World
根据foo1
中的用法,y
是指向double
1的2元数组的指针数组,有些东西像这样:
+---+ +---+
y: | | y[0] ------------------------------------------> | | y[0][0]
+---+ +---+ +---+
| | y[1] -------------------------> | | y[1][0] | | y[0][1]
+---+ +---+ +---+
... | | y[1][1]
+---+ +---+ +---+
| | y[n-1] ----> | | y[n-1][0]
+---+ +---+
| | y[n-1][1]
+---+
并且可能声明为
double *x[N]; // or some other name, just picking x for convenience
并使用现有数组的地址进行初始化:
double a[2], b[2], c[2], ...;
double *x[N] = { a, b, c, ... };
或者内存是动态分配的:
for ( size_t i = 0; i < N; i++ )
x[i] = malloc( sizeof *x[i] * 2 );
在调用函数中。
除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化字符类型数组的字符串文字,表达式“T
的 N 元素数组”类型的 将被转换或“衰减”为“指向 T
的指针”类型的表达式,并且表达式的值将为数组第一个元素的地址。
当您使用 x
作为参数调用 foo1
或 foo2
时,如
foo1( N, x );
foo2( N, x );
表达式x
从类型“指向double
的指针的N元素数组”类型转换为类型“指向[=18的指针的指针” =]",第一个元素的地址 (&x[0]
) 是实际传递给函数的地址。
在函数参数声明中,T a[N]
或 T a[]
形式的任何参数都被“调整”为 T *a
- IOW a
始终被视为指针T
,而不是数组。
因此,即使 y
在函数参数列表中被声明为 double *y[]
,它实际上被视为 double **y
。
数组下标操作a[i]
被定义为*(a + i)
——给定一个起始地址,偏移i
个元素(不是字节!)从该地址并取消引用结果。所以 y[i]
等价于 *(y + i)
而 y[i][j]
等价于 *(*(y + i) + j)
。这也意味着表达式 *y
等价于 y[0]
而 *y[i]
等价于 y[i][0]
.
*y == *(y + 0) == y[0]
*y[i] == *(y[i] + 0) == y[i][0]
- 更准确地说,每个
y[i]
指向double
的 2 元素数组的第一个元素。