C语言DAY11 - 指针patr1

指针

变量的地址就叫做指针

指针变量

指针变量也是一个变量,存储地址的变量,可以间接的访问指向的变量.
  • 语法
定义,赋值
数据类型* 指针表变量的名称;
int* p1;
//类型是 int* 读作 int 指针.
double* p2;
float* p3;
char* p4;
1. 只能存储对应类型变量的地址
2. 不能赋一个非地址类的数据
int* p1 = #
//正确的赋值方式

取地址
占位符是%p
printf("%p",&p1)
//p1这个变量的地址
printf("%p",p1)
//p1变量的值,就是*p1指向的变量的地址
1.p1 操作的是 p1这个指针变量.
2.可以取P1的值,也可以为 p1赋值
3.&p1拿到的是 p1的值

操作变量
*p1代表p1指针指向的变量
*p1完全等价于 num
*p1 = 100;
//将100赋值给 num
printf("%d",*p1)
//输出 num 的值
X 错误的
p1 = 200;
注意的问题
1.批量声明
int* p1,p2,p3;
//这样批量声明p2,p3都是 int 类型
//指针类型是*变量名
2.野指针
int* p1;
//指向一块随机的空间,操作起来会出现各种错误
//访问的时候,如果随机空间没人用就不会报错,如果有人用就会BAD_ACCESS
//如果赋值就相当危险
NULL 值
如果没有变量的地址给这个指针变量,就初始化一个 NULL,代表指针变量不指向内存中的任何地址.
  1. NULL == 0;
    所以也可以直接复制指针变量一个0;
  1. 0代表不指向任何空间
  2. 如果访问一个 NULL 值的指针100%报错.
多个指针指向同一个变量
int num = 100;
int* p1 = #
int* p2 = p1;
//把p1的值赋给了 p2 
*p2 也就指向了 num
*p2 = 100;

函数传递数组
void test2(int arr[],int len)

//int arr[] 不是传递的这个数组,而是这个数组的地址

指针作为函数参数
void test3(int *p1)
{
    *p1 = 1000;
    //函数内部修改变量值
}
//声明
test(&num);
//传递对应类型变量的地址
执行完函数,num 的值为1000;
  • 有什么作用
在函数内部修改实参的值,函数只能又一个返回值,当需要返回多个值时就可以用指针修改.
int getMaxAndMin(int arr[],int len,int* min);
//声明函数
int max = getMaxAndMin(arr,sizeof(arr)/sizeof(arr[0]),&min);
//调用函数
void getZuiDaHeZuiXiao (int arr[],int len,int* pMax,int* pMin);
//声明无返回值函数
getZuiDaHeZuiXiao(arr,sizeof(arr)/sizeof(arr[0]),&max,&min);
//调用无返回值函数,传递两个变量的地址


  • 指针为什么分类型

  1. 变量在内存中不同类型占用不同的字节数指针是最低字节地址
  2. 根据指针类型,确定指向的变量在内存中占用多少字节

> 3. 占几个字节连续操作几个字节找到整个变量.从而正确有效的操作访问和修改变量

多级指针
  1. 一级指针中存储的是1个普通变量的地址.
  2. 二级指针中存储的是1个一级指针变量的地址.
  3. 三级指针中存储的是1个二级指针变量的地址

    • 语法

    一级指针: 数据类型* 指针名;
    二级指针: 数据类型** 指针名;
    int** p2 = p1;
    //这样是错误的,把普通变量的地址赋给了二级指针.
    int** p2 = &p1;
    //这样就把一级指针的地址赋给了二级指针
    //他就指向了一级指针地址中存储的普通变量的地址,
    //就指向了普通变量

    &num == p1
    *p1 == num
    &p1 == p2
    **p2 == num
    *p2 == p1
    &p2 == p3

    • 操作

    int num = 10;
    int* p1 = #
    int** p2 = &p1;

    *p1 = 200;
    //代表 p1指针改变了 num 的值为200.
    (num == 200);

    int age =110;
    *p2 =&age;
    //代表p2这个指针指向的变量,也就是 p1
    //这句话执行完毕,p1就指向 age了
    (*p1 == age)
    同时
    (**p2 == age)

