C语言---指针的运算和各种类型的指针

指针的运算

1.指针+1或者指针-1是什么意思?

把指针中记录的内存地址,往后或者往前移动一个步长

2.什么是步长?跟什么有关?

跟数据类型有关

Windows64位操作系统:

char:移动一个字节

short:移动两个字节

int:移动四个字节

long:移动四个字节

long long:移动八个字节

有意义的操作 :

指针跟整数进行加、减操作(每次移动N个步长)

指针跟指针进行操作(间隔步长)

无意义的操作:

指针跟整数进行乘除操作

指针和指针进行加、乘、除操作

原因:此时指针指向不明

指针运算案例

前提:保证内存空间是连续的

#include<stdio.h>
main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9};
    int* p1 = &arr[0];
    int* p2 = &arr[5];
    printf("数组的0索引对应的元素是:%d\n",*p1);
    printf("数组的1索引对应的元素是:%d\n",*(p1+1));
    printf("arr[5]和arr[0]之间的间隔步长为:%d\n",p2-p1);
    printf("%p\n",p1);
    printf("%p\n",p2);
    return 0;
}

指向不明的指针

1.野指针

(指针指向的空间未被分配): 获取到的数据是其他程序的数据 (外挂的基本原理)

#include<stdio.h>
main()
{
​
    int a = 10; 
    int* p1 = &a;
    int* p2 = p1+10;    //将p1的内存地址加10个步长后的地址赋给p2  但p2是一个未被分配的内存地址
    printf("%p\n",p1);
    printf("%d\n",*p1);
    printf("%p\n",p2);
    printf("%d\n",*p2);
    return 0;
}
​
2.悬空指针

(指针指向的空间已分配,但被释放了)

#include<stdio.h>
int* test();
main()
{
    int* p3 = test();  //函数结束后内存空间被释放,里面的变量也被释放
    printf("%p\n",p3);
    printf("%d\n",*p3);
    return 0;
}
int* test()
{
    int a = 10;
    int* p = &a;
    return p;
}

void类型的指针

优点:

可以接收任何类型指针记录的内存地址

缺点:

无法获取其中的数据,也无法对其进行加、减计算

代码案例
#include<stdio.h>
void swap(void* p1,void* p2,int len);
int main()
{
    int a = 10;
    int b = 13;
    swap(&a,&b,sizeof(int));
    printf("a:%d   b:%d",a,b);
    return 0;
}
//函数:用于交换两个变量记录的数据
//使用viod型指针,提高函数通用性,任何数据类型的数据都可以进行交换
void swap(void* p1,void* p2,int len)    //定义两个viod指针来接受传递的内存地址,定义len接收外部数据的占用字节长度
{
    int i;      
    int temp = 0;
    //把void类型指针转成占用字节长度为一的char型,用于后面的字节级转换
    char* pc1 = (char*)p1;          
    char* pc2 = (char*)p2;
    //循环每一个字节进行交换
    for(i = 0;i < len;i++)
    {
        temp = *pc1;
        *pc1 = *pc2;
        *pc2 = temp;
        pc1++,pc2++;    //交换完后,进行下一个字节的交换
    }
}

多级指针

含义:

指向指针的指针

作用:

多重指针可以操作它指向的指针中的内存地址

代码案例

逻辑如下

int ** pp = p

其中的int*是p的变量类型; *是标记这是个指针变量

当使用多重指针时

*pp = &b

*是解引用运算符,代表解一次,所以此时就是p,而p保存的是内存地址,所以就代表把p的内存地址改为p的内存地址

**pp

解两次,解1次是p,p保存的是内存地址,再解一次就解成了b,b保存的是具体的值,所以此时就是输出b的值

#include<stdio.h>
int main()
{
    int a =10;
    int b =20;
    //定义指针保存变量a的内存地址
    int* p = &a;
    //定义指针保存指针变量p的内存地址
    int** pp = &p;
    //把p中的内存地址修改为为b的内存地址  
    *pp = &b;
    printf("a的内存地址为:%p\n",&a);
    printf("b的内存地址为:%p\n",&b);
    printf("指针p的内存地址为:%p\n",p);
    printf("指针pp的值为:%d\n",**pp);
    return 0;
}

数组指针

获取数组的指针,实际上是获取数组的首地址

代码案例

#include<stdio.h>
int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9};
    int length = sizeof(arr) / sizeof(arr[0]);
    int* p = arr;       //获取数组首地址
    //int* p = arr[0];    这行代码和上面效果一样
    int i;
    for(i = 0;i < length;i++)
    {
        printf("%d ",*(p+i));//*(p+i):首地址也就是0索引的元素,获取完0索引元素后,地址往后移一位就是1索引,以此类推
        
    }
    printf("\n");
    return 0;
​
}
数组指针的细节

arr参与计算的时候,会退化为第一个元素的指针

特殊情况:

sizeof 运算的时候,不会退化,arr还是整体

&arr获取地址的时候,不会退化,步长:数据类型*数组长度

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值