博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C语言---指针 & 指针数组偏移 const(C++的常量折叠)
阅读量:3922 次
发布时间:2019-05-23

本文共 4434 字,大约阅读时间需要 14 分钟。

非法指针并不只是未分配的内存,而包括所有已经不能访问的内存,例如,指向已经返回的函数局部变量,越过数组边界的地址等。

1、数组指针和指针数组

//“[]”(后缀运算符,1级) >  指针取值*(一元运算符,2级)1、int *p1[10];	≈	int*  (p1[10]) 【内容是int*的数组p1[10]】   					指针数组(储存指针的数组)原型定义:int* point[10]2、int (*p2)[10];  	理解为指针*p2→int[10]      指向数组的指针*p2					数组指针(指向数组的指针)原型定义:int (*)[10] 3、int* p();		返回值为int型指针的函数指针p4、int **p			5、int *p=NULL;		空指针:没有定位内存的指针,值为null(0)没有访问权限      			这就提醒别人不要对这个指针进行解引用的操作

指针/数组的类型和偏移(类型决定偏移)

int b[2][5]={
{
1,2,3,4,5},{
6,7,8,9,10}};//&b的类型是 int(*)[2][5] 故&b+1是按照int(*)[2][5]的长度进行偏于int *p=(int *)(&b+1); *p👉b[2][0]显然越界了cout<<*(p-3)<

二维数组++/二重指针:++意味着换下一行

int a[3][3]={
{
1,2,3},{
4,5,6},{
7,8,9}}; foo(a);void foo(int b[][3]) 最初二维数组b[0][0]指向数组a[0][0]{
++b; 执行++b后,b[0][0]指向a[1][0] b[1][1]=9; b[1][1]就是a[2][1],b[1][1]=9即a[2][1]=9}

一维数组++/指针:下一个成员

