函式參數為指標的指標

函式參數為指標

函式參數為指標,就是「複製」記憶體位址給「參數」。

在main()主函式中,建立Student s物件,s物件記憶體位址為0x1000
img

1.呼叫callByPoint()函式,並把0x1000記憶體位址作為參數傳遞過去。
2.在Stack中,建立callByPoint()函式的空間。
建立新指標變數s,把傳過來的0x1000,指派給新指標變數s
此時 main() 主函式中的s變數與 callByPoint() 函式中的新指標變數s,都指向0x1000。
img

callByPoint() 函式中的新指標變數s,指向nullptr(記憶體位址0x0000)。
img

離開callByPoint()函式,callByPoint()函式的記憶體位址被釋放,包含callByPoint() 函式中的新指標變數s記憶體位址也被釋放。
img

所以main()主函式的Student s物件,s物件記憶體位址一直為0x1000

完整程式碼

以下的程式碼中,建立物件s,並把它的記憶體位址傳入callByPoint()的函式中。
試圖把記憶體位址修改成nullptr,在函式中確實是有修改成nullptr。
但離開函式後,s的記憶體位址沒有修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include "main.h"
using namespace std;
class Student {
 public:
  const char* name_;
};
void callByPoint(Student* s) {
  cout << "callByPoint before address = " << s << endl;
  s = nullptr;
  cout << "callByPoint after address = " << s << endl;
}

int main() {
  Student s;
  cout << "Before main() address = " << &s << endl;
  callByPoint(&s);
  cout << "After main() address = " << &s << endl;
  return 0;
}
Before main() address = 0x7ff7bfeff2b0
callByPoint before address = 0x7ff7bfeff2b0
callByPoint after address = 0x0
After main() address = 0x7ff7bfeff2b0

函式參數為指標的指標

函式參數為指標的指標,就可以修改外部指標變數的記憶體位址。

函式參數為「指標的指標」語法:

傳回型態 函式名(指標資料型態** 指標) {
  *指標 = 修改其它記憶體位址
}

使用2個星號**宣告這個是「指標的指標」,「指標的指標」存放的是指標的記憶體位址。

呼叫函式語法:

建立物件
指標 = &物件記憶體位址
函式(&指標位址)

要先建立一個指標,這個指標指向的是物件的記憶體位址。
再把「指標的位址」,傳入函式。

在main()主函式中,建立Student s物件,s物件記憶體位址為0x1000
img

指標變數ptr,ptr的記憶體位址是0x2000,儲存的值為0x1000,0x1000指向s物件。
img

1.建立callByPPoint()函式空間。
2.建立s指標,儲存的是ptr指標0x2000。
img

將0x2000的內容,原本是0x1000,改成0x0000 nullptr的位址。
img

離開callByPPoint(),s指標記憶體位址會被釋放。
img

完整程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include "main.h"
using namespace std;
class Student {
 public:
  const char* name_;
};

void callByPPoint(Student** s) {
  cout << "callByPPoint before address = " << *s << endl;
  *s = nullptr;
  cout << "callByPPoint after address = " << *s << endl;
}

int main() {
  Student s;
  Student* ptr = &s;
  cout << "Before main() address = " << ptr << endl;
  callByPPoint(&ptr);
  cout << "After main() address = " << ptr << endl;
  return 0;
}
Before main() address = 0x7ff7bfeff2b0
callByPPoint before address = 0x7ff7bfeff2b0
callByPPoint after address = 0x0
After main() address = 0x0

使用new 建立物件

建立使用new動態記憶體建立,建立時是回傳物件存放的記憶體位址,所以使用Student類型的指標接收。

Student* s = new Student();

使用new 建立物件,物件存放的位址在Heap中,而不是在Stack中。

因為s指標本身就是記憶體位址,所以傳入參數為「指標的指標」時,只要傳入指標的位址就好。

callByPPoint(&s);

在Heap中建立student物件,使用new,傳回的是記憶體位址0x1000,使用Student指標去接收傳回的記憶體位址。
img

1.在Stack中建立callByPPoint的函式空間
2.複製s指標的位址0x1000給callByPPoint()函式中的s指標。
img

