程序设计基础 — 第 6 课
r 就是改 a,不产生新变量。&a 取地址,*p 按地址把值取回来。new 了一定要 delete。int a = 10;
int& r = a; // r 是 a 的引用(外号)
r = 20; // 改 r 就是改 a
cout << a; // 20 —— a 变了!
引用不是新变量,它就是原变量的另一个名字。改任意一个,另一个同步变。
// 没有引用 —— 拷贝,改不了原值
void addOne_copy(int x) { x = x + 1; }
// 有引用 —— 直接改原值
void addOne_ref(int& x) { x = x + 1; }
int main() {
int n = 5;
addOne_copy(n); cout << n; // 5(没变!)
addOne_ref(n); cout << n; // 6(变了!)
}
const:void print(const vector<int>& v)。
每个变量在内存里有个地址。指针存的就是这个地址。
int a = 42;
int* p = &a; // p 存的是 a 的地址(& 取地址)
cout << a; // 42(值)
cout << &a; // 0x5ffe8c(地址)
cout << p; // 0x5ffe8c(p 就是地址)
cout << *p; // 42(* 解引用:按地址找到值)
| 符号 | 读法 | 含义 | 示例 |
|---|---|---|---|
int* | “指向 int 的指针” | 声明指针类型 | int* p; |
&a | “a 的地址” | 取地址 | p = &a; |
*p | “p 指向的值” | 解引用 | cout << *p; |
int* p(声明)和 *p(解引用)里的 * 是两回事。声明时 * 表示“这是个指针”,使用时 * 表示“去地址上拿值”。
void swap(int* x, int* y) { // 接收两个地址
int temp = *x; // 解引用,拿到值
*x = *y; // 通过地址直接改原变量
*y = temp;
}
int main() {
int a = 3, b = 7;
swap(&a, &b); // 传地址
cout << a << " " << b; // 7 3(真正交换了!)
}
和引用版对比:引用版写 swap(a, b),调用时不用加 &;指针版必须自己把地址传进去,函数里也必须解引用才能碰到原值。
| 对比项 | 引用 | 指针 |
|---|---|---|
| 语法 | int& r = a; | int* p = &a; |
| 用的时候 | 直接当变量用 r = 5 | 必须解引用 *p = 5 |
| 能空吗 | 不行,必须绑定 | 可以 nullptr |
| 能改指向 | 不行,终生绑定 | 可以 p = &b; |
| 推荐 | 传参首选 | 需要“空”或“换指向”时 |
int arr[] = {10, 20, 30};
int* p = arr; // 数组名本身就是首地址
cout << *p; // 10(arr[0])
cout << *(p + 1); // 20(arr[1])—— 指针 +1 跳到下一个元素
cout << *(p + 2); // 30(arr[2])
这就是为什么数组索引从 0 开始:arr[i] 等价于 *(arr + i)。注意 p + 1 跳的是“一个元素”的距离,不是地址加 1 —— 下一课 0007B 会把这件事讲透。
int* p = new int; // 在堆上申请一个 int
*p = 100;
cout << *p; // 100
delete p; // 用完了必须释放!不然内存泄漏
int* arr = new int[5]; // 申请动态数组
arr[0] = 1;
delete[] arr; // 数组用 delete[]
new 和 delete 必须配对,new[] 配 delete[]。不过日常用 vector 就够了,它自动管理,不用你操心。
int& r = a; 之后 r 永远是 a。要表达“可能没有对象”,用指针加 nullptr。* 不是一回事:int* p 是声明,*p 是解引用。混着看一眼就能看错。new / delete 必须配对,而且 new[] 只能配 delete[]。用错方括号就是未定义行为。p + 1 是跳一个元素,不是地址加 1 字节。int* 一次跳 4 字节,double* 一次跳 8 字节。const:写成 vector<int>& v 会允许函数改掉调用者的数据,写成 const vector<int>& v 才是只读。int a = 5; int& r = a; r = 10; 之后 a 的值是?int a = 5; int* p = &a; *p = 3; cout << a; 输出什么?swap 要用引用而不是直接传值?void swap(int& x, int& y)。
int* p = arr; 然后 p++ 往后走,*p 取值。
int 还是 int&?写错就改不到原值。nullptr 和“已经 delete”的都要停下来问一句。main 里,加 cout 把中间值打印出来。&:变量的别名,传参首选;不能为空,也不能改绑。*:存地址,*p 解引用拿值;可以为空,可以改指向。arr[i] 就是 *(arr + i),指针 +1 跳一个元素。vector 代替。new 出来的数据为什么能活过函数、delete 之后指针为什么不能再用、指针 +1 为什么是按元素跳。这一课解决的是“指针的地址到底指向什么”。