#include
#include
int main(){
char a[10] = {
1,2,3,4,5,6,7,8,9,10 }; //类型char* //数组名:a 类型是cha* +1时按照char偏移 //数组首地址:&a[0] 类型是cha* +1时按照char偏移 //&a 类型是char(*)5]数组指针 +1时按照char[5]偏移 //char (*p)[5] = &a; 类型是char(*)5]数组指针 +1时按照char[5]偏移 //char *p = a; 类型是char* +1时按照char偏移 //char (*p)[5] = a; char*类型的值不能用于初始化char (*)[5] printf("数组a的首地址:%p\n", a); printf("a偏移:%p\n", a + 1); printf("首元素a[0]地址:%p\n", &a[0]); printf("首元素&a地址:%p\n", &a); //char(*p5)[5] = a; //char*类型的值不能用于初始化char (*)[5] char *p = a; //类型char* printf("%d\n", *p); //打印:1 此时p→a[1]=1 printf("后:%d 前:%d\n", *++p, *++p); //打印:后:3 前:3 此时p→a[3]=3 两个前缀++全部在入栈前生效 printf("%d\n", *p++); //打印:3 printf后执行++,故p→a[4]=4 *p++ == *(p++) 后缀++(后缀运算符,1级) 取值*(一元运算符,2级) printf("%d\n", *p); //打印:4 作证了上一行:后缀++的执行会放到整条语句结束后 printf("%d, %d\n", ++*p, *p); //打印:5,5 前缀++与所有数据入栈前生效 printf("%d, %d %d\n", ++*p, *p,*p++); //6 6 5 printf("%d\n", *p); //6 printf("%d, %d %d\n", *++p, *p, *p++); //7 7 6 printf("%d\n", *p); //7 //char *p2=(char*)a; //printf("%d",(int)strlen(p)); char ch; scanf_s("%c", &ch); return 0;}
1级运算符:后缀++为后缀运算符(1级)			从左向右2级运算符:前缀++和*均为一元运算符(2级),从右向左*p++、(*p)++、*++p、++*p 的区别int a[5]={
1,2,3,4,5};int *p = a; 类型是char* +1时按照char偏移*p++ ≈ *(p++) 先取指针p指向的值(数组第一个元素1),再将指针指向自增1【从指向a[0]变为指向a[1]】; cout << *p++; // 结果为 1 cout <<(*p++); // 1(*p)++ 先取指针p指向的值(数组第一个元素1),再将该值自增1(数组第一个元素变为2 cout << (*p)++; // 1 cout <<((*p)++) //2*++p 先将指针p自增1(此时指向数组第二个元素),* 操作再取出该值 cout << *++p; // 2 cout <<(*++p) //2++*p 先取指针p指向的值(数组第一个元素1),再将该值自增1(数组第一个元素变为2) cout <<++*p; //2 cout <<(++*p) //2

=两侧类型必须一致

int a[4]={
1,2,3,4};int *ptr=(int*)(&a+1);printf("%d",*(ptr-1)); //*(&a)=a[0] *ptr=*(&a+1)==a[5] *(ptr-1)=a[3]  1、a的类型是int * ++表现为:后一个成员(一维数组)or 后一行成员(二维数组)  2、&a[0]的类型是int *   指针  3、a[0]的类型是int  +1表现为数值+1 int  4、&a的类型为int(*)[?] 以数组a[]的长度偏移 数组指针  5、ptr的类型是int* 以int=4字节偏移 指针若int *p1,*p2,m=5,n;则*p2=*p1; 错误 因为p2没有初始化(会存放任意的之前残留的地址,会报错,相当于野指针)【p2指向的值有了 但是p2指向的地址没有 无法把*p1存储起来】

①struct STRUCT p ,则p+1表示向右偏移sizeof(STRUCT)

② (int)p + 1则按照新类型int进行偏移
视作int
 偏移一个int长度,比如:地址1000→地址1004
③(int)p + 1则按照新类型int*进行偏移
  视作int 并增加1,如数据1000→数据1001

#include
int main(){
//=两侧类型必须一致 int a[5]={
1,2,3,4,5}; //a和&a[0]的类型是int * 只能赋值给int * 【类型必须一致】 //&a的类型是int(*)[5] 只能赋值给int(*)[5] 【类型必须一致】 int *p1=a;  或者   int *p2=&a[0]; //=两侧类型都是int * a+1、&a[0]、p1、p2均按照类型int *的长度+1 int (*p3)[5]=&a; //=两侧类型都是int (*)[?] &a、3均按照类型int (*)[?]的长度+1//=两侧类型如果不一致→则需要强制类型转换【但是还是按照各自当前的类型偏移】int *ptr=(int *)(&a+1);//右侧&a的类型是int(*)[5] +1表示增加int(*)[5] 的长度【后转化为int *】//左侧ptr 的类型是int * 则ptr的+1 -1等都是按照int *类型变化 //int *ptr2=a+1;//则指针p指向数组a的第二个元素 即a[5]的第二个元素地址 //int *ptr2=(int *)a+1; //int *ptr2=(int *)(a+1);//这2行的(int *)有没有都一样,强制类型转换成自己没有任何区别 return 0;}

在这里插入图片描述

(++p) ->n

(a+1) ->n
(p+1) ->n 这3个均对应结构体a[1] 对应5

1、指针和const修饰

const的修饰目标:

1、修饰int(形式:const int 或者int const)   效果:变量数值不能变
2、修饰指针*p(形式:*const p)       效果:指针指向的变量不能变(指针指向固定内存地址) 
                          声明时必须初始化,不然固定指向NULL就很蠢

1、const int *p; ≈≈ int const* p;		指向整形常量 的指针,它指向的值不能修改		示例:	const char* name=" chen " ; 				常量指针(指向常量的指针)			name[3]='q';错误				常量内容不可修改,指向可以修改			name="lin";正确2、int * const p;		指向整形的常量指针 ,它不能在指向别的变量,但指向(变量)的值可以修改。 3、int const * const p; ≈≈ const int * const p;	指向整形常量的常量指针。它既不能再指向别的常量,指向的值也不能修改。

#include 
using namespace std; int main(void) {
const int a = 10; int * p = (int *)(&a); *p = 20; cout<<"a = "<
<<", *p = "<<*p<

2、指针在函数中的使用实例

转载地址:http://tyhrn.baihongyu.com/

你可能感兴趣的文章
阿星Plus:基于abp vNext开源一个博客网站
查看>>
写给自己,2020的年终总结
查看>>
Flash 生命终止,HTML5能否完美替代?
查看>>
ML.NET生成器带来了许多错误修复和增强功能以及新功能
查看>>
微信适配国产操作系统:原生支持 Linux
查看>>
我的2020年终总结:新的角色,新的开始
查看>>
C# 9 新特性 —— 增强的模式匹配
查看>>
ASP.NET Core Controller与IOC的羁绊
查看>>
如何实现 ASP.NET Core WebApi 的版本化
查看>>
探索 .Net Core 的 SourceLink
查看>>
AgileConfig-如何使用AgileConfig.Client读取配置
查看>>
【gRPC】 在.Net core中使用gRPC
查看>>
整合.NET WebAPI和 Vuejs——在.NET单体应用中使用 Vuejs 和 ElementUI
查看>>
“既然计划没有变化快,那制订计划还有个卵用啊!”
查看>>
C#实现网页加载后将页面截取成长图片
查看>>
C# 在自定义的控制台输出重定向类中整合调用方信息
查看>>
【gRPC】ProtoBuf 语言快速学习指南
查看>>
C# 9 新特性 —— 补充篇
查看>>
Asp.Net Core使用Skywalking实现分布式链路追踪
查看>>
浅谈CLR基础知识
查看>>