双指针作为 C 中的参数
Double pointers as arguments in C
我在使用双指针作为 C 中的参数时遇到了一些问题。
据我所知:
当我有一个将指针作为参数的函数时,假设一个名为 functionX(int *y)
的函数
然后当我调用 functionX 时,比方说:functionX(&randomvar)
,其中 randomvar
是一个包含特定值(比方说 5)的整数,然后 C 将创建一个也称为 'randomvar' 的指针其中包含 randomvar
的地址。所以 *randomvar
的输出将是 5.
我的理解正确吗?
如果是这样,那么当函数有双指针时:functionX(int **y)
并通过 functionX(&randomvar)
创建 2 个指针,一个包含 randomvar
的地址,另一个包含地址第一个指针。
我在这里有点难过我不确定它是否正确。
不对,你的理解不正确。 C 不会 "create" 任何你假设的意义上的东西——大多数变量只是内存位置的标签(不仅如此,它们可能 "alias",或标签,CPU 寄存器)——在调用 functionX
的范围内,您的 randomvar
是分配用于存储整数并被解释为整数的内存区域的标签。 &randomvar
一元表达式(运算符&
,单操作数randomvar
)的值是数据的地址。该地址是作为 y
传递给 functionX
的地址,这意味着内存位置(或 CPU 寄存器)被保留并存储 randomvar
的地址(不是值) .
举个例子,假设你的程序声明了一个像 int randomvar;
这样的变量——当执行时,RAM 的一部分——int
通常是 4 个字节——被保留来保存变量randomvar
的值。该地址直到程序在内存中执行时才为人所知,但为了举例,让我们假设地址 0xCAFEBABEDEADBEEF
(8 个字节)是指向 4 个字节以保存整数值的地址。在为变量赋值之前,地址处的值是不确定的——变量的声明只保留 space 来保存值,它不会在地址处写入任何内容,所以在你赋值之前变量的值,你甚至根本不应该使用这个值(大多数 C 编译器会警告你这一点)。
现在,当地址传递给 functionX
时,这意味着对于函数,标签 y
是在某个内存位置保留的 8 个字节,用于存储整数变量的地址。当像 functionX(&randomvar)
这样调用时,y
存储 0xCAFEBABEDEADBEEF
。但是,y
也[通常] 有一个地址——以前的值(randomvar
的地址)必须存储在某处!除非 CPU 寄存器存储值,在这种情况下自然没有 [RAM] 地址。
对于指向像 int * * y
这样的指针的指针,y
标记了一个保留的内存位置,用于存储指向整数变量地址的地址。
hen when I call functionX, let's say by: functionX(&randomvar),where
randomvar is an integer containing a certain value (let's say 5), then
C will create a pointer that is also called 'randomvar' that contains
the addresse of randomvar
函数functionX
中指针的名字是y
因为你自己写的是函数参数的名字functionX(int *y)
.
If so, then when the function has double pointers : functionX(int **y)
and by doing functionX(&randomvar) creates 2 pointers, one that
contains the adresse of randomvar, another that contains the adresse
of the first pointer. If you have a function declared for example like
运算符 & 创建一个指针而不是两个指针。
如果你声明了一个函数,例如
void functionX(int **y);
和一个声明为
的变量
int randomvar = 5;
那么函数的调用就像
functionX( &randomvar );
产生编译错误,因为参数的类型是int *
,而函数声明的参数类型是int **
.
你不能写例如
functionX( &&randomvar );
因为使用第一个运算符 &
创建了一个类型为 int * 的临时对象。并且您不能将运算符 & 应用于临时对象。
调用您可以编写的函数
int *p = &randomvar;
functionX( &p );
在这种情况下,参数类型将是 int **
,因为它是参数类型所要求的。
这是一个演示程序。
#include <stdio.h>
void f( int *p )
{
printf( "The value of p is %p\n"
"the pointed value is %d\n",
( void * )p, *p );
}
void g( int **p )
{
printf( "The value of p is %p\n"
"the pointed value is also a pointer %p\n"
"the pointed value by the dereferenced pointer is %d\n",
( void * )p, ( void * )*p, **p );
}
int main(void)
{
int x = 5;
f( &x );
putchar( '\n' );
int *p = &x;
g( &p );
return 0;
}
其输出可能类似于
The value of p is 0x7ffced55005c
the pointed value is 5
The value of p is 0x7ffced550060
the pointed value is also a pointer 0x7ffced55005c
the pointed value by the dereferenced pointer is 5
以传递变量的地址作为参数调用函数时,没有与传递变量同名的指针。当前面有 &
运算符时,它只是传递某个变量的地址。在被调用函数中,保存此地址的指针可以具有任何有效标识符。
when the function has double pointers : functionX(int **y)
and by doing functionX(&randomvar)
creates 2 pointers, one that contains the adresse of randomvar
, another that contains the adresse of the first pointer.
当函数需要 int**
.
类型的对象时,您不能传递类型为 int*
的 int
对象的地址
一般来说传递双指针,概念和上面说的是一样的。
From what I know so far: when I have a function that takes a pointer
as argument, says a function called functionX(int *y)
then when I
call functionX
, let's say by: functionX(&randomvar)
,where
randomvar
is an integer containing a certain value (let's say 5),
then C will create a pointer that is also called 'randomvar' that
contains the addresse of randomvar
. So the ouput of *randomvar
will be 5.
Is my understanding correct?
没有
您描述的情况大致如下:
void functionX(int *y) {
// ...
}
int main(void) {
int randomvar = 5;
functionX(&randomvar);
}
该代码的 main()
函数中的表达式 &randomvar
的计算结果为该函数的局部变量 randomvar
的地址。该表达式的类型为 int *
,与函数 functionX()
的参数 y
相同,因此非常适合用作该函数的参数。到目前为止一切都很好。
但表达式 &randomvar
仅指定一个 值 ,而不是一个对象。没有为它保留的存储空间,因此它没有地址。它也没有名字,特别是没有命名 'randomvar'。在函数 functionX()
内部,该值(的副本)可以作为 y
访问,表达式 *y
的计算结果将是 5。所提供的代码中没有任何地方是 *randomvar
语义上有效的表达。
If so
不是这样的。
, then when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the adresse of randomvar, another that contains the adresse of the first pointer.
完全没有。 &randomvar
是单个表达式。对其求值会产生 one 值,正如我已经介绍过的,其类型为 int *
。这与 int **
类型的函数参数不匹配。 int **
是指向 int *
的指针。要获得一个,您可以获取类型为 int *
:
的对象(不是值)的地址
void functionY(int **z) {
// ...
}
int main(void) {
int randomvar = 5;
int *varptr = &randomvar;
functionY(&varptr);
}
这样做的话,确实有两个指针,一个是int *
,另一个是int **
,但是前者需要显式声明。
这样想象:
void foo(int a);
void bar(int *b);
void baz(int **c);
// main function
{
int x = 5;
int *p = &x;
foo(x);
bar(p);
baz(&p);
}
// **main** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
ABCD:4000 x 5
ABCD:4008 p ABCD:4000
// **foo** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:2000 a 5
// a new variable is created.
// any changes made on 'a' will not affect 'x' in 'main'
// **bar** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:4000 b ABCD:4000
// a new pointer is created pointing to 'x'
// 'b' points to 'x' and '*b' means 'the value stored in ABCD:4000'
// any changes made on '*b' will affect 'x' in main
// **baz** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:8000 c ABCD:4008
// a new pointer is created pointing to 'p'
// 'c' points to 'p' and '*c' means 'the value stored in ABCD:4008'
// any changes made on '*c' will change the value of 'p' in main
// if '**c = 7' is executed, x will be assigned '7'
// if '*c = ABCD:8000' is executed, p will no longer point to 'x'
如果你愿意,你可以永远保持链接指针。下面是一些演示这一点的代码:
#include<stdio.h>
void foo(int ***A, int **B, int *C) {
printf(" %p A\n %p *A\n %p **A\n %d ***A\n", A, *A, **A, ***A);
printf(" %p B\n %p *B\n %d **B\n", B, *B, **B);
printf(" %p C\n %d *C\n ", C, *C);
}
int main(void) {
int D = 8;
int* C = &D;
int** B = &C;
int*** A = &B;
foo (A,B,C);
printf("%p &D (in main)\n", &D);
return 0;
对于取消引用的指针,这将给出这样的结果,每个“*”都会随着它的继续而消失,所以请注意 **A = *B = C = &D
0x7ffc81b06210 A
0x7ffc81b06218 *A
0x7ffc81b06224 **A
8 ***A
0x7ffc81b06218 B
0x7ffc81b06224 *B
8 **B
0x7ffc81b06224 C
8 *C
0x7ffc81b06224 &D (in main)
最后请注意,调用 foo (&B, &C, &D)
将产生相同的结果。
我在使用双指针作为 C 中的参数时遇到了一些问题。
据我所知:
当我有一个将指针作为参数的函数时,假设一个名为 functionX(int *y)
的函数
然后当我调用 functionX 时,比方说:functionX(&randomvar)
,其中 randomvar
是一个包含特定值(比方说 5)的整数,然后 C 将创建一个也称为 'randomvar' 的指针其中包含 randomvar
的地址。所以 *randomvar
的输出将是 5.
我的理解正确吗?
如果是这样,那么当函数有双指针时:functionX(int **y)
并通过 functionX(&randomvar)
创建 2 个指针,一个包含 randomvar
的地址,另一个包含地址第一个指针。
我在这里有点难过我不确定它是否正确。
不对,你的理解不正确。 C 不会 "create" 任何你假设的意义上的东西——大多数变量只是内存位置的标签(不仅如此,它们可能 "alias",或标签,CPU 寄存器)——在调用 functionX
的范围内,您的 randomvar
是分配用于存储整数并被解释为整数的内存区域的标签。 &randomvar
一元表达式(运算符&
,单操作数randomvar
)的值是数据的地址。该地址是作为 y
传递给 functionX
的地址,这意味着内存位置(或 CPU 寄存器)被保留并存储 randomvar
的地址(不是值) .
举个例子,假设你的程序声明了一个像 int randomvar;
这样的变量——当执行时,RAM 的一部分——int
通常是 4 个字节——被保留来保存变量randomvar
的值。该地址直到程序在内存中执行时才为人所知,但为了举例,让我们假设地址 0xCAFEBABEDEADBEEF
(8 个字节)是指向 4 个字节以保存整数值的地址。在为变量赋值之前,地址处的值是不确定的——变量的声明只保留 space 来保存值,它不会在地址处写入任何内容,所以在你赋值之前变量的值,你甚至根本不应该使用这个值(大多数 C 编译器会警告你这一点)。
现在,当地址传递给 functionX
时,这意味着对于函数,标签 y
是在某个内存位置保留的 8 个字节,用于存储整数变量的地址。当像 functionX(&randomvar)
这样调用时,y
存储 0xCAFEBABEDEADBEEF
。但是,y
也[通常] 有一个地址——以前的值(randomvar
的地址)必须存储在某处!除非 CPU 寄存器存储值,在这种情况下自然没有 [RAM] 地址。
对于指向像 int * * y
这样的指针的指针,y
标记了一个保留的内存位置,用于存储指向整数变量地址的地址。
hen when I call functionX, let's say by: functionX(&randomvar),where randomvar is an integer containing a certain value (let's say 5), then C will create a pointer that is also called 'randomvar' that contains the addresse of randomvar
函数functionX
中指针的名字是y
因为你自己写的是函数参数的名字functionX(int *y)
.
If so, then when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the adresse of randomvar, another that contains the adresse of the first pointer. If you have a function declared for example like
运算符 & 创建一个指针而不是两个指针。
如果你声明了一个函数,例如
void functionX(int **y);
和一个声明为
的变量int randomvar = 5;
那么函数的调用就像
functionX( &randomvar );
产生编译错误,因为参数的类型是int *
,而函数声明的参数类型是int **
.
你不能写例如
functionX( &&randomvar );
因为使用第一个运算符 &
创建了一个类型为 int * 的临时对象。并且您不能将运算符 & 应用于临时对象。
调用您可以编写的函数
int *p = &randomvar;
functionX( &p );
在这种情况下,参数类型将是 int **
,因为它是参数类型所要求的。
这是一个演示程序。
#include <stdio.h>
void f( int *p )
{
printf( "The value of p is %p\n"
"the pointed value is %d\n",
( void * )p, *p );
}
void g( int **p )
{
printf( "The value of p is %p\n"
"the pointed value is also a pointer %p\n"
"the pointed value by the dereferenced pointer is %d\n",
( void * )p, ( void * )*p, **p );
}
int main(void)
{
int x = 5;
f( &x );
putchar( '\n' );
int *p = &x;
g( &p );
return 0;
}
其输出可能类似于
The value of p is 0x7ffced55005c
the pointed value is 5
The value of p is 0x7ffced550060
the pointed value is also a pointer 0x7ffced55005c
the pointed value by the dereferenced pointer is 5
以传递变量的地址作为参数调用函数时,没有与传递变量同名的指针。当前面有 &
运算符时,它只是传递某个变量的地址。在被调用函数中,保存此地址的指针可以具有任何有效标识符。
when the function has double pointers :
functionX(int **y)
and by doingfunctionX(&randomvar)
creates 2 pointers, one that contains the adresse ofrandomvar
, another that contains the adresse of the first pointer.
当函数需要 int**
.
int*
的 int
对象的地址
一般来说传递双指针,概念和上面说的是一样的。
From what I know so far: when I have a function that takes a pointer as argument, says a function called
functionX(int *y)
then when I callfunctionX
, let's say by:functionX(&randomvar)
,whererandomvar
is an integer containing a certain value (let's say 5), then C will create a pointer that is also called 'randomvar' that contains the addresse ofrandomvar
. So the ouput of*randomvar
will be 5.Is my understanding correct?
没有
您描述的情况大致如下:
void functionX(int *y) {
// ...
}
int main(void) {
int randomvar = 5;
functionX(&randomvar);
}
该代码的 main()
函数中的表达式 &randomvar
的计算结果为该函数的局部变量 randomvar
的地址。该表达式的类型为 int *
,与函数 functionX()
的参数 y
相同,因此非常适合用作该函数的参数。到目前为止一切都很好。
但表达式 &randomvar
仅指定一个 值 ,而不是一个对象。没有为它保留的存储空间,因此它没有地址。它也没有名字,特别是没有命名 'randomvar'。在函数 functionX()
内部,该值(的副本)可以作为 y
访问,表达式 *y
的计算结果将是 5。所提供的代码中没有任何地方是 *randomvar
语义上有效的表达。
If so
不是这样的。
, then when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the adresse of randomvar, another that contains the adresse of the first pointer.
完全没有。 &randomvar
是单个表达式。对其求值会产生 one 值,正如我已经介绍过的,其类型为 int *
。这与 int **
类型的函数参数不匹配。 int **
是指向 int *
的指针。要获得一个,您可以获取类型为 int *
:
void functionY(int **z) {
// ...
}
int main(void) {
int randomvar = 5;
int *varptr = &randomvar;
functionY(&varptr);
}
这样做的话,确实有两个指针,一个是int *
,另一个是int **
,但是前者需要显式声明。
这样想象:
void foo(int a);
void bar(int *b);
void baz(int **c);
// main function
{
int x = 5;
int *p = &x;
foo(x);
bar(p);
baz(&p);
}
// **main** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
ABCD:4000 x 5
ABCD:4008 p ABCD:4000
// **foo** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:2000 a 5
// a new variable is created.
// any changes made on 'a' will not affect 'x' in 'main'
// **bar** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:4000 b ABCD:4000
// a new pointer is created pointing to 'x'
// 'b' points to 'x' and '*b' means 'the value stored in ABCD:4000'
// any changes made on '*b' will affect 'x' in main
// **baz** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:8000 c ABCD:4008
// a new pointer is created pointing to 'p'
// 'c' points to 'p' and '*c' means 'the value stored in ABCD:4008'
// any changes made on '*c' will change the value of 'p' in main
// if '**c = 7' is executed, x will be assigned '7'
// if '*c = ABCD:8000' is executed, p will no longer point to 'x'
如果你愿意,你可以永远保持链接指针。下面是一些演示这一点的代码:
#include<stdio.h>
void foo(int ***A, int **B, int *C) {
printf(" %p A\n %p *A\n %p **A\n %d ***A\n", A, *A, **A, ***A);
printf(" %p B\n %p *B\n %d **B\n", B, *B, **B);
printf(" %p C\n %d *C\n ", C, *C);
}
int main(void) {
int D = 8;
int* C = &D;
int** B = &C;
int*** A = &B;
foo (A,B,C);
printf("%p &D (in main)\n", &D);
return 0;
对于取消引用的指针,这将给出这样的结果,每个“*”都会随着它的继续而消失,所以请注意 **A = *B = C = &D
0x7ffc81b06210 A
0x7ffc81b06218 *A
0x7ffc81b06224 **A
8 ***A
0x7ffc81b06218 B
0x7ffc81b06224 *B
8 **B
0x7ffc81b06224 C
8 *C
0x7ffc81b06224 &D (in main)
最后请注意,调用 foo (&B, &C, &D)
将产生相同的结果。