為什么要使用二級指針?


需求:通過封裝的函數使指針 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;
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM