C语言-指针1(基础,原理,详细)

C语言-指针1(基础,原理,详细) 目录一了解内存和地址二指针变量1指针变量的表示和大小1指针变量的创建和使用2指针变量的大小2解引用操作符(*3不同指针变量的意义1指针解引用2指针加减整数4特殊指针:void*5const修饰指针1const修饰的常变量2const修饰的指针变量三指针运算1指针-整数2指针-指针3指针的关系运算四野指针1指针未初始化2指针越界访问3指针指向的空间释放4规避野指针五assert断言六指针的使用和传址调用1模拟实现strlen函数2传值调用和传址调用补充进制转化1任意进制转化为十进制2,十进制转化为2进制3二进制转化为 8进制和16进制一了解内存和地址再引出指针前我们要先了解一下计算机的内存和地址。在计算机中内存有8GB/16GB/32GB等等这些内存被分为一个个的内存单元。一个内存的大小为1字节),一个字节就是8个比特位。其中每个内存单元都有一个编号这个编号就是内存的地址也是指针。编号地址指针在VS编译器中有两中环境一种是X64,表示64位的环境另一种是X86,表示的是32位的环境。以X86(32位)的环境为例子在32位的环境中内存都为32位的二进制只不过为了方便表示转化为16进制进行表示。细节分析在电脑中有32根地址线每根地址线有两种状态分别是有无电信号脉冲1/0这32根地址线就可以产生2^32中情况对应着二进制地址中每一位。于是就可以产生2^32种地址存储内容与int的可能取值相同类似在64位环境下地址有2^64种取值可能。补充在栈上开辟空间是由高地址向低地址开辟在数组上开辟空间是由低地址向高地址处开辟。二指针变量1指针变量的表示和大小1指针变量的创建和使用int a 10;int* p a; //p为指针变量补充若a为char类型则p前面的类型为char*其他同理分析//为取地址操作符 a就是a在内存中分配的地址传给了指针变量p.注意由于使用 int创建了4个字节的空间而每个字节都用对应的内存编码这里a表示四个地址中最小的地址。//int*为p的类型 *表示p为一个指针变量int表示p所存地址的对象为一个整型。2指针变量的大小指针的大小取决于地址的大小32位平台下地址是32个bit位 即4个字节 64位平台下 地址是64个bit位即8个字节2解引用操作符(*int a 10;int* p a;*p 5;printf(%d\n,a);执行结果5分析说明*p就是a变量。*p表示p指向的对象。3不同指针变量的意义1指针解引用x8632位环境下在计算机的存储当中有大小端存储模式小端低位字节存放低地址高位字节存放高地址大端高位字节存放低地址低位字节存放高地址而VS下的不论是x86还是x64环境都使用的是小端存储模式11位于高位字节地址就比较高由上图可知*ps将n的内容全部转化为0而*pi只将最后一位转化为0本质上是ps是int*类型的指针变量可以访问4个字节而pi是char*类型的指针变量只可以访问1个字节。2指针加减整数由上图可知由于int类型占4个字节int*类型1后直接跳过了4个字节而char只占1个字节char*类型1只跳过了 1个字节。这就是不同指针变量类型带来的差异。指针的类型决定了走一步的大小。4特殊指针:void*void*指针为无具体类型的指针或者叫做泛用指针这种地址可以用来接收任意类型的地址。但是也有局限性void*指针不能进行解引用和指针加减整数。原因void没有指定类型导致在解引用时无法确定访问的字节数同理在进行加减整数时无法确定跳过的字节数。作用void*指针一般使用在函数参数部分用来接收不同类型数据的地址。5const修饰指针1const修饰的常变量上述操作只锁住了a变量但是没有锁住a变量的地址要想让a的值彻底不能修改需要即使让p拿到了地址也不能修改a的值。如何才能实现此操作呢由此我们引入const修饰的指针变量2const修饰的指针变量3种形式1int* const pa;2int const *p a;3,int const * const p a;注意p的三个内容1p表示a的地址 2*p表示a的值 3p还有自己的地址p这三种形式表示不同的含义总结在const后面的内容不可改变。三指针运算指针运算有三种分别是1指针-整数2指针-指针3指针的关系运算1指针-整数int a 10;int* p a;(type)*p:跳过的sizeof(type)取决于*p前的类型p1p1*sizeof(type)pnpn*sizeof(type)指针-整数的运用打印数组中的每一个元素2指针-指针指针整数 指针故指针-指针整数整数为两个指针之间的元素个数可以为正也可以为负。展示2利用指针-指针得到字符串的长度注意没有指针指针的形式这是一种没有意义的形式3指针的关系运算指针的关系运算就是比较指针的大小即比较地址的大小运用当p的地址小于arrsz时就一直执行。四野指针野指针就是指针指向的位置是不可知的随机的不确定的没有明确限制的造成野指针的三种情况1指针未初始化2指针越界访问3指针指向的空间释放4规避野指针1指针初始化如果知道指针明确指向哪里就赋值如果不知道指针指向哪里就给指针初始化为NULL。NULL是C语言规定的一个标识符常量值为0也就是说地址为零不可以进行使用。2小心数组越界不能超出数组的访问范围3,避免返回局部变量的地址五assert断言语法assert(表达式 )若表达式的执行结果为1则继续往下执行若表达式的 执行结果为0则终止报错,并显示错误信息断言失败表达式以及在哪个文件下哪一行。注意assert断言使用时必须包含头文件#include assert.h使用assert的好处使用assert不仅可以在出错误时显示出错误的信息还可以随时对assert断言进行开启和关闭。如果不需要断言时在#include assert.h的前面输入#define NDBUG运用1判断是否为空指针2表达式判断assert断言失效如果想要重新开启assert对#define NDEBUG进行注释或删除即可。assert的唯一缺点是由于引入了assert,会增加程序的运行时间。注意assert断言只能在Debug中使用不能在Release中使用在Release中会直接失效。六指针的使用和传址调用1模拟实现strlen函数分析strlen的返回值类型是size_t,表示无符号的整型。使用int也可以)通过使用const和assert断言使得代码的健壮性得到了提高。2传值调用和传址调用利用函数实现对两个整数的交换1传值调用分析函数执行前后a,b的值并未交换原因a和b向函数传入的只是两个数值x和y接收的也仅仅是两个数。x和y在函数内进行了交换。出函数时销毁无意义。a和b并未和x,y建立真正的联系。这种情况称为传值调用。2传址调用分析通过传地址的形式使得a,b和x,y建立了真正的联系。通过对地址内值的修改实现了交换。总结实参传给形参时形参时实参的一份临时拷贝对形参的修改不会改变实参。补充进制转化1任意进制转化为十进制公式每一位的数字*该进制^(位数-1次幂) 对此求和例如十六进制ee 转化为10进制数15*16^(2-1)15*16^(1-1)2552,十进制转化为2进制例如1253二进制转化为 8进制和16进制由于8进制的每一位的范围为0~7而二进制三位000到111的范围刚好是0~7于是一个八进制为和三个二进制位进行匹配。步骤将二进制从后往前每三个一组进行划分将每一组的数字按照十进制转化并填写到8进制内转化为16进制的原理和步骤与上述转化为8进制的步骤异曲同工