在C语言中什么时候应该使用双重间接?谁能举个例子解释一下吗?

我所知道的是双间接是指向指针的指针。为什么我需要指向指针的指针?


当前回答

例如,如果您想随机访问不连续的数据。

p -> [p0, p1, p2, ...]  
p0 -> data1
p1 -> data2

——用C

T ** p = (T **) malloc(sizeof(T*) * n);
p[0] = (T*) malloc(sizeof(T));
p[1] = (T*) malloc(sizeof(T));

存储一个指针p,它指向一个指针数组。每个指针指向一段数据。

如果sizeof(T)很大,则可能无法分配sizeof(T) * n字节的连续块(即使用malloc)。

其他回答

为什么是双指针?

目标是使用函数改变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!)
 */

1. 基本概念-

当你申报如下:-

1. Char *ch -(称为字符指针) - ch为单个字符的地址。 - (*ch)将解引用字符的值。

2. Char **ch - 'ch'包含字符指针数组的地址。(如1) '*ch'包含单个字符的地址。(注意它与1不同,因为声明不同)。 (**ch)将解引用到字符的确切值..

添加更多指针将扩展数据类型的维度,从字符扩展到字符串,再扩展到字符串数组,等等……你可以把它和一维,二维,三维矩阵联系起来。

指针的用法取决于你如何声明它。

这是一个简单的代码..

int main()
{
    char **p;
    p = (char **)malloc(100);
    p[0] = (char *)"Apple";      // or write *p, points to location of 'A'
    p[1] = (char *)"Banana";     // or write *(p+1), points to location of 'B'

    cout << *p << endl;          //Prints the first pointer location until it finds '\0'
    cout << **p << endl;         //Prints the exact character which is being pointed
    *p++;                        //Increments for the next string
    cout << *p;
}

2. 双指针的另一个应用 (这也包括引用传递)

假设您想从函数中更新一个字符。如果你尝试以下方法:-

void func(char ch)
{
    ch = 'B';
}

int main()
{
    char ptr;
    ptr = 'A';
    printf("%c", ptr);

    func(ptr);
    printf("%c\n", ptr);
}

输出为AA。这是行不通的,因为您已经将“按值传递”传递给了函数。

正确的做法是-

void func( char *ptr)        //Passed by Reference
{
    *ptr = 'B';
}

int main()
{
    char *ptr;
    ptr = (char *)malloc(sizeof(char) * 1);
    *ptr = 'A';
    printf("%c\n", *ptr);

    func(ptr);
    printf("%c\n", *ptr);
}

现在扩展这个要求,更新字符串而不是字符。 为此,需要将函数中的形参作为双指针接收。

void func(char **str)
{
    strcpy(str, "Second");
}

int main()
{
    char **str;
    // printf("%d\n", sizeof(char));
    *str = (char **)malloc(sizeof(char) * 10);          //Can hold 10 character pointers
    int i = 0;
    for(i=0;i<10;i++)
    {
        str = (char *)malloc(sizeof(char) * 1);         //Each pointer can point to a memory of 1 character.
    }

    strcpy(str, "First");
    printf("%s\n", str);
    func(str);
    printf("%s\n", str);
}

在本例中,method使用双指针作为参数来更新字符串的值。

添加到Asha的响应,如果你使用单个指针指向下面的例子(例如alloc1()),你将失去对函数内部分配的内存的引用。

#include <stdio.h>
#include <stdlib.h>

void alloc2(int** p) {
    *p = (int*)malloc(sizeof(int));
    **p = 10;
}

void alloc1(int* p) {
    p = (int*)malloc(sizeof(int));
    *p = 10;
}

int main(){
    int *p = NULL;
    alloc1(p);
    //printf("%d ",*p);//undefined
    alloc2(&p);
    printf("%d ",*p);//will print 10
    free(p);
    return 0;
}

发生这种情况的原因是在alloc1中,指针是按值传入的。因此,当它被重新分配给alloc1内部的malloc调用的结果时,更改不属于不同作用域中的代码。

这里的大多数答案或多或少都与应用程序编程有关。下面是一个嵌入式系统编程的例子。例如,以下是NXP Kinetis KL13系列微控制器参考手册的摘录,此代码片段用于从固件中运行驻留在ROM中的引导加载程序:

" 为了获得入口点的地址,用户应用程序读取包含引导加载程序API树指针的单词,该指针位于引导加载程序向量表的0x1C偏移量处。向量表被放置在引导加载器地址范围的底部,ROM的地址范围是0x1C00_0000。因此,API树指针位于地址0x1C00_001C。

引导加载程序API树是一个包含指向其他结构的指针的结构,这些结构具有引导加载程序的函数和数据地址。引导加载程序入口点总是API树的第一个单词。 "

uint32_t runBootloaderAddress;
void (*runBootloader)(void * arg);
// Read the function address from the ROM API tree.
runBootloaderAddress = **(uint32_t **)(0x1c00001c);
runBootloader = (void (*)(void * arg))runBootloaderAddress;
// Start the bootloader.
runBootloader(NULL);

一个原因是你想要改变传递给函数的作为函数参数的指针的值,要做到这一点,你需要指针指向指针。

简单地说,当你想在函数调用之外保留(或保留)内存分配或分配的变化时,使用**。(因此,传递带有双指针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);
}