指针与整数的加减运算
指针与整数加减运算,是在指针地址的基础之上加1个单位变量占用的字节数.
int* p1 = #
int* p2 = p1+1;
//如果 &num 的地址是0x11901,p2的值就是0x11905
//不能写成*p1 + 1,这样写就是 num+1了.
//*(p1+1)才是正确的表达式
指针与数组
int arr[] = {10,20,30,40,50,60,70};
int *p1 = &arr[0];
//表示p1指针指向了数组中的第0个元素.
int* p2 = arr; 
//这么做完全也是没有问题,因为arr代表数组的地址.也就是数组的第0个元素的地址.
使用指针来遍历数组.
  1. 第一种方式

    int arr[7] = {10,20,30,40,50,60,70};
    int* p1 = arr;
    //p1指针指向了数组的第0个元素.
    for(int i = 0; i < 7; i++)
    {
    printf(“%d\n”,*(p1+i));
    }

  2. 第二种方式

    int arr[7] = {10,20,30,40,50,60,70};

     for(int i = 0; i < 7; i++)
     {
        printf("%d\n",*(arr+i));
     }
    

    //arr本身就是一个指针地址.

  3. 第三种方式

    int arr[7] = {10,20,30,40,50,60,70};
    int* p1 = arr;

     for(int i = 0; i < 7; i++)
     {
        printf("%d\n",*(p1++));
     }
     *p1
     //. 代表p1指针指向的变量. 就是数组中第0个元素.
    //    *(p1+1);//p1+1 的结果是第1个元素的地址  *(p1+1) 代表数组中第1个元素.
    //    *(p1+2);//p1+2 的结果是第2个元素的地址. *(p1+2) 代表数组中第2个元素.
    **注意的地方**
     每次循环.p1的值都会变化.
     最后1次执行完毕之后. p1指针指向外面去了.
     p1就不再执行数组中的任何元素了.
    
    • 注意: 数组名代表数组的地址.而数组一旦创建.数组的地址就确定了.不能改变

      所以.我们不能为数组名赋值. 不能修改数组名的值. 但是可以使用数组名的值.

    结论: 无法修改数组名的值. 不能为数组名赋值.任何值都不可以.

    WHY? 因为数组名代表数组的地址. 而数组一旦创建数组的地址是无法改变的. 所以你不能给他赋值.
    数组名是1个常量.1个地址常量

当数组作为函数的参数的时候
void test(int arr[],int len);
//系统在编译的时候已经把数组换成了指针
void test(int *arr,int len)
//在声明参数的时候,不是创建数组,而是创建一个存储数组地址的指针变量
所以 sizeof计算函数参数的长度时永远都是8.
函数如果带了1个参数 这个参数是1个数组.
直接写1个指向数组的第0个元素的指针,=再传入长度
索引的本质
  • 指针变量后面可以使用中括弧,在中括弧中写上下标来访问数据.

    p1[n]; 前提是p1是1个指针变量.

    完全等价于 *(p1+n);

    int num1 = 100;
    int num2 = 200;
    int* p1 = &num2;
    p1[0] == (p1+0) == num2;
    p1[1] == (p1+1) == num1;
    -拿数组举例

    *arr == arr[0];
    *(arr+1) == arr[1];
    1.只要是指针都可以使用中括弧下标.就相当于是去访问指针指向的变量.
    2.操作数组我们虽然使用的中括弧下标来操作,实际上内部仍然使用的指针来操作.

存储指针的数组
  • 声明

    元素类型 数组名[数组长度];
    int* arr[3];
    类是是 int* 长度为3
    int* arr[3] = {p1,p2,p3};
    int* arr[3] = {&num1,&num2,&num3};

    int arr[3] = {10.20,30};
    int* pArr[3] = {arr,&arr[1],&arr[2]};
    *(pArr[0]) = 100;
    //pArr 数组第0个元素是 arr 数组第0个元素的指针,赋值100,arr[0]==100

指针之间的减法
long res = &arr[7] - &arr[1] == 6;
指针指向的同一个数组内的两个变量之间相差几个元素

int num1 = 0;
double num2 = 0.0;
double num3 = 0.0;
int num4 =0;

int* p1 =&num1;
int* p2 =&num4;
long res = p2-p1 == 5;
double+double+int = 20个字节.
//一般只用在同一个数组内,不然结果没有意义.
指针之间的比较运算
  • 比较运算符都可以用在两个指针之间
  1. 变量分配字节空间的时候,从高往低分配.
  2. 比较运算符可以判断两个指针指向的地址谁在高字节谁在低字节. >,>=,<,<=
  3. 也可以用 ==、!=来判断两个指针指向的地址是不是同一个地址.
int* p1 = &num;
int* p2 = p1;
这个时候 p1,p2都指向同一个变量.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值