指针(2),c语言笔记

alt

swap3 函数确实没有交换 ab 的值。

具体原因分析如下:

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
}

关键问题在于: 它交换的是函数内部的指针变量本身(pxpy)的值(也就是地址),而不是指针所指向的内存地址中的值

3. 为什么交换指针变量无效?

  • pxpy 是函数的形参,它们虽然是指针,但本质上是局部变量。
  • 当你调用 swap3(&a, &b) 时,px 获得了 a 的地址,py 获得了 b 的地址。
  • 在函数内部,pxpy 这两个指针变量的值(它们保存的地址)被交换了。也就是说,在函数内部,px 指向了 bpy 指向了 a
  • 但是,这个交换操作只发生在形参(局部变量)上。 函数调用结束后,这些局部变量就被销毁了。而原始变量 ab 所在内存地址中的值(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 直接修改了主调函数中变量 ab 的值。

总结

swap3 只是交换了函数内部指针形参的副本,并没有触及到实际需要交换的数据,因此 ab 的值没有发生任何变化。

幻灯片右侧的表格也印证了这一点:调用 swap3 后,a 的值仍然是 1b 的值仍然是 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); // 通过基地址偏移并解引用来访问
}

这两种写法在功能上没有任何区别,编译器通常会生成相同的机器指令。

总结

  1. 数组名是常量指针:数组名 a 是一个指向数组首元素的指针常量,其值不可改变(例如,不能进行 a++ 操作)。
  2. [] 运算符的本质:下标运算符 [] 实际上就是通过“基地址 + 偏移量”然后“解引用”这一过程的语法糖。
  3. 理解偏移单位:对指针加 i,并不是地址值简单加上 i,而是加上 i * sizeof(数组元素类型) 个字节。

理解数组和指针的这种紧密关系,是深入掌握C语言内存操作和指针运用的关键一步。

全部评论

相关推荐

12-03 15:06
武汉大学 Java
投递拼多多集团-PDD等公司10个岗位
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
11-22 12:43
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务