指针的使用场景

指针的使用场景通常只有两个,传递和偏移。

一、指针的传递使用场景

例1

//  在子函数内去改变主函数中某个变量的值
//  Created by Lee Lucy on 2024/2/24.

#include <stdio.h>
void change(int j){//j是形参
    j=5;
}
int main(int argc, const char * argv[]) {
    int i=10;
    printf("before change i=%d\n",i);//在这里打断点
    //C语言的函数调用是值传递,实参赋值给形参,j=i
    change(i);//在这里按下箭头,进入change函数
    printf("after change i=%d\n",i);
    return 0;
}

代码提示位置打断点,然后调试程序,在内存视图输入&i,可以看到变量i的地址是0x61fe1c。向下键(F7)进入change函数,这时变量j的值的确为10,但是&j的值为0x61fdf0,即j和i的地址并不相同。运行j=5后,change函数实际修改的是地址0x61fdf0上的值,从10变成了5,接着change函数执行结束,变量i的值肯定不会发生改变,因为变量i的地址是0x61fe1c而非0x61fdf0.

程序的执行过程是内存的变化过程,需要关注栈空间的变化。当main函数开始执行时,系统会为main函数开辟函数栈空间,当程序走到int i时,main函数的栈空间就会为变量i分配4字节大小的空间。调用change函数时,系统会为change函数重新分配新的函数栈空间,并为形参变量j分配4字节大小的空间。在调用change(i)时,实际上是将i的值赋值给j,称为值传递(C语言的函数调用均为值传递)。因此当在change函数的函数栈空间内修改变量j的值后,change函数执行结束,其栈空间就会释放,j不再存在,i的值不会改变。

如何在子函数中修改main函数内的某个变量的值?

例2

//  Created by Lee Lucy on 2024/2/24.

#include <stdio.h>
void change(int *j){//j是形参
    *j=5;//*j等价于变量i,间接访问得到变量i
}

int main(int argc, const char * argv[]) {
    int i=10;
    printf("before change i=%d\n",i);
    change(&i);//传递变量i的地址
    printf("after change i=%d\n",i);
    return 0;
}

将变量i的地址传递给change函数时,实际效果是j=&i,依然是值传递。j是一个指针变量,内部存储的是变量i的地址,所以通过*j间接访问到了与变量i相同的区域,通过*j=5实现了对i的值的改变。通过单步调试,依然可以看到变量j自身的地址是与变量i的地址依然不相等。

二、指针的偏移使用场景

指针的偏移

把对指针的加减称为指针的偏移,加就是向后偏移,减就是向前偏移。

数组名中存储着数组的起始地址0x61fdf0,其类型为整型指针,所以可以将其赋值给整型指针变量p,从监视窗口看到p+1的值为0x61fdf4。为什么加1后不是0xfdf1呢?因为指针变量加1后,偏移的长度是其基类型的长度,即偏移sizeof(int),通过*(p+1)可以得到元素a[1]。编译器在编译时,数组取下标的操作正是转换为指针偏移来完成的。

float *p; p的加减也是偏移4个字节

//  指针的偏移使用场景,对指针进行加减
//  Created by Lee Lucy on 2024/2/24.

#include <stdio.h>
#define N 5
int main(int argc, const char * argv[]) {
    //数组名内存储了数组的起始地址,a中存储的就是一个地址值
    int a[N]={1,2,3,4,5};
    int *p;//定义指针变量p
    int i;
    p=a;//保证等号两边的数值类型一致
    for(i=0;i<N;i++){//正序输出
        printf("%3d",*(p+i));//与a[i]等价
    }
    printf("\n-----------------\n");
    p=&a[4];//让指针变量p指向数组最后一个元素
    for(i=0;i<N;i++){//逆序输出
        printf("%3d",*(p-i));
    }
    printf("\n");
    return 0;
}

指针与一维数组

为什么一维数组在函数调用进行传递时,它的长度子函数无法知道呢?——一维数组名中存储的是数组的首地址。eg.数组名c中存储是一个起始地址,所以子函数change传入了一个地址。定义一个指针变量时,指针变量的类型要和数组的数据类型保持一致,通过取值操作,就可将“h”改为“H”,称为指针法。获取数组元素时,可以通过取下标的方式来获取数组元素并进行修改,称为下标法。

//  指针与一维数组的传递
//  练习传递与偏移
//  数组名作为实参传递给子函数时,是弱化为指针的。
//  Created by Lee Lucy on 2024/2/24.

#include <stdio.h>
void change(char *d){
    *d='H';
    d[1]='E';
    *(d+2)='L';
}
int main(int argc, const char * argv[]) {
    char c[10]="hello";
    change(c);
    puts(c);
    return 0;
}

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LucyLee04

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值