C++指针基础
指针基础
引用
引用变量是对现有变量的引用,它是使用 & 运算符创建的:
string food = "Pizza"; // 声明 food 变量
string &meal = food; // 引用 food
- 不存在空引用。引用必须连接到一块合法的内存。
- 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
- 引用必须在创建时被初始化。指针可以在任何时间被初始化。
#include <iostream>
using namespace std;
int main()
{
// 声明简单的变量
int i;
double d;
// 声明引用变量
int &r = i;
double &s = d;
i = 5;
cout << "value of i : " << i << endl;
cout << "value of i reference : " << r << endl;
d = 11.7;
cout << "value of d : " << d << endl;
cout << "value of d reference : " << s << endl;
return 0;
}
// value of i : 5
// value of i reference : 5
// value of d : 11.7
// value of d reference : 11.7
为了了解动态内存,首先需要了解指针。我们创建的所有变量都存储在内存中。
指针是一个变量,它将另一个变量的内存地址存储为其值。
定义和访问
int *p; // 数值类型
p=&a; // 记录变量a的地址
必要时要加( ) 来避免优先级的问题
int(*p_arr)[3]; //指向含有3个int元素的数组的指针
Student* p_struct; //类或结构体类型的指针
使用 & 运算符访问变量的地址。
使用 * 定义一个指针类型。
int num = 42;
int *p = #
cout << p;
使用 星号 * 还用于访问存储在内存地址的值。它称为解除引用运算符
cout << *p;
案例
#include <iostream>
using namespace std;
int main() {
int num = 42;
int *p = #
cout << "nums " << num << endl;
cout << "*p " << p << endl;
cout << "**p " << *p << endl;
return 0;
}
// 执行结果
nums 42
*p 0x3bfb3ff894
**p 42
内存空间
在32位操作系统下占用4个字节,64位下占用8个
空指针和野指针
空指针:指针变量指向内存编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
野指针:指变量指向非法的内存空间
const修饰指针
const修饰指针----常量指针
特点:指针的指向可以修改,指针指向的值不可以修改
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
const int *p = &a;
*p = 20; // --错
p = &b; // --对
}
const修饰常量----指针常量
特点:指针的指向不可以修改,指针指向的值可以修改
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
int *const p = &a;
*p = 20; // --对
p = &b; // --错
}
指针之间的赋值
指针赋值和int变量赋值一样,就是将地址的值拷贝给另外一个。
指针之间的赋值是一种浅拷贝,是在多个编程单元之间共享内存数据的高效的方法。
int* p1 = &a;
int* p2 = p1;
通过指针改变原数据值
int num = 42;
int *p = #
*p = 8;
cout << num;
8
指针和数组
数组的名称实际上是指向其第一个元素的指针。
可以通过递增指针来访问每个元素。
案例1
#include <iostream>
using namespace std;
int main() {
int arr[] = {2, 4, 6, 8}; // 数组
int *p = arr; // 数组指针-指向了数组的第一个元素
// 第一个元素
cout << *p << endl;
// 第二个元素
cout << *(p + 1) << endl;
// 第三个元素
cout << *(p + 2) << endl;
return 0;
}
// 执行结果
2
4
6
案例2
#include <iostream>
using namespace std;
int main() {
int arr2[] = {44, 22, 11, 0};
int *p2 = arr2;
for (int i = 0; i < 4; i++) {
cout << *p2 << endl;
p2++;
}
return 0;
}
44
22
11
0
说明
& 运算符用于访问变量的内存位置。
* 运算符用于访问存储在指针中的内存地址的值。
同样的 * 符号也用于声明指针,它与解除引用运算符不同。
指针和函数
1.值传递
2.地址传递
#include<iostream>
using namespace std;
void swap(int a, int b) {
int temp = 0;
temp = a;
a = b;
b = temp;
}
void swap2(int *a, int *b) {
int temp = *a; // 解指针得到数值
*a = *b;
*b = temp;
}
int main() {
int a = 10;
int b = 20;
//值传递
swap(a, b);
cout << a << " " << b << endl;
//地址传递
swap2(&a, &b);
cout << a << " " << b << endl;
return 0;
}
// 执行结果
10 20
20 10
动态内存
我们需要根据用户输入分配新内存时。 创建动态数组(具有可变大小的数组)
#include <iostream>
using namespace std;
int main() {
int size = 10;
int *p = new int[size]; // 通过new来创建一个数组指针
for (int i = 0; i < size; i++) {
p[i] = i * i;
}
for (int i = 0; i < size; i++) {
cout << p[i] << ends;
}
}
0 1 4 9 16 25 36 49 64 81
指针潜在危险
指针的让我们对内存的操作有了很大的自由性,同时也带来了潜在的危险。
产生的原因:
1.定义指针变量的同时未对其进行初始化:
指针在被定义的时候,如果程序不对其进行初始化的话,它会指向随机区域,
因为任何指针变量(除了static修饰的指针变量)在被定义的时候是不会被置空的,它的默认值是随机的。
2.指针所指向的内存空间被释放时,却没有对该指针变量的值(即该指针原来指向的内存空间的地址)进行置空:
我们在用库函数malloc开辟内存空间时,要检查返回值是否为空,如果为空,则开辟失败;如果不为空,则指针指向的是开辟的内存空间的首地址。
指针指向的内存空间在用free()或者delete(注意delete只是一个操作符,而free()是一个函数)
释放后,如果程序员没有对其置空或者其他的赋值操作,就会使其成为一个野指针。
3.指针操作超越变量作用域.
危害规避
1.在定义一个指针时同时初始化为NULL
int *p=NULL;
2.释放指针指向的内存空间时,将指针重置为NULL。
free(p1); //只释放了p1指向的堆区空间 并没有将指针p1置为空
p1 = NULL;
3..使用时不要超出变量作用
int a[3];
int*p=a;
cout<<p[5]; // 错误使用