初阶指针补充

目录

野指针

野指针成因

如何避免野指针

指针运算

指针+-整数

指针-指针

指针的关系运算

指针和数组

数组首元素地址和数组地址的区别

二级指针

指针数组 


野指针

野指针就是指针指向的位置是不可知的(随机,不确定)

野指针成因

1.指针未初始

int *p;//P不初始化放的就是随机值,这块内存是不让你访问的
*p=20;

 2.指针越界访问

int main()
{
    int arr[5]={1,2,3,4,5};
    for(i=0;i<10;i++)
    {
        printf("%d",*p);
        p++;
    }
    return 0;
}

10次循环,前五次正常,后五次越界,越界访问p就是野指针

3.指针指向的空间释放

test()
{
    int a=10;
    return &a;
}
int main()
{
    int *p=test();
    *p=100;
    return 0;
}

test函数调用完后,a的空间销毁,p就变成了野指针

如何避免野指针

1.指针初始化(可以给具体地址,也可以给NULL)

p赋值成NULL((void*) 0)一般都是无法使用的,又避免了它成为野指针

我们通常把用不到的指针赋值成NULL

2.小心指针越界

3.指针指向空间释放就要置为NULL

4.避免返回局部变量地址

5.指针再使用之前要检测有效性

 

if(P!=NULL)
{
    
}

指针运算

指针+-整数

vlaues是5个元素的数组

下面的循环把每四个字节(每个元素)赋值成0

指针-指针

下面打印什么?

int main()
{
    int arr[10]={0};
    printf("%d\n",&arr[9]-&arr[0]);
    return 0;
}

结果是9

指针-指针(两个指针必须指向同一块空间) 得到的数的绝对值是指针和指针之间元素的个数

&arr[4]-&ch[3]//error

 

我们记得my_strlen的实现使用过

1.计数器的方法

2.递归

3.指针-指针

今天可以用指针-指针实现

int my_strlen(char *init)
{
    char *arr=init;
    while(*arr++)
    {
        ;
    };
    return arr-1-init;
}
int main()
{
    char arr[]="abcdef";
    int len=my_strlen(arr);
    printf("%d",len);
}

 

指针的关系运算

 

还是values数组,有5个元素

这个代码把values的每个元素都赋值为0,倒序

 

 

这个代码在vp=&values[0]的时候,对vp赋值后,vp就又会减1

此时vp指向的空间不属于数组,这种代码被认定是错误的

 

 

标准规定:允许指向数组的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较

,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较(也就是向前越界是不允许的,但是向后越界是可以的)

指针和数组

数组名是数组首元素的地址

但是有两个例外:

sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小

&数组名,数组名表示整个数组,取出的是整个数组的地址

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	printf("%d\n", sizeof(arr));

 

我们看个代码:

int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    int * p=arr;
    int sz=sizeof(arr)/sizeof(arr[0]);
    int i=0;
    for(i=0;i<sz;i++)
    {
        printf("%d",*(p+i));//p+i就是下标为i的数组元素地址
    }
}

 

可以看出数组名是int * 类型的指针,是数组首元素地址

数组首元素地址和数组地址的区别

int main()
{
    int arr[10]={0};
    printf("%d",arr);
    printf("%d",arr+1);//加了4个字节,arr是int * 的
    
    printf("%d",&arr[0]);
    printf("%d",&arr[0]+1);//加了4个字节,&arr[0]是int *的
    
    printf("%d",&arr);
    printf("%d",&arr+1);//加了40个字节,&arr是int(*)[10]的
}

 

 

二级指针

int a=10;
int *pa=&a;//*说明空间里存放的是指针,int说明存放的是int型指针
//pa指向的空间看成int
int* *ppa=&pa;//后一个*说明空间里存放的是指针,int * 说明存放的是int *型的指针
//ppa指向的空间看成int *

ppa就是个二级指针,里面存放pa的地址

pa里存放a的地址

*ppa=pa

*pa=a

所以* *ppa=a

指针数组 

int arr[5];//整型数组,存放整型的数组
char ch[6];//字符数组,存放字符的数组

所以指针数组,就是存放指针的数组,每个元素都是指针类型

每个元素都是指针

int a=1;
int b=2;
int c=3;
int d=4;
int e=5;
int* arr[5]={&a,&b,&c,&d,&e}

 

看段代码:

int main()
{
    int data1={1,2,3,4,5};
    int data2[]={2,3,4,5,6};
    int data3[]={3,4,5,6,7};
    int *arr[3]={data1,data2,data3};
    int i=0;
    for(i=0;i<3;i++)
    {
        int j=0;
        for(j=0;j<5;j++)
        {
            printf("%d",arr[i][j]);
        }
        printf("\n");
    }
}

 

 

arr就是一个指针数组,这个代码模拟实现了以恶搞二维数组,但并非真的二维数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

愿你生活有惊喜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值