在C语言中什么时候应该使用双重间接?谁能举个例子解释一下吗?
我所知道的是双间接是指向指针的指针。为什么我需要指向指针的指针?
在C语言中什么时候应该使用双重间接?谁能举个例子解释一下吗?
我所知道的是双间接是指向指针的指针。为什么我需要指向指针的指针?
当前回答
例如,你可能想要确保当你释放某个东西的内存时,你将指针设置为空。
void safeFree(void** memory) {
if (*memory) {
free(*memory);
*memory = NULL;
}
}
当你调用这个函数时,你会用指针的地址来调用它
void* myMemory = someCrazyFunctionThatAllocatesMemory();
safeFree(&myMemory);
现在myMemory被设置为NULL,任何重用它的尝试都将是非常明显的错误。
其他回答
我经常使用它们的一件事是,当我有一个对象数组,我需要根据不同的字段对它们执行查找(二进制搜索)。 我保留原始数组…
int num_objects;
OBJECT *original_array = malloc(sizeof(OBJECT)*num_objects);
然后创建一个指向对象的排序指针数组。
int compare_object_by_name( const void *v1, const void *v2 ) {
OBJECT *o1 = *(OBJECT **)v1;
OBJECT *o2 = *(OBJECT **)v2;
return (strcmp(o1->name, o2->name);
}
OBJECT **object_ptrs_by_name = malloc(sizeof(OBJECT *)*num_objects);
int i = 0;
for( ; i<num_objects; i++)
object_ptrs_by_name[i] = original_array+i;
qsort(object_ptrs_by_name, num_objects, sizeof(OBJECT *), compare_object_by_name);
您可以根据需要创建任意数量的已排序指针数组,然后对已排序指针数组使用二进制搜索,根据已有的数据访问所需的对象。对象的原始数组可以保持无序,但是每个指针数组将按照它们指定的字段进行排序。
一个原因是你想要改变传递给函数的作为函数参数的指针的值,要做到这一点,你需要指针指向指针。
简单地说,当你想在函数调用之外保留(或保留)内存分配或分配的变化时,使用**。(因此,传递带有双指针arg的函数。)
这可能不是一个很好的例子,但会告诉你基本的用法:
#include <stdio.h>
#include <stdlib.h>
void allocate(int **p)
{
*p = (int *)malloc(sizeof(int));
}
int main()
{
int *p = NULL;
allocate(&p);
*p = 42;
printf("%d\n", *p);
free(p);
}
为什么是双指针?
目标是使用函数改变studentA所指向的对象。
#include <stdio.h>
#include <stdlib.h>
typedef struct Person{
char * name;
} Person;
/**
* we need a ponter to a pointer, example: &studentA
*/
void change(Person ** x, Person * y){
*x = y; // since x is a pointer to a pointer, we access its value: a pointer to a Person struct.
}
void dontChange(Person * x, Person * y){
x = y;
}
int main()
{
Person * studentA = (Person *)malloc(sizeof(Person));
studentA->name = "brian";
Person * studentB = (Person *)malloc(sizeof(Person));
studentB->name = "erich";
/**
* we could have done the job as simple as this!
* but we need more work if we want to use a function to do the job!
*/
// studentA = studentB;
printf("1. studentA = %s (not changed)\n", studentA->name);
dontChange(studentA, studentB);
printf("2. studentA = %s (not changed)\n", studentA->name);
change(&studentA, studentB);
printf("3. studentA = %s (changed!)\n", studentA->name);
return 0;
}
/**
* OUTPUT:
* 1. studentA = brian (not changed)
* 2. studentA = brian (not changed)
* 3. studentA = erich (changed!)
*/
下面是一个非常简单的c++示例,说明如果要使用函数将指针设置为指向对象,则需要一个指针指向指针。否则,指针将继续返回null。
(一个c++的答案,但我相信在C中也是一样的)
(同样,供参考:谷歌("pass by value c++") = "默认情况下,c++中的参数是按值传递的。当实参按值传递时,实参的值被复制到函数的形参中。”)
我们想让指针b等于字符串a。
#include <iostream>
#include <string>
void Function_1(std::string* a, std::string* b) {
b = a;
std::cout << (b == nullptr); // False
}
void Function_2(std::string* a, std::string** b) {
*b = a;
std::cout << (b == nullptr); // False
}
int main() {
std::string a("Hello!");
std::string* b(nullptr);
std::cout << (b == nullptr); // True
Function_1(&a, b);
std::cout << (b == nullptr); // True
Function_2(&a, &b);
std::cout << (b == nullptr); // False
}
// Output: 10100
在Function_1(&a, b);这条线上会发生什么?
The "value" of &main::a (an address) is copied into the parameter std::string* Function_1::a. Therefore Function_1::a is a pointer to (i.e. the memory address of) the string main::a. The "value" of main::b (an address in memory) is copied into the parameter std::string* Function_1::b. Therefore there are now 2 of these addresses in memory, both null pointers. At the line b = a;, the local variable Function_1::b is then changed to equal Function_1::a (= &main::a), but the variable main::b is unchanged. After the call to Function_1, main::b is still a null pointer.
在函数_2(&a, &b);这一行发生了什么?
The treatment of the a variable is the same: within the function, Function_2::a is the address of the string main::a. But the variable b is now being passed as a pointer to a pointer. The "value" of &main::b (the address of the pointer main::b) is copied into std::string** Function_2::b. Therefore within Function_2, dereferencing this as *Function_2::b will access and modify main::b . So the line *b = a; is actually setting main::b (an address) equal to Function_2::a (= address of main::a) which is what we want.
如果你想用一个函数来修改一个东西,无论是一个对象还是一个地址(指针),你必须传递一个指向那个东西的指针。您实际传入的内容不能被修改(在调用范围内),因为创建了本地副本。
(一个例外是如果形参是一个引用,例如std::string& a.但通常这些是const。一般来说,如果你调用f(x),如果x是一个对象,你应该能够假设f不会修改x。但如果x是一个指针,那么你应该假设f可能修改x指向的对象。)
比较变量的修改值和指针的修改值:
#include <stdio.h>
#include <stdlib.h>
void changeA(int (*a))
{
(*a) = 10;
}
void changeP(int *(*P))
{
(*P) = malloc(sizeof((*P)));
}
int main(void)
{
int A = 0;
printf("orig. A = %d\n", A);
changeA(&A);
printf("modi. A = %d\n", A);
/*************************/
int *P = NULL;
printf("orig. P = %p\n", P);
changeP(&P);
printf("modi. P = %p\n", P);
free(P);
return EXIT_SUCCESS;
}
这帮助我避免指针被调用函数修改时返回指针的值(用于单链表)。
古老的(坏的):
int *func(int *P)
{
...
return P;
}
int main(void)
{
int *pointer;
pointer = func(pointer);
...
}
新(更好的):
void func(int **pointer)
{
...
}
int main(void)
{
int *pointer;
func(&pointer);
...
}