为什么使用双重间接?或者为什么使用指针指向指针?

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

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

274459 次浏览

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

简单地说,当你想在函数调用之外保留(或保留)内存分配或赋值时,使用**(所以,传递这样的双指针函数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);
}

字符串是使用双指针的一个很好的例子。字符串本身是一个指针,所以任何时候你需要指向一个字符串,你就需要一个双指针。

例如,你可能想要确保当你释放某个东西的内存时,你将指针设置为空。

void safeFree(void** memory) {
if (*memory) {
free(*memory);
*memory = NULL;
}
}

当你调用这个函数时,你会用指针的地址来调用它

void* myMemory = someCrazyFunctionThatAllocatesMemory();
safeFree(&myMemory);

现在myMemory被设置为NULL,任何重用它的尝试都将是非常明显的错误。

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

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)。

如果你想要一个字符列表(一个单词),你可以使用char *word

如果你想要一个单词列表(句子),你可以使用char **sentence

如果你想要一个句子列表(独白),你可以使用char ***monologue

如果你想要一个独白列表(传记),你可以使用char ****biography

如果你想要一个传记列表(生物库),你可以使用char *****biolibrary

如果你想要一个生物库列表(a ??lol),你可以使用char ******lol

……

是的,我知道这些可能不是最好的数据结构


使用例子非常非常非常无聊的哈哈

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


int wordsinsentence(char **x) {
int w = 0;
while (*x) {
w += 1;
x++;
}
return w;
}


int wordsinmono(char ***x) {
int w = 0;
while (*x) {
w += wordsinsentence(*x);
x++;
}
return w;
}


int wordsinbio(char ****x) {
int w = 0;
while (*x) {
w += wordsinmono(*x);
x++;
}
return w;
}


int wordsinlib(char *****x) {
int w = 0;
while (*x) {
w += wordsinbio(*x);
x++;
}
return w;
}


int wordsinlol(char ******x) {
int w = 0;
while (*x) {
w += wordsinlib(*x);
x++;
}
return w;
}


int main(void) {
char *word;
char **sentence;
char ***monologue;
char ****biography;
char *****biolibrary;
char ******lol;


//fill data structure
word = malloc(4 * sizeof *word); // assume it worked
strcpy(word, "foo");


sentence = malloc(4 * sizeof *sentence); // assume it worked
sentence[0] = word;
sentence[1] = word;
sentence[2] = word;
sentence[3] = NULL;


monologue = malloc(4 * sizeof *monologue); // assume it worked
monologue[0] = sentence;
monologue[1] = sentence;
monologue[2] = sentence;
monologue[3] = NULL;


biography = malloc(4 * sizeof *biography); // assume it worked
biography[0] = monologue;
biography[1] = monologue;
biography[2] = monologue;
biography[3] = NULL;


biolibrary = malloc(4 * sizeof *biolibrary); // assume it worked
biolibrary[0] = biography;
biolibrary[1] = biography;
biolibrary[2] = biography;
biolibrary[3] = NULL;


lol = malloc(4 * sizeof *lol); // assume it worked
lol[0] = biolibrary;
lol[1] = biolibrary;
lol[2] = biolibrary;
lol[3] = NULL;


printf("total words in my lol: %d\n", wordsinlol(lol));


free(lol);
free(biolibrary);
free(biography);
free(monologue);
free(sentence);
free(word);
}

输出:

total words in my lol: 243
我经常使用它们的一件事是,当我有一个对象数组,我需要根据不同的字段对它们执行查找(二进制搜索) 我保留原始数组…

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);

您可以根据需要创建任意数量的已排序指针数组,然后对已排序指针数组使用二进制搜索,根据已有的数据访问所需的对象。对象的原始数组可以保持无序,但是每个指针数组将按照它们指定的字段进行排序。

指针的指针也可以作为内存的“句柄”来使用,你想在函数之间传递一个“句柄”来重新定位内存。这基本上意味着函数可以改变句柄变量内的指针所指向的内存,并且使用句柄的每个函数或对象都将正确地指向新重新定位(或分配)的内存。类库喜欢使用“不透明”数据类型来执行此操作,也就是说,你不必担心它们对指向的内存做什么,你只需在类库的函数之间传递“句柄”来对该内存执行一些操作……库函数可以在底层分配和解分配内存,而不必显式地担心内存管理进程或句柄指向何处。

例如:

#include <stdlib.h>


typedef unsigned char** handle_type;


//some data_structure that the library functions would work with
typedef struct
{
int data_a;
int data_b;
int data_c;
} LIB_OBJECT;


handle_type lib_create_handle()
{
//initialize the handle with some memory that points to and array of 10 LIB_OBJECTs
handle_type handle = malloc(sizeof(handle_type));
*handle = malloc(sizeof(LIB_OBJECT) * 10);


return handle;
}


void lib_func_a(handle_type handle) { /*does something with array of LIB_OBJECTs*/ }


void lib_func_b(handle_type handle)
{
//does something that takes input LIB_OBJECTs and makes more of them, so has to
//reallocate memory for the new objects that will be created


//first re-allocate the memory somewhere else with more slots, but don't destroy the
//currently allocated slots
*handle = realloc(*handle, sizeof(LIB_OBJECT) * 20);


//...do some operation on the new memory and return
}


void lib_func_c(handle_type handle) { /*does something else to array of LIB_OBJECTs*/ }


void lib_free_handle(handle_type handle)
{
free(*handle);
free(handle);
}




int main()
{
//create a "handle" to some memory that the library functions can use
handle_type my_handle = lib_create_handle();


//do something with that memory
lib_func_a(my_handle);


//do something else with the handle that will make it point somewhere else
//but that's invisible to us from the standpoint of the calling the function and
//working with the handle
lib_func_b(my_handle);


//do something with new memory chunk, but you don't have to think about the fact
//that the memory has moved under the hood ... it's still pointed to by the "handle"
lib_func_c(my_handle);


//deallocate the handle
lib_free_handle(my_handle);


return 0;
}

希望这能有所帮助,

杰森

1. 基本概念-

当你申报如下:-

< p > 1. Char *ch -(称为字符指针) < br > - ch为单个字符的地址
- (*ch)将解引用字符的值。< / p > < p > 2. Char **ch - < br > '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;
}
< p > 2. 双指针的另一个应用 < br > (这也包括通过引用传递)

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

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使用双指针作为参数来更新字符串的值。

我今天看到了一个非常好的例子,来自这篇博文,如下所述。

假设您有一个链表中节点的结构,可能是这样

typedef struct node
{
struct node * next;
....
} node;

现在你想要实现一个remove_if函数,它接受删除条件rm作为参数之一,并遍历链表:如果一个条目满足条件(类似rm(entry)==true),它的节点将从链表中删除。最后,remove_if返回链表的头(可能与原始头不同)。

你可以写信

for (node * prev = NULL, * curr = head; curr != NULL; )
{
node * const next = curr->next;
if (rm(curr))
{
if (prev)  // the node to be removed is not the head
prev->next = next;
else       // remove the head
head = next;
free(curr);
}
else
prev = curr;
curr = next;
}

作为你的for循环。消息是如果没有双指针,则必须维护prev变量来重新组织指针,并处理两种不同的情况。

但是使用双指针,你实际上可以写

// now head is a double pointer
for (node** curr = head; *curr; )
{
node * entry = *curr;
if (rm(entry))
{
*curr = entry->next;
free(entry);
}
else
curr = &entry->next;
}

你现在不需要prev,因为你可以直接修改prev->next所指向的内容

为了使事情更清楚,让我们稍微跟随一下代码。拆卸过程中:

  1. 如果entry == *head:它将是*head (==*curr) = *head->next——head现在指向新标题节点的指针。你可以通过直接将head的内容更改为一个新指针来做到这一点。
  2. if entry != *head:类似地,*currprev->next所指向的,现在指向entry->next

无论哪种情况,您都可以使用双指针以统一的方式重新组织指针。

添加到亚莎的响应,如果你使用单个指针指向下面的例子(例如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调用的结果时,更改不属于不同作用域中的代码。

今天我在为工作编程时使用了双指针,所以我可以回答为什么我们必须使用它们(这是我第一次实际上必须使用双指针)。我们必须处理缓冲区中包含的帧的实时编码,这些缓冲区是一些结构的成员。在编码器中,我们必须使用指向这些结构之一的指针。问题是我们的指针被更改为指向来自另一个线程的其他结构。为了在编码器中使用当前结构,我必须使用双指针,以便指向在另一个线程中被修改的指针。至少对我们来说,一开始并不明显,我们必须采取这种方法。在这个过程中打印了很多地址:))。

