原创:C/C++语言 您所在的位置:网站首页 c语言point怎么定义 原创:C/C++语言

原创:C/C++语言

2023-10-06 00:40| 来源: 网络整理| 查看: 265

因为我觉得学习C语言最重要的知识点之一就是指针,可是无论对于新手还是有一定经验的人来说,指针的理解还是不够系统的,于是结合我个人见解写出了这么一份代码形式的笔记,读者可以自行探究加深理解和记忆。

此篇文章经过几年很多次的修改,个人觉得足够完善了,如有疑问欢迎联系作者本人一起探讨学习~,尊重作者的劳动,转载请记得注明来源:http://www.cnblogs.com/weifeng727/p/5584151.html

 

1 /*---------------------------------------- 2 指针练习(精华) 3 4 1)首先,要理解变量或数组的首地址,指的就是存放数据的RAM或ROM中地址号最小的那个字节地址。 5 6 2)指针前面的类型说明符,具有2重意义(既决定了对一级指针进行解引用时,将会操作的字节数,以及对一级指针进行算术运算时,会跳转的地址个数)。 7 ①决定了指针加一时,指针会跳转多少个地址, 8 例如: 9 如果指针是 10 char类型的,(指针+n) 指针会跳转n*1个地址。 11 int 类型的,(指针+n) 指针会跳转n*2个地址。 12 long类型的,(指针+n) 指针会跳转n*4个地址。 13 14 ②并且还决定了通过指针操作地址值时,实际上会返回多少个字节的值,且地址号大的字节先返回。 15 例如: 16 假设要操作指针的一次地址返回值,那么如果指针是 17 char类型的,返回1个字节。 18 int 类型的,返回2个字节。 19 long类型的, 返回4个字节。 20 21 数组前面的类型说明符,同样具有2重意义,且跟上面的很相似。 22 例如: 23 #include"stdio.h" 24 int c[]={0x1234,0x5678}; 25 void main() 26 { 27 printf("%p %d\n",c,*c); //数组是int类型意味着返回2个字节 28 printf("%p %d\n",(c+1),*(c+1)); //实际上(c+1)与c是夹着一个地址,因为数组类型符号是int,如果数组类型是long,则夹着3地址 29 } 30 31 也就是要注意类型所占的字节数,还有就是什么时候该看数组类型符号或者指针类型符号。 32 3)&叫取首地址符号,*叫解引用符号。 33 34 4)数组名是指一个首地址,所以,point=a(point是一个指针,a是一个数组名), a的前面不需要加&符号。 35 变量名指的是一个值,a[1]指的也是一个值,这些值包含着一个或多个字节,在想要让指针指向这些值的字节的地址时, 36 需要在变量名以及a的前面加上&符号,即意思是要让指针赋值符号(=)右边的东西是地址。 37 38 5)数组或变量的数据是一个一个字节的存放的,而且字节的地址是呈现连续的,赋值的时候,从左到右看 39 越往右,字节的地址号越大。因此,对于多字节数据类型的数组而言,看起来有种“首尾相连”的效果, 40 因为一个元素的最低位字节其地址的加一地址对应的字节,就是下一个元素的最高位字节。 41 42 简单点来说就是低地址存放高字节,这种现象称为大端排列(常用单片机)。注意:有些时候则是低地址存放低字节,这种现象称为小端排列(ARM)。 43 44 6)指针可分为:函数指针,数组指针(多维指针),变量指针,结构体指针。 又可分为:多级指针,多维指针。 地址可分为:多级地址,多维地址。 45 46 7)只有字符数组的最后一个元素会紧接一个隐藏元素,该元素值为0,映射的字符为“\0”。 47 48 8)数据指针型函数,也叫指针函数(即返回值是一个地址)。 49 50 9)char (*p)[2]; //声明一个1维指针(也叫1维数组指针) 51 分析方括号([])对多维指针的操作时,要遵循一个原则:先明确指针的维数,再分析有多少组方括号,方括号里面的数字是多少,由此得到地址是如何跳转的; 52 然后根据方括号的组数得知地址最终会发生多少次的解引用,如果解引用的次数少于地址的维数, 53 那么最终得到的还是一个地址,也如果解引用的次数等于地址的维数+1,那么得到是一个数据值。 54 每次对多维地址进行一次解引用后,地址的维数将会变小。 55 一维数组名就是一个一级0维地址,二维数组名就是一个一级1维地址,多维数组名就是一个一级多维地址。每一个数组名都是一个地址。这些地址是固定的。 56 一级多维指针的特点是:解引用的写法很特殊;运算时地址的跳转很特殊。 57 探究代码如下: 58 int Array[2][3][2]={{{1,2},{3,4},{5,6}},{{7,8},{9,10},{11,12}}}; //Array是一个一级2维地址 59 60 printf("%d\n", Array); 61 printf("%d\n", Array[1]); //与上一行代码相比,发生了 3*2*4=24个地址 的跳转 62 printf("%d\n", Array[1][1]); //与上一行代码相比,发生了 2*4=8个地址 的跳转 63 64 printf("%d\n",*(Array[1][1]));//对0维地址进行1次解引用,得到一个数据值,为9 65 66 printf("%d\n",*(*(Array[1]))); //对1维地址进行2次解引用,得到一个数据值,为7 67 printf("%d\n",*(Array[1])); //对1维地址进行1次解引用,得到的是一个0维地址,且与Array[1]值一样,但Array[1]是一个1维地址 68 69 10) #include 70 #include 71 int main() 72 { 73 74 //下面是存在着非法读写的演示,虽然非法读写是可以实现,但是这只能存在于同一个进程里面,而且这种情况没有什么有利的实际意义 75 76 int *p; //int类型指针,操作4个字节 77 p=(int *)malloc(2); //向堆申请了2个字节,但不进行初始化,calloc方式的申请会进行初始化 78 if(p) 79 printf("Memory Allocated at: %p\n",p); 80 else 81 printf("Not Enough Memory!\n"); 82 printf("%x\n",*p); //由于只申请了2个字节,所以非法读取了2个字节 83 *p=0x12345678; //由于只申请了2个字节,所以非法写入了2个字节 84 printf("%x\n",*p); //由于只申请了2个字节,所以非法读取了2个字节 85 free(p); //释放堆中申请过的2个字节,并且有可能把内存中的值也清0,这要取决于运行的内核 86 //下面是非法读写了4个字节 87 printf("%x\n",*p); 88 *p=0x87654321; 89 printf("%x\n",*p); 90 return 0; 91 } 92 93 11)经探究发现,不同类型的指针指向的地址跟指针类型不一致时,有可能会报错,也有可能只是警告而已 94 95 12)unsigned char (*q)(); //声明一个函数指针 96 指针形式调用函数时不给定传递参数值的话,默认是传递-1 , 指针调用函数的格式为:"(*指针名)(形参列表)" 或 "指针名(形参列表)" 97 98 13)一级和多级指针的使用: 99 int val=0x1122; 100 char *p3=&val; 101 char **p2=&p3; 102 103 printf("%x\n", p3); 104 printf("%x\n", p3+1); //跳转1个地址(因为p3是个一级指针而且类型修饰符为char) 105 106 printf("%x\n", *(p3)); //操作1个字节(因为p3是个一级指针而且类型修饰符为char) 107 printf("%x\n", *(p3+1));//操作1个字节(因为p3是个一级指针而且类型修饰符为char) 108 109 printf("%x\n", (p2)); 110 printf("%x\n", (p2+1)); //跳转4个地址(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针) 111 112 printf("%x\n", *(p2)); //操作4个字节(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针) 113 114 14)对多级多维指针的探究: 115 //假设已经掌握对多级0维指针,和一级多维指针的使用 116 117 unsigned char (**p)[3]; //这是一个二级2维指针 118 int Array3[10]={0x804a0e0,0x55667788,2,3,4,5,6,7,8,9}; //之所以第一个元素设为0x804a0e0,是因为如果该值取的不当,下面对(*(*p))进行解引用的时候,有可能在程序执行时导致内核塌陷,看起来好像是程序语法错误,也就是说要保证解引用的指针是在正确范围内的 119 p=Array3; //Array3是一个一级1维地址,先让Array3转变为二级2维地址,再让二级2维指针p所指向 120 121 printf("%x\n", p); //原本p是一个二级2维指针,在这里p表示为一个二级2维地址 122 printf("%x\n", p+1); //发生4个地址的跳转(因为地址长度为4个字节),因为(p+1)是一个二级2维地址,也就是此行语句输出值比上一行语句大4 123 124 printf("%x\n", *p); //解引用得到4个字节的值,因为p是一个二级2维地址。*p 得到的是一个一级2维地址 125 printf("%x\n", (*p+1)); //跳转3个字节,因为 *p 属于一级2维地址,也就是此行语句输出值比上一行语句大3。因为一级指针地址的跳转,是取决于维数,*p是一个一级2维地址,那么跳转数为:sizeof(unsigned char)*[3]=3 126 127 printf("%x\n", *(*p)); //对一级2维地址(*p)进行解引用,得到一级1维地址*(*p) 128 129 printf("%d\n", *(*(*p))); //对一级1维地址*(*p)进行解引用,得到1个字节的值,值为0xe0也就是224,因为指针 p 的类型修饰符为char,而sizeof(unsigned char)=1 130 131 printf("%d\n", *(*(*p))+1); //该行打印值比上一行大1,为225 132 133 //总结:对多级多维指针进行解引用的时,每次解引用都会遵循先降级再降维,当级数没降到1,那么维数不起作用。 134 // 当已经是一级指针了后,维数起作用,当做一级多维指针或一级1维指针处理 ,一级1维地址再解引用就得到值了 135 136 15)指针常量和常量指针 137 int a =3; 138 int b = 1; 139 int c = 2; 140 int const *p1 = &b;//const 在前,定义为常量指针 141 int *const p2 = &c;//*在前,定义为指针常量 142 //常量指针p1:指向的地址可以变,但内容不可以重新赋值,内容的改变只能通过修改地址指向后变换。 143 //p1 = &a是正确的,但 *p1 = a是错误的。 144 //指针常量p2:指向的地址不可以重新赋值,但内容可以改变,必须初始化,地址跟随一生。 145 //p2= &a是错误的,而*p2 = a 是正确的。 146 147 16)假设a是数组名,p是指针名,那么p=&a等效于p=a 148 int abc[4]={1,2,3,4}; 149 int (*p)[4]; 150 p=abc; //等效于p=&abc; 151 for(i=0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有