將0x1000記憶體位址所儲存的內容,改為指向0x0000 nullptr
img

離開callByPPoint函式,callByPPoint()函式被記憶體回收。
但main()函式中的s指標的內容已經指向nullptr。
img

完整程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include "main.h"
using namespace std;
class Student {
 public:
  const char* name_;
};

void callByPPoint(Student** s) {
  cout << "callByPPoint before address = " << *s << endl;
  *s = nullptr;
  cout << "callByPPoint after address = " << *s << endl;
}

int main() {
  Student* s = new Student();
  cout << "Before main() address = " << s << endl;
  callByPPoint(&s);
  cout << "After main() address = " << s << endl;
  return 0;
}
Before main() address = 0x600000008030
callByPPoint before address = 0x600000008030
callByPPoint after address = 0x0
After main() address = 0x0

以前舊文章內容:

函式參數為指標的指標

在函式中若要修改指標所指向的記憶體位址,就要用到指標的指標。

[引數][1]為「指標」的位址,函式參數宣告為指標資料型態** 指標變數,這樣才可以接收指標的記憶體位址。

參考以下文章

https://www.geeksforgeeks.org/passing-reference-to-a-pointer-in-c/

If a pointer is passed to a function as a parameter and tried to be modified then the changes made to the pointer does not reflects back outside that function. This is because only a copy of the pointer is passed to the function. It can be said that “pass by pointer” is passing a pointer by value. In most cases, this does not present a problem. But the problem comes when you modify the pointer inside the function. Instead of modifying the variable, you are only modifying a copy of the pointer and the original pointer remains unmodified.

(google翻譯)如果將指標作為參數傳遞給函式並嘗試對其進行修改,則對指標所做的更改不會反映回該函式外部。這是因為僅將指標的副本傳遞給函式。可以說「透過指標傳遞」就是按值傳遞指標。在大多數情況下,這不會出現問題。但當你修改函式內部的指標時,問題就來了。您只是修改指標的副本,而不是修改變數,而原始指標保持不變。

  • 函式語法
傳回型態 函式名(指標資料型態** 指標) {
  *指標 = 其它記憶體位址
}
  • 呼叫函式語法
    函式(&指標位址)
    

程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
int global_var = 100;
void changePointerValue(int** ptr_ptr){
  *ptr_ptr = &global_var; //改為指向global_var
}
int main() {
  int var = 1;
  int* pointer_to_var = &var; //指向var
  cout << "Before:" << *pointer_to_var << endl;
  //passing the address of the pointer
  //把指標的位址傳進函式中
  changePointerValue(&pointer_to_var);
  cout << "After:" << *pointer_to_var << endl;
  return 0;
}
Before:1
After:100

指標的指標與new

參考文章

參考指向指標與new

new會返回動態配置記憶體的開始位址,將p_to_p使用*取值運算子修改p指向的位址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
//宣告一個函式initAddress() 指標是p_to_p,指向外部指標的位址
void initAddress(int** p_to_p){
  //印出指向外部指標p的記憶體位址
  cout << "Before p address = " << *p_to_p << endl;
  //動態配置記憶體位址,位址存放的內容為10,使用new會返回動態配置記憶體的開始位址。
  //使用*取值運算子修改指標p指向的位址
  *p_to_p = new int(10);
  //印出指向外部指標的記憶體位址與值
  cout  << "After p address= " << *p_to_p << ",After p value = " << **p_to_p << endl;
}
int main() {
  //宣告指標p,初始化為nullptr,也就是沒有指向任何位址
  int* p = nullptr;
  //呼叫函式initAddress,引數為指標p的位址
  initAddress(&p);
  //印出指標p的位址,印出指標p指向的位址,對指向的位址取出內容。
  cout << "== outside == " << endl;
  cout << "outside pointer address = " << p << ",outside pointer value = " << *p << endl;
  return 0;
}
Before p address = 0x0
After p address= 0x60000000c010,After p value = 10
== outside == 
outside pointer address = 0x60000000c010,outside pointer value = 10

results matching ""

    No results matching ""