当你处理在应用程序其他地方被更改的指针时,你应该使用双指针。在处理返回和寻址给您的硬件时,您可能还会发现双指针是必须的。

  • 假设你有一个指针。取值为地址。
  • 但现在你想更改地址。
  • 你可以。通过执行pointer1 = pointer2,你给了pointer1一个pointer2的地址。
  • 但是!如果在函数中执行此操作,并且希望结果在函数完成后仍然存在,则需要做一些额外的工作。你需要一个新的pointer3来指向pointer1。将指针3传递给函数。

  • 这里有一个例子。先看看下面的输出,以便理解。

#include <stdio.h>


int main()
{


int c = 1;
int d = 2;
int e = 3;
int * a = &c;
int * b = &d;
int * f = &e;
int ** pp = &a;  // pointer to pointer 'a'


printf("\n a's value: %x \n", a);
printf("\n b's value: %x \n", b);
printf("\n f's value: %x \n", f);
printf("\n can we change a?, lets see \n");
printf("\n a = b \n");
a = b;
printf("\n a's value is now: %x, same as 'b'... it seems we can, but can we do it in a function? lets see... \n", a);
printf("\n cant_change(a, f); \n");
cant_change(a, f);
printf("\n a's value is now: %x, Doh! same as 'b'...  that function tricked us. \n", a);


printf("\n NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' \n");
printf("\n change(pp, f); \n");
change(pp, f);
printf("\n a's value is now: %x, YEAH! same as 'f'...  that function ROCKS!!!. \n", a);
return 0;
}


void cant_change(int * x, int * z){
x = z;
printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", x);
}


void change(int ** x, int * z){
*x = z;
printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", *x);
}

下面是输出:(先读这篇文章)

 a's value: bf94c204


b's value: bf94c208


f's value: bf94c20c


can we change a?, lets see


a = b


a's value is now: bf94c208, same as 'b'... it seems we can, but can we do it in a function? lets see...


cant_change(a, f);


----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see


a's value is now: bf94c208, Doh! same as 'b'...  that function tricked us.


NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a'


change(pp, f);


----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see


a's value is now: bf94c20c, YEAH! same as 'f'...  that function ROCKS!!!.

为什么是双指针?

目标是使用函数改变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);行发生了什么?

  • &main::a的“值”(地址)被复制到参数std::string* Function_1::a中。因此,Function_1::a是指向字符串main::a的指针(即其内存地址)。

  • main::b的“值”(内存中的地址)被复制到参数std::string* Function_1::b中。因此现在内存中有两个这样的地址,都是空指针。在b = a;行,局部变量Function_1::b随后被更改为等于Function_1::a (= &main::a),但变量main::b不变。在调用Function_1之后,main::b仍然是一个空指针。

Function_2(&a, &b);行发生了什么?

  • a变量的处理是相同的:在函数中,Function_2::a是字符串main::a的地址。

  • 但是变量b现在被作为指针传递给指针。&main::b的“值”(指针 main::b地址)被复制到std::string** Function_2::b中。因此在Function_2中,将其解引用为*Function_2::b将访问并修改main::b。因此,行*b = a;实际上是设置main::b(一个地址)等于Function_2::a (= main::a的地址),这是我们想要的。

如果你想用一个函数来修改一个东西,无论是一个对象还是一个地址(指针),你必须传递一个指向那个东西的指针。实际上传入的东西不能被修改(在调用范围内),因为已经创建了一个本地副本。

(一个例外是,如果参数是一个引用,例如std::string& a。但通常这些是const。一般来说,如果你调用f(x),如果x是一个对象,你应该可以假设f 不会修改了x。但是如果x是一个指针,那么你应该假设f const0修改了x所指向的对象。)

简单的例子,你可能已经见过很多次了

int main(int argc, char **argv)

在第二个参数中有它:指向char的指针的指针。

注意,指针表示法(char* c)和数组表示法(char c[])在函数参数中是可以互换的。所以你也可以写char *argv[]。换句话说,char *argv[]char **argv是可以互换的。

上面所代表的实际上是一个字符序列数组(在启动时给予程序的命令行参数)。

有关上述函数签名的更多详细信息,请参见这个答案

比较修改变量值和修改指针的值:

#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);
...
}

