我试图理解这段代码中的指针是如何工作的:
void allocateArray( int **arr, size_t size, int value )
{
*arr = malloc( size * sizeof( int ));
if ( *arr != NULL )
for ( size_t i = 0; i < size; ++i )
*( *arr + i ) = value;
}
int main( void )
{
int *vector = NULL;
allocateArray(&vector,5,45);
free( vector );
return 0;
}
如果我声明了一个指向int(* vector)的指针,那么如何传递它的地址使它成为指向int(** arr)的指针?我的意思是,它是如何工作的,现在内存中的向量地址将被覆盖!
答案 0 :(得分:3)
C按值传递函数参数。因此,要允许函数修改调用者提供的变量,必须传递指向它的指针。并且该函数必须取消引用指针才能进行修改。
void foo_1 (int a) {
a += 1; /* caller will not see any change to a */
}
void foo_2 (int *ap) {
*ap += 1; /* caller will see value has changed */
}
int a = 0;
foo_1(a); /* a is still 0 after return */
foo_2(&a); /* a becomes 1 after return */
&
运算符生成一个值,表示应用它的对象的地址,结果类型是&#34;指向(对象的类型)&#34;的指针。在上面的示例中,&a
的结果是&#34;指向int
&#34;的指针。
如果变量是指针类型,则没有什么根本不同。
void foo_1 (int *a) {
a = malloc(sizeof(int)); /* caller will not see any change to a */
}
void foo_2 (int **ap) {
*ap = malloc(sizeof(int)); /* caller will see value has changed */
}
int *a = 0;
foo_1(a); /* a is still 0 after return */
foo_2(&a); /* a becomes initialized to memory allocated by malloc */
在上面的示例中,由于a
是指向int
的指针,因此&a
的类型是&#34;指向int
&#34;的指针。
指针是一个用于指代对象地址的术语。对象的地址是表示对象驻留在内存中的位置的值。知道该地址意味着可以读取和修改对象。 指针变量是一个可以存储对象地址的变量。
通常,变量的名称用于表示对象。通过对象,我只是指变量使用的内存,它的语义表示,又称它的类型(通常,术语变量和对象可以互换使用,但对我来说,不同之处在于变量有一个名称)。通过名称读取和修改对象。获取指向对象的指针的一种方法是将一元&
运算符应用于变量的名称。保存该地址的指针变量因此是指向该对象的指针。现在,通过使用一元*
运算符取消引用指针,可以通过指针读取和修改同一个对象。
int a = 0;
int *ap = &a;
a += 1; /* a now has the value 1 */
*ap += 1; /* a now has the value 2 */
动态创建的对象(即通过malloc()
)没有名称。但是,malloc()
返回一个指针,通过该指针可以读取和修改对象。
int *ap = 0; /* ap initialized to NULL */
ap = malloc(sizeof(int)); /* ap points to dynamically allocated int */
*ap = 0; /* int pointed to by ap now holds value 0 */
*ap += 1; /* int pointed to by ap now holds value 1 */
您的allocateArray()
函数将指针的这两种用法组合成一个函数。
int *vector = NULL; /* vector is pointer to int variable initialized to NULL */
allocateArray(&vector,5,45); /* the address of vector is passed to allocateArray */
由于vector的地址传递给allocateArray()
,因此该函数现在可以通过引用它收到的指针值来修改名为vector
的对象。指针值在arr
参数中接收:
void allocateArray( int **arr, size_t size, int value )
并且,通过取消引用arr
,它正在使用vector
返回的值更新malloc()
对象:
*arr = malloc( size * sizeof( int ));
如果分配,内存初始化以及vector
变量的更新发生在多个步骤中,那么函数可能会更清楚。
void allocateArray( int **arr, size_t size, int value )
{
int *vec = malloc( size * sizeof( int )); /* vec points to size contiguous int */
if ( vec != NULL )
for ( size_t i = 0; i < size; ++i )
vec[i] = value; /* vec[i] set to value */
*arr = vec; /* return vec into first parameter */
}
答案 1 :(得分:1)
某些背景:
C中的参数始终按值传递。例如,考虑代码
void some_func(int i) { i = i + 2; printf("i = %d\n", i); }
void main_func() {
int n = 5;
some_func(n);
printf("n = %d\n", n);
}
<强>输出:强>
i = 7
n = 5
main函数将值5传递给some_func
,i
会在n
中更改自己的本地副本,但不能在调用函数中更改void new_func(int *i) { *i = *i + 2; printf("*i = %d\n", *i); }
void main_func() {
int n = 5;
some_func(&n);
printf(" n = %d\n", n);
}
。
现在,假设您要编写一个 更改调用者值的函数。您可以通过传递要更改的变量的地址来执行此操作:
*i = 7
n = 7
<强>输出:强>
new_func
“技巧”是foo
不会改变其参数的值;它改变了一些其他值 - 其参数指向的变量。所以规则是:
如果您希望函数更改变量,请传递该变量的地址。
换句话说,如果您希望功能更改foo
,则将指针传递给main
。
应用于您的代码:
vector
函数声明了一个没有分配内存的指针NULL
。它的值是allocateArray()
。它调用vector
来分配内存并将其分配给vector
。但这意味着它必须将NULL
的值从vector
更改为新分配的内存的地址。遵循与上述相同的规则,为了更改allocateArray()
,您需要将其地址传递给vector
。由于vector
是指向int的类型,因此它的地址是指向指针指向int的类型。
要明确:您没有更改allocateArray()
的类型;你只是通过了它的地址。因此,在arr
中,int **
的类型为*arr
,而int *
的类型为*arr
。从语法上讲,您完全按照vector
使用{{1}}。
答案 2 :(得分:0)
因此vector是一个指向int的指针,因此vector的地址是指向int的指针(&amp; vector相当于int **)。 vector = * arr,not&amp; vector = * arr。因此vector获取对malloc的调用返回的地址,而不是vector的地址。我认为混淆是在向量的地址和向量指向的地址之间。
答案 3 :(得分:0)
在函数main()
内,vector
是堆栈上的单个变量(可能是4个字节)。 那4个字节的第一个地址是&vector
。当你调用allocateArray()
时,你会在堆上分配一块内存。 那些字节的地址必须存储在某处。该函数将4字节地址存储在传递给它的存储器地址中,即堆栈上分配的字节。
因此,当我们返回main()
时,变量vector
现在指向已分配块的开头。因为它被声明为int的指针,所以该内存将作为一个int数组进行访问。
内存地址就像任何其他数字一样。您在C中为其分配的“类型”只是告诉编译器您打算如何处理该地址的内存。将vector
声明为int *
只会告诉编译器在看到int
时从内存中获取*vector
。用于存储变量值的内存本身就是堆栈,就像它是一个普通的int一样,并且该内存与它所指向的内存无关。
我们需要获取堆栈变量的地址,否则allocateArray()
将无法影响变量vector
的值,这在其范围内未定义,因此我们只需要告诉它在哪里看。
实现这个的更好方法可能是删除allocateArray()
的第一个参数,并让它返回已分配块的地址。然后,我们只需将vector
分配给main()
中的返回值即可。
答案 4 :(得分:0)
int main( void )
{
int *vector = NULL;
allocateArray(&vector,5,45);
free( vector );
return 0;
}
正如您在main函数中看到的,当语句allocateArray(&vector,5,45);
执行时,
5元素数组的内存地址将传递给向量变量;但是,如果使用allocateArray(vector,5,45);
(假设已更正已修改),则内存地址不会传递给矢量变量,因为函数allocateArray(vector,5,45)现在只是将vector的值传递给功能