指针详细讲解(上)

目录

一、指针的变量、内存和地址

1、内存和地址

2、指针的变量和地址

二、指针变量类型的意义和使用

1、指针的解引用

2、指针运算

(1)指针+-指针

(2)指针-指针

3、void*指针

三、野指针

1、野指针成因

2、如何避免野指针

四、const修饰指针变量以及如何使用断言

1、const修饰变量

2、const修饰指针变量

3、assert断言


一、指针的变量、内存和地址

1、内存和地址

        我们所写的变量,数组这些值都需要开辟空间来存储,而这个空间我们也叫内存,如图:

        每一个内存里面有许多的内存单元的比那好,也成为地址,在c语言中也叫指针,而一个内存单元大小取1个字节,不同的变量类型取不同的地址大小,例如:int类型取四个字节,char类型取一个字节,值得注意的是,*(任意)类型在x86环境都是取四个字节,在x64环境取八个字节;一个字节也包含着八个比特位(二进制)。

        补充(单位换算):

        1 byte  = 8 bit;

        1 KB = 1024 byte;

        1 MB = 1024 KB;

        1 GB = 1024 MB

        1 TB = 1024 GB;

        1 PB = 1024 TB;

2、指针的变量和地址(&和*的使用)

        &(取地址操作符)可以快速查找该变量的地址

        

#include<stdio.h>
int main()
{
	int a = 0;
	&a;
	printf("%p\n", &a);
	return 0;
}

        运行结果如下:,而这个地址只是a的首元素地址,而它的内存不止这么一点,而他的内存单元是连续存放的,而int占四个字节,所以a的实质地址在006FF28~006FF82C;

        对于指针*解引用,主要是和内存配套的,下面举个例子:

int a=10;
int *pa=&a;

        我们发现pa的类型是int*,*说明pa是指针变量,而int则说明pa只想的是整形(int)类型的对象;

        pa指向的是a的首元素地址,而*pa对a的首元素地址进行解引用,从而找到a的值是10;

二、指针变量类型的意义和使用

1、指针的解引用

int main()
{
    int n=0x12345678;
    int x=0x11223344;
    int *p1=&n;
    *p1=0;
    char *pc=(char*)&n;
    *pc=0;
    return 0;
}

        对于这个代码,会全部变成0;而x只有前面俩个1变成0;那么为什么会这样呢?因为指针的类型决定了对指针解引用的时候有多大的权限,char*的指针每次只能访问一个字节,而int*指针的解引用就能访问4个字节;

        另外对于代码来说,一个字节占八个比特位,代码我们都是以十六进制来编写,所以每一个数字占四个比特位,而0x12345678一共占了32个比特位,也就是4个字节,所以*p1能将n全部变为0,而*pc一个字节只有八个比特位,也就只能把8/32变成0;

2、指针运算

(1)指针+-指针

        我们主要是为了观察地址的变化。

int main()
{
 int n = 10;
 char *pc = (char*)&n;
 int *pi = &n;
 
 printf("%p\n", &n);
 printf("%p\n", pc);
 printf("%p\n", pc+1);
 printf("%p\n", pi);
 printf("%p\n", pi+1);
 return 0;
}

        对于不同的指针类型+1都会跳过不同的直接,int*类型直接跳过4个字节,而char*类型跳过一个字节,当然,指针-1也是往回跳;

(2)指针-指针

        对于指针-指针,我们可以得出指针的地址单元差值;

        例如:

int my_strlen(char *s)
{
 char *p = s;
 while(*p != '\0' )
 p++;
 return p-s;
}
int main()
{
 printf("%d\n", my_strlen("abc"));
 return 0;
}

        我们可以返回该指针的长度;而这种找长度只对char有效,因为char只占一个字节;

3、void*指针

        在指针类型中有一种特殊的类型,也可以理解为无具体类型的指针,可以接受任意类型地址;

        局限性:void*类型的指针不能直接进行指针的+-整数和解引用的运算,不然系统会报错,会说因为类型不兼容;

三、野指针

1、野指针成因

        对于野指针的成因一共有三种,首先是指针未初始化;

int *p;

        指针未初始化的时候默认是随机值,它是不可预估的;

        第二种就是指针的越界访问,如下;

#include<stdio.h>
int main()
{
 int arr[10] = {0};
 int *p = &arr[0];
 int i = 0;
 for(i=0; i<=11; i++)
 {
 //当指针指向的范围超出数组arr的范围时,p就是野指针​
 *(p++) = i;
 }
 return 0;
}

        当我们对指针进行越界访问的时候,它也会形成一个野指针,是一种比较危险的行为;

        第三种则是指针指向的空间释放,已经被释放的指针,里面是没有存放值得,那么指针指向它得时候就也是随机值,如下:

#include <stdio.h>
int* test()
{
 int n = 100;
 return &n;
}
int main()
{
 int*p = test();
 printf("%d\n", *p);
 return 0;
}

2、如何避免野指针

        对于三种野指针得成因,我们都是有不同的办法去应对,对于未定义得指针,我们可以定义该指针,如果是不想指向任何一个值,我们可以设置为null值,如下:

#include<stdio.h>
int main()
{
    int num=10;
    int *p1=&num;
    int *p2=NULL
    return 0;
}

        而对于第二种我们可以避免越界,不越界的话就不会出现野指针;

        第三种我们如果不适用该指针变量得时候,及时设置NULL值,检查有效性,也能够避免

四、const修饰指针变量以及如何使用断言

1、const修饰变量

        const是用来限制变量的,也可以理解为把变量变为常量(不能被修改),例如:

int n=0;
n=20;
const int p = 0;
p=20;

        n是成功被修改的,而p没有被修改,而且会报错,因为const限制了变量,从而p变成常量不能被修改。

2、const修饰指针变量

        对于const限制指针变量可以分为俩部分,一部分是当*放在const左边的时候,限制的是指针指向内容,第二部分则是当*放在const右边的时候,限制的是指针本身。

char const *p;
char * const p;

3、assert断言

        assert断言需要包括头文件assert.h;

        assert()宏会接受一个表达式作为参数,返回值为真(返回值非0),assert()不会产生任何作用,程序继续运行,如果返回值为假,assert()会报错。对于代码的严谨性,assert()宏的断言还是十分有必要的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值