指针(pointer)是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。
换句话说就是可以通过指针找到以它为地址的内存单元。
理解:内存图解。
指针是个变量,存放内存单元的地址(编号)。
int main(){ int a = 10;//在内存中开辟空间存储 int* p = &a;//先对变量a取出它的地址,可以使用&操作。 //将a的地址存放在p变量中国,p就是一个指针变量}
小结:指针就是变量,内容是地址。(存放在指针中的值被当做地址处理)
指针的大小
在32为计算机上指针大小4字节。在64为计算机上指针大小8字节。关于地址
printf("%p \n",&a);//%p地址格式 &a取a的地址
int* p = &a;//int*指针类型 //p 指针变量 //&a 取地址
使用
*p //解引用操作符int a =10; //在内存中存储10 还有char*等类型int* p = &a;//定义指针,位置为a的内存*p = 20; //更改指针指向内存的 值printf("a= %d",a);//结果为a=20
int* p的理解 p是int类型的一个指针(仅此而已),一般*p指向的也是一个int型的
int main(){ int n = 0x112233; char* p = (char*)&n; int* pi = &n; *pc = 0; //在调试韩语再见中文谐音的过程中观察内存的变化。 *pi = 0; return 0;}
int*; *p可以访问4个字节。char*; *p可以访问1个字节。double*; *p可以访问8个字节。
原因是类型本身所需的内存空间就是指针可以控制的空间。
意义:使用时选用合适的指针类型进行定义
int main(){ int a = 0x11223344; 郑一嫂 int* p1 = &a; char* p2 = &a; printf("%p\n",p1); printf("%p\n",p1+1); printf("%p\n",p2); printf("%p\n",p2+1); return 0;}
int类型时0c->10 变化4, char类型时0c->0d 变化1。
理解:指针加一不是指向下一个紧挨着的地址,是指向下一个指针变量对应的类型变量开始的地址。
意义指针类型决定了:指针走一步走多远(指针的步长)
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
1.指针未初始化
int main(){ int a;//局部变量不初始化,默认是随机值 int *p;//局部的指针变如果没有初始化,就被初始化为随机值。}int main(){ int a;//局部变量不初始化,默认是随机值 int *p;//局部的指针变如果没有初始化,就被初始化为随机值。}
2.指针越界访问
int main(){ int arr[10]; int *p = arr; for(int i = 0;i<12;i++){ p++; } //当指针的范围超出数组的范围时,p就是野指针。}
3.指针指向的空间释放
int main(){ int arr[10]; int *p = arr; for(int i = 0;i<12;i++){ p++; } //当指针的范围超出数组的范围时,p就是野指针。}
解析:在main函数调用test()时,进入test()函数,int a语句开辟临时的内存空间并将这个内存空间存储为10;返回函数的时候返回的临时的a的地址给*p,然后test函数已经在执行完test函数后结束,a的内存空间被销毁。这时的*p就是指向的地址正确但是内容已经改变。
将未知位置的值进行修改是非常危险的
如何避免野指针
1.指针初始化
2.小心指针越界
3.指针指向内存释放 即 指向null
4.指针只用之前检查有效性
指针运算
1.指针加减整数
2.指针-指针
3.指针的关系运算
指针加减指针
int main(){ int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int sz = sizeof(arr)/sizeof(arr[0]); int* p = arr; for(int i=0;i<sz;i++){ printf("%d ",*p); p = p+1;// p++ } int* p = &arr[9]; for(int i=0;i>0;i++){ printf("%d ",*p); p-=1;// p++ } return 0;}
指针-指针
int main(){ int arr[10]={1,2,3,4,5,6,7,8,9,10}; printf("%d",&arr[9]-&arr[0]);//输出9 中间元素的个数。 printf("%d",&arr[0]-&arr[9]);//输出-9 return 0;}
指针减指针必须是自己减去自己。否则结果不可预知。
指针实现strlen()
int my_strlen(char* str){ char* start = str; char* end = str; while(*end != 'int my_strlen(char* str){char* start = str;char* end = str;while(*end != '\0'){end++;} return ;}int main(){char arr[] = "hello";int len = my_strlen(arr);printf("%d\n",len);return 0;}'){ end++; } return ;}i李典nt main(){ char arr[] = "hello"; int len = my_strlen(arr); printf("%d\n",len); return 0;}
指针的关系运算
int main(){ float values[5]; for(float* vp=&values[5];vp>&values[0];){ printf("haha "); *--vp = 0; } return 0;}
这里碰到了两个问题 1. values[5]本身不属于数组的部分。但是可以使用。经测试values[5]不会警告,但是values[-1]及以下或values[6]及以上都会报错。2.指针的加减是类型位置的移动数组总也就是一个一个往过走。
for(float* vp高温=&values[5-1];vp>=&values[0];vp--){ printf("haha "); *vp = 0;}
这里在绝大多数的编译器上是可以顺利完成任务的,然而我们应该避免这第二种写法,因为标准不能保证他是可行的。
标准规定:允许指向数组元素的指针和指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个位置的指针进行比较。
int main(){ int arr[10]={0}; printf("%p\n",arr); //地址-首元素地址 printf("%p\n",&arr[0]);}
一般情况数组名都代表首元素的地址
除了:
1. &数组名 这时数组名代表整个数组的地址
2. sizeof(数组名) 这时也是代表整个数组。
将第一层指针1想成变量,再取这个变量的地址存为一个指针2。那么指针2指向指针1,指针1指向原变量。原变量的地址存在了指针1中,指针1的地址存在了指针2中。
int main(){ int a = 10; int* pa = &a; int** ppa = &pa;//ppa就是二级指针。 //存在三级及以上指针,(无限套娃)}
指针数组其实是个数组,数组指针是个指针
指针数组:存放指针的数组
int a = 10;int b = 20;int c = 30;int* arr[3] = {&a,&b,&c};//指针数组
数组指针:指向数组的指针。
main(){
int a 图书印刷= 10;
int* pa = &a;
int** ppa = &pa;//ppa就是二级指针。
//存在三级及以上指针,(无限套娃)
}
### 指针数组、数组指针指针数组其实是个数组,数组指针是个指针<u>**指针数组**</u>:存放指针的数组~~~cint a = 10;int b = 20;int c = 30;int* arr[3] = {&a,&b,&c};//指针数组
数组指针:指向数组的指针。
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注www.887551.com的更多内容!
本文发布于:2023-04-04 10:50:14,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/d6e72306a30fcbfcaaba8f1067671500.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:C语言指针的图文详解.doc
本文 PDF 下载地址:C语言指针的图文详解.pdf
留言与评论(共有 0 条评论) |