有点晚了,但希望这能帮助到一些人。

在C语言中,数组总是在堆栈上分配内存,因此函数不能返回 一个(非静态)数组,因为内存分配在堆栈上 当执行到达当前块的末尾时自动释放。 当你想处理二维数组时,这真的很烦人 (即矩阵),并实现一些可以改变和返回矩阵的函数。 要实现这一点,可以使用指针对指针来实现矩阵 动态分配内存:

/* Initializes a matrix */
double** init_matrix(int num_rows, int num_cols){
// Allocate memory for num_rows float-pointers
double** A = calloc(num_rows, sizeof(double*));
// return NULL if the memory couldn't allocated
if(A == NULL) return NULL;
// For each double-pointer (row) allocate memory for num_cols floats
for(int i = 0; i < num_rows; i++){
A[i] = calloc(num_cols, sizeof(double));
// return NULL if the memory couldn't allocated
// and free the already allocated memory
if(A[i] == NULL){
for(int j = 0; j < i; j++){
free(A[j]);
}
free(A);
return NULL;
}
}
return A;
}

这里有一个例子:

double**       double*           double
-------------       ---------------------------------------------------------
A ------> |   A[0]    | ----> | A[0][0] | A[0][1] | A[0][2] | ........ | A[0][cols-1] |
| --------- |       ---------------------------------------------------------
|   A[1]    | ----> | A[1][0] | A[1][1] | A[1][2] | ........ | A[1][cols-1] |
| --------- |       ---------------------------------------------------------
|     .     |                                    .
|     .     |                                    .
|     .     |                                    .
| --------- |       ---------------------------------------------------------
|   A[i]    | ----> | A[i][0] | A[i][1] | A[i][2] | ........ | A[i][cols-1] |
| --------- |       ---------------------------------------------------------
|     .     |                                    .
|     .     |                                    .
|     .     |                                    .
| --------- |       ---------------------------------------------------------
| A[rows-1] | ----> | A[rows-1][0] | A[rows-1][1] | ... | A[rows-1][cols-1] |
-------------       ---------------------------------------------------------
双指针到双指针A指向a的第一个元素A[0] 内存块本身的元素是双指针。你可以想象一下 双指针作为矩阵的行。这就是为什么 双指针为double类型的num_cols元素分配内存。 此外,A[i]指向第i行,即A[i]指向A[i][0]和 这是第i行内存块的第一个双元素。 最后,您可以访问第i行中的元素 和第j列A[i][j].

下面是一个完整的例子来演示它的用法:

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


/* Initializes a matrix */
double** init_matrix(int num_rows, int num_cols){
// Allocate memory for num_rows double-pointers
double** matrix = calloc(num_rows, sizeof(double*));
// return NULL if the memory couldn't allocated
if(matrix == NULL) return NULL;
// For each double-pointer (row) allocate memory for num_cols
// doubles
for(int i = 0; i < num_rows; i++){
matrix[i] = calloc(num_cols, sizeof(double));
// return NULL if the memory couldn't allocated
// and free the already allocated memory
if(matrix[i] == NULL){
for(int j = 0; j < i; j++){
free(matrix[j]);
}
free(matrix);
return NULL;
}
}
return matrix;
}


/* Fills the matrix with random double-numbers between -1 and 1 */
void randn_fill_matrix(double** matrix, int rows, int cols){
for (int i = 0; i < rows; ++i){
for (int j = 0; j < cols; ++j){
matrix[i][j] = (double) rand()/RAND_MAX*2.0-1.0;
}
}
}




/* Frees the memory allocated by the matrix */
void free_matrix(double** matrix, int rows, int cols){
for(int i = 0; i < rows; i++){
free(matrix[i]);
}
free(matrix);
}


/* Outputs the matrix to the console */
void print_matrix(double** matrix, int rows, int cols){
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
printf(" %- f ", matrix[i][j]);
}
printf("\n");
}
}




int main(){
srand(time(NULL));
int m = 3, n = 3;
double** A = init_matrix(m, n);
randn_fill_matrix(A, m, n);
print_matrix(A, m, n);
free_matrix(A, m, n);
return 0;
}

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

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

引导加载程序API树是一个包含指向其他结构的指针的结构,这些结构具有引导加载程序的函数和数据地址。引导加载程序入口点总是API树的第一个单词。 “< / p >
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);