C++ 傻鸟指针

C++ 傻鸟指针

lucas Lv4

指针是操作内存的工具

1. 指针也存在内存中,指针也有内存地址

指针也存在内存中,指针也有内存地址

pointer.png

记住这个图,每次难以理解指针的时候,就看看这个图

2. 指针的类型及其初始化

首先,一个 int *n; ,表明了这个指针类型是 int *

所以,通用的指针类型就是 dataType *

1
2
int a = 10;
int *p = &a;

这里p的类型是int*而不是int

所以,指针的声明并没有什么难处,他和普通的变量其实没什么区别,只是类型改成对应的指针类型就行了

而指针的赋值,一般就是对象的引用,

1
2
Person person = *new Person;
Person* p = &person;

注意

第一行代码, *new Person() 是这个分配内存后用一个临时指针所指的内存空间

所以就类似于

1
2
Person* pPerson = new Person;
Person person = *pPerson;

这里的 * 称为指针运算符,用来取得某个地址上的数据

person *p 是一个指针,&person 是这个 person 的引用

tips

auto person = *new Person();这里还调用了拷贝构造函数,但这不是本文所述的重点

3. 指针通过->可调用当前指向内存所属对象的内部成员

1
2
3
4
5
6
7
8
class Person {
public:
char *name;
};

// 调用
Person *p = new Person();
p->name;

4. 指针指向一个内存地址

可以将指针赋值给指针,也可以将一个地址赋值给指针

1
2
3
int n = 10;
int *ptr1 = &n;
int *ptr2 = ptr1;

5. 指针输出(打印或调用)

输出形式 代码 结果
输出变量名 ptr 存储的地址
输出 *变量名 *ptr 地址上的数据
输出 &变量名 &ptr 指针本身的地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main() {

int n = 10;
int *ptr = &n;

std::cout << "ptr : " << ptr << std::endl;
// ptr : 0x7ff7b5fe020c
std::cout << "*ptr : " << *ptr << std::endl;
// *ptr : 10
std::cout << "&ptr : " << &ptr << std::endl;
// &ptr : 0x7ff7b5fe0200

std::cout << "n : " << &n << std::endl;
// n : 0x7ff7ba53120c
}

6. 作为参数传递

这里涉及一个 形参、实参 的概念

简单来说,
形参就是声明函数(方法)的时候,填写的参数
实参就是调用函数(方法)的时候,填写的参数

所以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

class Person {
public:
const char *name = "tom";
};

void print(Person *p) {
std::cout << std::endl;
std::cout << "print2(Person *p) " << p << std::endl;
std::cout << "print2(Person &p) " << &p << std::endl;
std::cout << "print2(Person p->name) " << p->name << std::endl;
}

int main() {

auto person = *new Person();
auto *p_ptr = &person;

std::cout << "p_ptr : " << p_ptr << std::endl;
std::cout << "&p_ptr : " << &p_ptr << std::endl;
std::cout << "p_ptr->name : " << p_ptr->name << std::endl;

print(p_ptr);
}

我们来看输出结果

1
2
3
4
5
6
7
p_ptr : 0x7ff7bbb55208 // person 地址
&p_ptr : 0x7ff7bbb55200
p_ptr->name : tom

print2(Person *p) 0x7ff7bbb55208
print2(Person &p) 0x7ff7bbb551d8
print2(Person p->name) tom

我们知道第 20 行输出的肯定是指针 ptr存储的地址,也就也是这个person的地址

并且,第 21 行输出的是指针 ptr本身的地址

第 8 行定义的函数,括号里是形参

在调用函数的时候,会生成一个新的指针p,指向person,也就是把传进去的p_ptr赋值给p

所以第 10 行输出的就是p存储的地址

所以第 11 行输出的就是p自身的地址

所以第 11 行就是用p访问person,输出自然是personname

所以,指针对象作为参数传入,会生成一个新的指针,和这个传入的指针指向同一块内存,所以你用这个指针执行的操作,在函数外面也会接收到。

所以就可以这么写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

void copyStringToDynamicMemory(char*& destination) {
const char* source = "This is a dynamically allocated string.";

destination = new char[strlen(source) + 1];

std::strcpy(destination, source);
}

int main() {
char* code = nullptr;
copyStringToDynamicMemory(code);

if (code != nullptr) {
std::cout << "code : " << code << std::endl;
delete[] code;
} else {
std::cerr << "Memory allocation failed." << std::endl;
}
}

我们传入了code为空,等到执行完函数,code所指的内存已经写入了数据

这里的参数这样写 char* &destination

7. 作为返回值

这里涉及两个概念:堆和栈

堆内存一般指的是动态分配的内存,栈内存一般指的是方法调用栈

在C++中,你可以使用以下几种方法来申请堆内存:

  1. 使用new运算符: 使用new运算符可以动态分配内存并返回一个指向该内存的指针。例如,如果要动态分配一个整数数组:
1
int* dynamicArray = new int[10];

在分配内存后,不要忘记在不再需要时,使用delete运算符释放内存:

1
delete[] dynamicArray;
  1. 使用malloc函数: 你还可以使用标准C库函数malloc来分配堆内存。malloc返回一个指向分配的内存块的指针。与new不同,malloc不会自动调用类的构造函数。你需要手动管理内存。
1
int* dynamicArray = (int*)malloc(10 * sizeof(int));

同样,你应该使用free函数来释放内存:

1
free(dynamicArray);
  1. **使用std::allocator**: C++还提供了std::allocator类,它可以用于分配内存并构造对象。虽然通常不需要手动使用它,但它提供了更多的内存管理灵活性。
1
2
std::allocator<int> alloc;
int* dynamicArray = alloc.allocate(10);

当你不再需要内存时,你可以使用alloc.deallocate函数来释放它。

1
alloc.deallocate(dynamicArray, 10);
  1. 使用智能指针: 在现代C++中,推荐使用智能指针来管理堆内存。std::shared_ptrstd::unique_ptr是强大的工具,它们会在对象不再需要时自动释放内存。
1
std::shared_ptr<int> dynamicArray = std::make_shared<int[]>(10);

当指针超出范围或不再需要时,它们会自动处理内存的释放。

使用newmalloc时,请确保在不再需要内存时手动释放它,以避免内存泄漏。同时,了解每种方法的区别和适用场景,以便根据需求选择合适的方法。

当指针作为返回值的时候,只有两种情况

  • 指向堆内存
  • 指向全局变量

举一个的例子🌰

1
2
3
4
int* createAndReturnDynamicArray(int size) {
int* arr = new int[size];
return arr;
}
  • Title: C++ 傻鸟指针
  • Author: lucas
  • Created at : 2023-10-27 10:14:16
  • Updated at : 2024-11-27 17:12:57
  • Link: https://darkflamemasterdev.github.io/2023/10/27/C-傻鸟指针/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments