需求:通過封裝的函數使指針 q的指向改變(以前指向a,現在要指向b)
說的明白點:主函數中有個指針 int *q=&a; 把指針q作為參數傳入自己寫的函數
- int a=10,b=100;
- int *q=&a;
- void func(怎么寫q)
- {
- 怎么寫
- }
通過函數實現q=&b
錯誤案例1:
#include<iostream> using namespace std; int a= 10; int b = 100; int *q; void func(int *p) { p = &b; } int main() { q = &a; func(q); system("pause"); return 0; }
分析:雖然我們是用指針傳值,但是並不能改變參數的本質:p只是q的副本,副本p怎么變也變不了q的值。
錯誤案例2:
#include<iostream> using namespace std; int a= 10; int b = 100; int *q; void func(int *p) { *p = b; //把p=&b 改 } int main() { q = &a; func(q); cout<<a<<endl; system("pause"); return 0; }
分析:*p=*q=*(&a)=a 也就是p的值對應地址的值改為100.所以外部a=100,但q的值不會變。
因為*p只是修改a地址的內容。
雖然p是q的副本(假如q=FF01,則p也=FF01),但是我們通過解引用直接修改了a的內存,使外部的a變了。
上例雖然錯誤,但我們得出
結論:通過解引用我們直接修改內存數據,則不論函數內部、外部、是不是副本,只要變量名、指針、引用與這塊內存地址有關,全都改變。
從上圖我們得到:對一級指針的解引用賦值就是對它下級的數據的修改,同理,二級的解引用就是對一級的數據的直接修改。
我們再看題目 一級指針q=&a 要變為q=&b 也就是要把q的數據(FF01,中間那個)換為&b
怎么換?就是通過它的上級指針(q1)的解引用賦值 即*q1=&b, q1是一個二級指針。
所以我們知道函數內部
void func(/*因為q1是二級指針,所以參數也就要二級指針接收*/int**q1) { *q1 =&b; }
正確代碼1:
#include<iostream> using namespace std; int a= 10; int b = 100; int *q; void func(int **p) //2 { cout<<"func:&p="<<&p<<",p="<<p<<endl; *p = &b; //3 cout<<"func:&p="<<&p<<",p="<<p<<endl; } int main() { cout<<"&a="<<&a<<",&b="<<&b<<",&q="<<&q<<endl; q = &a; cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl; //下面2行可以換為一行 func(&q); //************************** int **q1=&q; func(q1); //******************* //func(&q); cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl; system("pause"); return 0; }
其實在c++中還有一種方法就是用
指針的引用
#include<iostream> using namespace std; int a= 10; int b = 100; int *q; void func(int *&p) //p就是q的別名 q是一級指針 所以參數要是int* { p = &b; //改變p就是改變q } int main() { q = &a; func(q); system("pause"); return 0; }
二、二級指針實際中的應用
需求:封裝一個函數 從堆區 給str申請一個空間 並賦值為"hello world"
也就是在封裝的函數中在堆區申請空間,用函數外的指針維護申請的空間
#include<iostream> using namespace std; void my_str2(char**my_str) { *my_str = new char[15]; strcpy(*my_str, "hello world"); } int main() { char *str = NULL; my_str2(&str); cout<<"str = "<<str<<endl; delete[] str; str=NULL; system("pause"); return 0; }
當然也可以用指針的引用
#include<iostream> using namespace std; void my_str2(char*&my_str) { my_str = new char[15]; strcpy(my_str, "hello world"); } int main() { char *str = NULL; my_str2(str); cout<<"str = "<<str<<endl; delete[] str; str=NULL; system("pause"); return 0; }
1、傳參規則
- 當二級指針作為函數形參時,能作為函數實參的是二級指針,指針數組,一級指針的地址
- 當數組指針作為函數形參時,能作為函數實參的是二維數組,數組指針
- 當二維數組作為函數形參時,能作為函數實參的是二維數組,數組指針
- 當指針數組作為函數形參時,能作為函數實參的是指針數組,二級指針,一級指針的地址
2、實例驗證:
#include <stdio.h> #include <stdlib.h> void fun1(int **pp) { printf("fun1\n"); } void fun2(int(*a_p)[5]) { printf("fun2\n"); } void fun3(int t_d_a[][5]) { printf("fun3\n"); } void fun4(int *p_a[5]) { printf("fun4\n"); } int main() { int *p_a[5]; //指針數組 int **pp = NULL; //二級指針 int *p = NULL; //一級指針 int t_d_a[5][5]; //二維數組 int a[5]; //一維數組 int(*a_p)[5] = &a; //數組指針 fun1(p_a); fun1(pp); fun1(&p); //fun1(t_d_a); //fun1(a_p); printf("\n"); //fun2(p_a); //fun2(pp); //fun2(&p); fun2(t_d_a); fun2(a_p); printf("\n"); //fun3(p_a); //fun3(pp); //fun3(&p); fun3(t_d_a); fun3(a_p); printf("\n"); fun4(p_a); fun4(pp); fun4(&p); //fun4(t_d_a); //fun4(a_p); printf("\n"); return 0; }