user-0 提问: void InitializeList(List * plist)没有必要用指针的指针呀

回复:
user: user-1
content: 引用 3 楼 落笔、守护爱 的回复:[quote=引用 2 楼 自信男孩的回复:]你的这个函数实现呢？不给实现怎么知道要不要用？ void InitializeList(List * plist) {     *plist = NULL; }[/quote] 那确实是需要二重指针，因为用一重指针和swap(int, int)交换两个变量的原因是一样的。

user: user-2
content: void func(int * ptr) { 	if (ptr != nullptr) 		delete ptr; 	ptr = nullptr; } void func1(int** ptr) { 	if (*ptr != nullptr) 		delete *ptr; 	*ptr = nullptr; } int main() { 	int *x = new int(10); 	func(x); 	cout << hex; 	cout << x << endl; 	x = new int(20); 	func1(&x); 	cout << x << endl;   } 试一下上边代码，自己体会一下其中的区别。

user: user-2
content: 引用 9 楼 落笔、守护爱的回复:[quote=引用 7 楼 真相重于对错的回复:] 一个函数，参数是指针，在函数中修改这个指针的地址，函数返回后，那个指针依然是传入时的地址，只有参数是二级指针，修改参数的地址，函数返回后参数的地址才可能发生改变。 您好，这个函数不需要修改指针的地址呀[/quote] /* 函数原型 */ /* 操作：初始化一个列表           */ /* 操作前：plist指向一个列表      */ /* 操作后：该列表被初始化为空列表 */ void InitializeList(List * plist

user: user-3
content: 之前的排版有点问题  /*下面两个函数表达的意思一样吗？*/ void listadd(List list, Node *pnode) {     list->next = pnode; } void listadd(Node *plist, Node *pnode) {     plist->next = pnode; } /*其实是一样的，第一个函数的参数list, 其实说到底是Node 指针 因为typedef Node * List; 只是 第一个函数让你看起来觉得， 更像是往链表（List嘛，翻译过来就是链表)加节点（Node） 第二个函数呢？ 什么？往节点加节点，你摇脑袋说，不可理解 这就是typdef Node *List; 让你觉得舒服的同时，使你迷失了 对指针，或者链表节点本质的理解。 */  /*最后回到链表，链表其实每个节点都是等价的， 打个比方，5个人组成一个小队，排成一排， 为了带点传奇色彩，想象这个小队是FBI特工组织，代号猎鹰 大家都用右手抓住相邻的人的肩膀，这样就形成一个简单的链表， 链表尾巴的人右手抓着空气（NULL）， 这个链表有5个人 但是要表示链表为空怎么办？ 我这里稍稍改下定义 */ typedef struct Node_t{     char name[16];     Node *next; }Node;  //两种方案：区别在于，你怎么定义头节点（链表标记）  /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.空即是空，（注意不是色即是空） 没人表示空，Node *plist_head = NULL; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ bool is_empty(Node *p){     if(p == NULL)         return true;     else         return fals; } Node *plist_head = NULL; is_empty(plist_head);//?? ? : yes,空的 /* 但是这样带来一个麻烦，你要往里面加人 必须先创建这个链表头 */     /*-----------------------------     //1.1 (空即是空的 加入组织方法1)     *------------------------------*/     list_add(Node **phead, Node *pnode){  //这里用**，这样出来之后phead就改变了           if(*phead == NULL){             *p = (Node *)malloc(sizof(Node));   //who am I? 我是谁？？??         }         *p->next = pnode;     }     Node *plist_head = NULL; //list头，老大     Node p1 = {"张三"， NULL};     //假设你很莽，直接往头里加     list_add(&plist_head, &p1);     //---ok,现在组织里有两个人了，p是一个人，无名大哥，不知道他是谁，第一个小弟是张三     //---感觉有点怪怪的,一个登记在册的人员：张三，可是突然多出来的大哥蒙着面，不知道是谁      /*------------------------------------     //1.2(空即是空, 加入组织方法2, 先入为主)     *-----------------------------------*/     list_add(Node **phead, Node *pnode){  //这里用**，这样出来之后phead就改变了           if(*phead == NULL){             *phead = pnode;// 嘻嘻，先来的就是大哥, 假设这个phead是老大住的房子, 现在pnode住进去了             pnode->next = NULL;             return; //强调一下，可以出去了，这个组织已经不一样了，空组织迎来老大         }         else{             Node *old_first = *phead->next;             *p->next = pnode;             pnode->next = old_first;         }     }     Node *plist_head = NULL;     Node p1 = {"张三"， NULL};     list_add(&plist_head, &p1);      //---OK,现在组织里有一个人了，没错，张三就是老大了（苍天已死，黄天当立，张角可以继续招小弟了）     //---这样很OK，解决了组织口号问题，空即是空，又不会无故增加一个无民氏进来     //组织很有激情，新来的即可做大哥     //等一下！，我要执行初始化怎么办？，     //--要什么初始化，Node *plist_head = NULL; 完事了  /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //方案2 (色即是空，) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/      //2.1 现造个假人？还是弄个真人，抹去他的名字和记忆，让他当个工具人,随你怎么想了     //反正组织的缔造者认为，虚无缥缈的空不可捉摸，还是有个具体的东西代表一下比较实际     //明明是一个实体Node，却偏偏指鹿为马，Node，你不存在，你是空链表      bool is_empty(Node *plist){ //只是名字上命名为plist，你要知道，他总是Node *         /*         if(p == NULL)   //???，不带这么玩的，p必须是实体         */         if(p->next == NULL) //没有小弟             return true;         else             return false;     }      //来了来了，我的初始化函数终于派上用场,,终于切入楼主正题，初始化     void initialize_list(Node* plist)     {         // plist->name = ????; //无所谓啦，关键看你有没有带小弟         plist->next = NULL; //废了小弟先，     }     //      /*这里用*phead了，因为加人之前，必须要有个工具人头领存在，     不存在空即是空的问题, 可以对比之前1.2的实现*/     /*---------------------------------------     //2.2 加入组织的方法     *--------------------------------------*/     list_add(Node *phead, Node *pnode){           /*这个版本比起1.1的实现如何？         两个字舒服，而且没有使用双重指针，原来苦口婆心         虽然给我塞了个色即是空的概念（第一个节点明明存在，我却要说他是空链表）         但是没有双重指针就是爽，是不是？ 妈妈再也不用担心我的学习了~~~~~~~         */         Node *old_first = phead->next;         *p->next = pnode;         pnode->next = old_first;     }      Node head;  //既然是假人，英雄不问出身姓名，不要名字也罢, 也不知道他带了小弟没有（next）     initialize_list(&head); //强行把next置成NULL，     is_empty(&head);//yes!!, head明明看起来像个正常人，大活人，却要说他是空，这就是当老大的代价吧，色即是空     Node *p1 = (Node*)malloc(sizeof(Node));     strcpy(p1->name, "007");     Node *p2 = (Node*)malloc(sizeof(Node));     strcpy(p2->name, "谍影重重");     list_add(&head, p1);   //链表要领，无论何时，都要记得头是谁     list_add(&head, p2);      /*题外话, 这时候还能直接初始化链表吗？*/     initialize_list(&head); //???     /*想象下电影情节，这像是特工小组档案被直接删除，人还在，没有正常遣散，     也没给遣散费，后果是什么？, 幕后负责人会被清算，对就是你这个写代码的人，哈~     -正确的方式是遍历链表，把他们都free()掉，释放内存，     -安抚一下，现在是和平时期不需要特工了，（其实是没钱发工资了）*/      /*但愿你有这个耐心慢慢去体会, 并最终学会指针，链表？ 节点？     他们不再那么难以捉摸*/ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~The End~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

user: user-3
content: 谢邀 请注意 typedef Node * List;  // 指向Node(struct node)类型的指针， List已经是指针类型（Node指针） 你再定义，以下函数时 void InitializeList(List * plist); plist已经是指向指针的指针了，相当于Node **plist；  其实不建议定义这样的东西typedef Node * List;  这个并不会给你理解指针带来太多的便利 只是教材在好心玩把戏却让你迷失，他让你误以为List是链表，Node *则是节点。 是这个定义产生了这么神奇的效果吗？  施主，“空即是空，色即是空”，小僧备上一些代码，望施主能脱离苦海 =================以下代码不定义typedef Node *LIst；这种东西----  /*下面两个函数表达的意思一样吗？*/ void listadd(List list, Node *pnode) {     list->next = pnode; } void listadd(Node *plist, Node *pnode) {     plist->next = pnode; } /*其实是一样的，第一个函数的参数list, 其实说到底是Node 指针 因为typedef Node * List; 只是 第一个函数让你看起来觉得， 更像是往链表（List嘛，翻译过来就是链表)加节点（Node） 第二个函数呢？ 什么？往节点加节点，你摇脑袋说，不可理解 这就是typdef Node *List; 让你觉得舒服的同时，使你迷失了 对指针，或者链表节点本质的理解。 */  /*最后回到链表，链表其实每个节点都是等价的， 打个比方，5个人组成一个小队，排成一排， 为了带点传奇色彩，想象这个小队是FBI特工组织，代号猎鹰 大家都用右手抓住相邻的人的肩膀，这样就形成一个简单的链表， 链表尾巴的人右手抓着空气（NULL）， 这个链表有5个人 但是要表示链表为空怎么办？ 我这里稍稍改下定义 */ typedef struct Node_t{     char name[16];     Node *next; }Node;  //两种方案： /* 1.空即是空，（注意不是色即是空） 没人表示空， */ bool is_empty(Node *p){     if(p == NULL)         return true;     else         return fals; } Node *p = NULL; is_empty(p);//?? ? : yes,空的 /* 但是这样带来一个麻烦，你要往里面加人 必须先创建这个链表头 */ //1.1 (空即是空的 加入组织方法1)     list_add(Node **phead, Node *pnode){  //这里用**，这样出来之后phead就改变了           if(*phead == NULL){             *p = (Node *)malloc(sizof(Node));   //who am I? 我是谁？？??         }         *p->next = pnode;     }     Node *plist_head = NULL; //list头，老大     Node p1 = {"张三"， NULL};     //假设你很莽，直接往头里加     list_add(&plist_head, &p1);     //---ok,现在组织里有两个人了，p是一个人，无名大哥，不知道他是谁，第一个小弟是张三     //---感觉有点怪怪的,一个登记在册的人员：张三，可是突然多出来的大哥蒙着面，不知道是谁     1.2(空即是空, 加入组织方法2, 先入为主)     list_add(Node **phead, Node *pnode){  //这里用**，这样出来之后phead就改变了           if(*phead == NULL){             *phead = pnode;// 嘻嘻，先来的就是大哥, 假设这个phead是老大住的房子, 现在pnode住进去了             pnode->next = NULL;             return; //强调一下，可以出去了，这个组织已经不一样了，空组织迎来老大         }         else{             Node *old_first = *phead->next;             *p->next = pnode;             pnode->next = old_first;         }     }     Node *plist_head = NULL;     Node p1 = {"张三"， NULL};     list_add(&plist_head, &p1);      //---OK,现在组织里有一个人了，没错，张三就是老大了（苍天已死，黄天当立，张角可以继续招小弟了）     //---这样很OK，解决了组织口号问题，空即是空，又不会无故增加一个无民氏进来     //组织很有激情，新来的即可做大哥     //等一下！，我要执行初始化怎么办？，     //--要什么初始化，Node *plist_head = NULL; 完事了 //1.2 (色即是空，)     //1 现造个假人？还是弄个真人，抹去他的名字和记忆，让他当个工具人,随你怎么想了     //反正组织的缔造者认为，虚无缥缈的空不可捉摸，还是有个具体的东西代表一下比较实际     //明明是一个实体Node，却偏偏指鹿为马，Node，你不存在，你是空链表      bool is_empty(Node *plist){ //只是名字上命名为plist，你要知道，他总是Node *         /*         if(p == NULL)   //???，不带这么玩的，p必须是实体         */         if(p->next == NULL) //没有小弟             return true;         else             return false;     }      //来了来了，我的初始化函数终于派上用场,,终于切入楼主正题，初始化     void initialize_list(Node* plist)     {         // plist->name = ????; //无所谓啦，关键看你有没有带小弟         plist->next = NULL; //废了小弟先，     }     //      /*这里用*phead了，因为加人之前，必须要有个工具人头领存在，     不存在空即是空的问题, 可以对比之前1.1的实现*/     list_add(Node *phead, Node *pnode){           /*这个版本比起1.1的实现如何？         两个字舒服，而且没有使用双重指针，原来苦口婆心         虽然给我塞了个色即是空的概念（第一个节点明明存在，我却要说他是空链表）         但是没有双重指针就是爽，是不是？ 妈妈再也不用担心我的学习了~~~~~~~         */         Node *old_first = phead->next;         *p->next = pnode;         pnode->next = old_first;     }      Node head;  //既然是假人，英雄不问出身姓名，不要名字也罢, 也不知道他带了小弟没有（next）     initialize_list(&head); //强行把next置成NULL，     is_empty(&head);//yes!!, head明明看起来像个正常人，大活人，却要说他是空，这就是当老大的代价吧，色即是空     Node *p1 = (Node*)malloc(sizeof(Node));     strcpy(p1->name, "007");     Node *p2 = (Node*)malloc(sizeof(Node));     strcpy(p2->name, "谍影重重");     list_add(&head, p1);   //链表要领，无论何时，都要记得头是谁     list_add(&head, p2);      /*题外话, 这时候还能直接初始化链表吗？*/     initialize_list(&head); //???     /*想象下电影情节，这像是特工小组档案被直接删除，人还在，没有正常遣散，     也没给遣散费，后果是什么？, 幕后负责人会被清算，对就是你这个写代码的人，哈~     -正确的方式是遍历链表，把他们都free()掉，释放内存，     -安抚一下，现在是和平时期不需要特工了，（其实是没钱发工资了）*/      /*但愿你有这个耐心慢慢去体会, 并最终学会指针，链表？ 节点？     他们不再那么难以捉摸*/ /*~~~~~~~~~~~~~~~~~The End~~~~~~~~~~~~~~~~~~~~*/

user: user-4
content: 你的函数名说明这个函数是用来进行初始化的，如果是初始化，要不要修改list？要修改的话为什么不需要用指针

user: user-4
content: 打个比方，如果你要通过函数修改一个int的值，你会怎么做？一般有两种方法，通过引用或者指针传参，通过指针也就是传递一个int*的变量，那这样来理解，如果你要通过函数修改int的值，那么就用int*，再扩展，如果你要修改某种类型的值，那么就要传递这种类型的指针

user: user-0
content: 引用 6 楼 user-5的回复:哦 我看错 List 本身是指针  等于这个参数是二级指针  那没什么问题了  改成一级指针这个接口就废了 麻烦您能说具体点吗

user: user-0
content: 引用 7 楼 真相重于对错的回复:一个函数，参数是指针，在函数中修改这个指针的地址，函数返回后，那个指针依然是传入时的地址，只有参数是二级指针，修改参数的地址，函数返回后参数的地址才可能发生改变。 您好，这个函数不需要修改指针的地址呀

user: user-0
content: 您好，这个函数不需要修改指针的地址呀

user: user-2
content: 一个函数，参数是指针，在函数中修改这个指针的地址，函数返回后，那个指针依然是传入时的地址，只有参数是二级指针，修改参数的地址，函数返回后参数的地址才可能发生改变。

user: user-5
content: 哦 我看错 List 本身是指针  等于这个参数是二级指针  那没什么问题了  改成一级指针这个接口就废了

user: user-0
content: 引用 1 楼 user-5的回复:反了 不但应该使用指针 如果写想用参数返回 还得使用二级指针 一级指针还不够  目前这个接口是算是废了 没有用到这个指针呀，不理解，

user: user-0
content: 引用 1 楼 user-5的回复:反了 不但应该使用指针 如果写想用参数返回 还得使用二级指针 一级指针还不够  目前这个接口是算是废了 void InitializeList(List * plist) {     *plist = NULL; }

user: user-0
content: 引用 2 楼 自信男孩的回复:你的这个函数实现呢？不给实现怎么知道要不要用？ void InitializeList(List * plist) {     *plist = NULL; }

user: user-1
content: 你的这个函数实现呢？不给实现怎么知道要不要用？

user: user-5
content: 反了 不但应该使用指针 如果写想用参数返回 还得使用二级指针 一级指针还不够  目前这个接口是算是废了