指针(2),c语言笔记
swap3 函数确实没有交换 a 和 b 的值。
具体原因分析如下:
1. 函数的设计意图
从函数名和参数 int *px, int *py 来看,这个函数的本意应该是通过指针来交换两个整数的值。
2. 函数内部的问题
让我们逐行分析这个有问题的 swap3 函数:
void swap3(int *px, int *py) {
int *pt; // 定义了一个整型指针变量pt
pt = px; // 将指针px的地址(即指向a的地址)赋给pt
px = py; // 将指针py的地址(即指向b的地址)赋给px
py = pt; // 将pt中保存的(原px的,即a的)地址赋给py
}
关键问题在于: 它交换的是函数内部的指针变量本身(px 和 py)的值(也就是地址),而不是指针所指向的内存地址中的值。
3. 为什么交换指针变量无效?
px和py是函数的形参,它们虽然是指针,但本质上是局部变量。- 当你调用
swap3(&a, &b)时,px获得了a的地址,py获得了b的地址。 - 在函数内部,
px和py这两个指针变量的值(它们保存的地址)被交换了。也就是说,在函数内部,px指向了b,py指向了a。 - 但是,这个交换操作只发生在形参(局部变量)上。 函数调用结束后,这些局部变量就被销毁了。而原始变量
a和b所在内存地址中的值(1 和 2)自始至终都没有被修改过。
4. 正确的做法应该是怎样的?
要实现交换,应该操作指针所指向的内容,即使用解引用操作符 *:
// 正确的交换函数(通常命名为 swap2)
void swap_correct(int *px, int *py) {
int temp; // 定义一个整型临时变量
temp = *px; // 将px指向的内存地址中的值(a的值)存入temp
*px = *py; // 将py指向的内存地址中的值(b的值)赋给px指向的地址(a的地址)
*py = temp; // 将temp中保存的(原a的)值赋给py指向的地址(b的地址)
}
这个正确的版本通过 *px 和 *py 直接修改了主调函数中变量 a 和 b 的值。
总结
swap3 只是交换了函数内部指针形参的副本,并没有触及到实际需要交换的数据,因此 a 和 b 的值没有发生任何变化。
幻灯片右侧的表格也印证了这一点:调用 swap3 后,a 的值仍然是 1,b 的值仍然是 2。
数组名与地址的关系
这个关系导致了访问数组元素的两种完全等价的方法,这也是PPT中 &(a[i]) 和 *(a+i) 标注的含义:
| 表示法 | 含义 | 说明 |
|---|---|---|
a[i] |
数组的第 i 个元素 |
最常见的形式,下标运算符 |
*(a + i) |
访问地址 a+i 处的值 |
通过指针解引用来访问 |
&a[i] |
获取第 i 个元素的地址 |
等价于 a + i |
结论是:a[i] 在编译时完全等价于 *(a + i)。
代码示例解析
PPT下方的循环代码正是这一概念的应用:
// 常见的循环写法
for (i = 0; i < 100; i++) {
sum += a[i]; // 使用下标访问
}
// 完全等价的指针写法
for (i = 0; i < 100; i++) {
sum += *(a + i); // 通过基地址偏移并解引用来访问
}
这两种写法在功能上没有任何区别,编译器通常会生成相同的机器指令。
总结
- 数组名是常量指针:数组名
a是一个指向数组首元素的指针常量,其值不可改变(例如,不能进行a++操作)。 []运算符的本质:下标运算符[]实际上就是通过“基地址 + 偏移量”然后“解引用”这一过程的语法糖。- 理解偏移单位:对指针加
i,并不是地址值简单加上i,而是加上i * sizeof(数组元素类型)个字节。
理解数组和指针的这种紧密关系,是深入掌握C语言内存操作和指针运用的关键一步。
快手成长空间 767人发布