免费空间访客网站,求职网站开发,百度提交入口网址,建设增塑剂网站目录 1.什么是指针
2.指针变量和地址
1.解引用操作符
2.指针变量类型的意义
3.void*指针
4.const修饰指针
1.const放在*左边
2.const放在*右边
3.指针的运算
1.指针加减整数
2.指针减指针
3.指针比较大小
4.野指针
1.没有给指针变量初始化
2.指针指向的空间释放 …目录 1.什么是指针
2.指针变量和地址
1.解引用操作符
2.指针变量类型的意义
3.void*指针
4.const修饰指针
1.const放在*左边
2.const放在*右边
3.指针的运算
1.指针加减整数
2.指针减指针
3.指针比较大小
4.野指针
1.没有给指针变量初始化
2.指针指向的空间释放
3.指针越界访问
5.assert断言
6.传值调用和传址调用 1.什么是指针
在c语言中指针就是地址我们将内存中的空间划分成一个一个字节每一个字节都有自己的地址一个字节是8bit位 我们可以把地址看作一个宿舍的编号一个宿舍有8个同学通过这个宿舍的编号可以找到里面居住的同学
在32位机器上地址大小为32bit4字节
在64位机器上地址大小为64bit8字节
2.指针变量和地址
指针变量的形式
int a10;
int* paa;//指针变量 指针变量也是一种变量只不过它里面存的是地址同时只要将一个正整数存入里面他就会将那个数字看作是地址那么这种指针类型的大小是多少呢
我们知道如果是32位机器的话地址的大小一定是4字节那么int*的指针是否是4个字节呢 那指针变量有char*int*double*那么他们的类型又是多大呢
同时我们要知道地址的大小事4个字节那么无论是什么类型的地址它都是地址只要是地址在32位机器上就是4个字节在64位机器上就是8个字节 我们发现好像类型不相同大小好像都还是一样的那么我们指针变量还要有类型的区分呢
1.解引用操作符
我们取出地址是要去使用的那么如何去使用
指针操作中一个很重要的操作符解引用操作符 * 比如上面我们要去通过这个指针变量pa对它指向的对象进行操作
int main()
{int a 10;int* pa a;*pa 20;return 0;
} 解引用操作符的作用就是通过某个地址找到这块地址所属的空间
2.指针变量类型的意义
前面我们提到了既然类型不同但是大小还是一样那为什么还要有这么多不同的类型呢
这里我们先来看2组代码 我们通过内存观察发现指针的类型不同好像操作的范围也不同char*的指针只能操作一个字节int*的指针能操作4个字节
然后再让我们来看一组代码 我们发现刚开始pa和ps指向的都是a但是int*的指针加一从c4变成了c8char*的指针从c4变成了c5前面我们知道内存的每一个字节都是有自己的编号的那么是不是就说明int*的指针加一跳过了4个字节char*的指针跳过了个字节同理short*加一跳过2个字节减法也是同理
通过上面2个代码的演示我们可以总结2条指针类型的意义
1.指针类型决定了解引用操作进行访问的字节的最大权限所能操作的字节个数
2.指针类型决定了指针进行加一减一运算向前和向后的距离
3.void*指针
这种类型的指针是无具体类型的指针这种类型的指针无法进行加一减一的运算同时也无法进行解引用操作这种类型有点类型于一个大的垃圾桶什么类型的指针都能往里面装
我们知道等号2变的类型必须相等不然就会报错 但是void*的类型的指针就不会有这种报错 void*指针一般在函数里面用的比较多比如我们进行传参的时候我们也不知道我们传的是什么类型数据的地址这个时候我们就可以用void* 来接收这个地址这个我们后面再谈
4.const修饰指针
const是c语言的关键字可以用来修饰变量和指针它可以使变量具有常属性常量是不可修改的相当于使得我们无法对这个变量进行修改从语法形式上限制了我们 虽然我们从语法形式上限制了变量a但是我们可以通过地址来找a的空间并将它修改了这是非常不安全的 我们不想让这个指针变量通过地址来改变a就可以通过给指针变量前面加上const来修饰它
1.const放在*左边 const放在*左边是限制*pa如果是这样写int const* pa效果是一样的都是限制了*pa这样就不能通过地址来改变这个值了
2.const放在*右边 const放在右边就限制了pa所指向的对象不可修改但是可以通过地址来修改地址所指向的那块空间
总结
const如果放在*的左边修饰的是指针指向的内容保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。
const如果放在*的右边修饰的是指针变量本⾝保证了指针变量的内容不能修改但是指针指 向的内容可以通过指针改变。
3.指针的运算
1.指针加减整数
前面我们就提到了指针加减整数不同类型的指针加减整数向前和向后的距离不同比如char*的指针加一跳过一个字节int*的指针加一跳过4个字节 同理其他的类型也遵循这个规则
2.指针减指针
这种一般用于同一块空间中进行计算 数组名等于首元素的地址arr9说明此时指针变量指向了数组的最后一个元素指针减去指针计算的是指针之间的元素个数
3.指针比较大小
和数字一样地址之间也有大小之分
在数组中地址是由低到高变化的栈区上的地址是从高往低使用的
比较的方法和整数比较一样
int main()
{int arr[10] { 1,2,3,4,5,6,7,8,9,10 };int* p arr[0];int i 0;int sz sizeof(arr) / sizeof(arr[0]);while (p arr sz) //指针的⼤⼩⽐较{printf(%d , *p);p;}return 0;
}4.野指针 在我们使用指针的时候一定要正确的使用指针避免出现野指针那么野指针又是什么呢
准确来说野指针是没有明确的指向空间的可能那块空间并不属于你但是你通过野指针对那块区域进行操作那么野指针是如何形成的呢
1.没有给指针变量初始化
看过前面的栈区的创建和销毁那篇文章应该都知道我们在创建一个局部变量的时候如果不进行初始化里面放的就是cccccccc这种随机值如果将这种随机值放在指针变量中的话会默认将它看作是一个地址如果此时我们对这个地址进行加一减一解引用等操作这是很危险的那块空间并不是操作系统分配给我们的而是一个随机的地址
2.指针指向的空间释放
我们进行函数调用的时候在里面所创建的局部变量出了函数作用域都是会销毁的如果此时我们传回来了一个地址并且还用一个指针变量接收了这个地址 这里我们虽然能运行起来并且打印的结果还是对的是因为这个函数的栈帧空间没有被破坏如果我们在前面随便打印一个东西就会破坏栈帧空间打印的就不是那个结果了总而言之返回栈空间地址都是不对的
我们重点不在上面当函数运行结束之后函数的栈帧空间就会返回给操作系统此时pa虽然拿到了那块地址的编号但是并没有什么用这块空间已经不属于我们了此时pa就是野指针
3.指针越界访问 这里我们通过指针来访问数组的每一个元素并把i赋值给每一个元素当i10的时候此时指针已经指向了数组的外面此时指针就是野指针如果我们对这个地址进行操作就是对野指针进行操作这是很危险的
在用指针的时候我们自己要知道指针指向的地址是否是有效地址避免出现返回栈区地址指针越界访问等等问题在我们不使用指针或者指针指向的地址的空间被销毁的时候要及时将指针置为NULL空指针
5.assert断言
在使用指针的时候我们通常都会去判断指针指向的目标是否为NULL会去判断指针的有效性
assert.h 头⽂件定义了宏 assert() ⽤于在运⾏时确保程序符合指定条件如果不符合就报 错终⽌运⾏。这个宏常常被称为“断⾔”。 我们可以看到assert在报错的同时还会告诉我们出错的文件路径还要第几行出现的非常的好用同时在我们不使用的时候还可以关闭它
我们只需要在assert.h的头文件前面加上#define NDEBUG即可一定要在它的前面加上才有用
#define NDEBUG
#include assert.h
同时在Release版本会自动屏蔽assert断言 6.传值调用和传址调用
传值调用这个很好理解就是传的数值比如我们写的加法函数
int Add(int x, int y)
{return x y;
}int main()
{int a 10;int b 20;int ret Add(a, b);printf(%d, ret);return 0;
}
这个时候我们传递的是a和b的数值a和b是形参修改形参不会影响实参
传址调用就是传递地址有时候我们仅仅有传值调用是没办法完成我们的目的的比如设计一个函数让a和b的数值交换此时我们如果用传值调用的话是没法完成的其1是形参无法改变实参其二是函数的返回值有且仅有一个值这个时候我们缺的就是如何于主调函数的a和b建立联系这个时候就可以用传址调用
void Fact(int* pa, int* pb)
{int tmp *pa;*pa *pb;*pb tmp;
}int main()
{int a 10;int b 20;Fact(a, b);printf(交换之后%d %d, a, b);return 0;
}