对指针的学习总结
2018-06-18 04:20:41来源:未知 阅读 ()
1 1 /*---------------------------------------- 2 2 指针练习(精华) 3 3 4 4 1)首先,要理解变量或数组的首地址,指的就是存放数据的RAM或ROM中地址号最小的那个字节地址。 5 5 6 6 2)指针前面的类型说明符,具有2重意义(既决定了对一级指针进行解引用时,将会操作的字节数,以及对一级指针进行算术运算时,会跳转的地址个数)。 7 7 ①决定了指针加一时,指针会跳转多少个地址, 8 8 例如: 9 9 如果指针是 10 10 char类型的,(指针+n) 指针会跳转n*1个地址。 11 11 int 类型的,(指针+n) 指针会跳转n*2个地址。 12 12 long类型的,(指针+n) 指针会跳转n*4个地址。 13 13 14 14 ②并且还决定了通过指针操作地址值时,实际上会返回多少个字节的值,且地址号大的字节先返回。 15 15 例如: 16 16 假设要操作指针的一次地址返回值,那么如果指针是 17 17 char类型的,返回1个字节。 18 18 int 类型的,返回2个字节。 19 19 long类型的, 返回4个字节。 20 20 21 21 数组前面的类型说明符,同样具有2重意义,且跟上面的很相似。 22 22 例如: 23 23 #include"stdio.h" 24 24 int c[]={0x1234,0x5678}; 25 25 void main() 26 26 { 27 27 printf("%p %d\n",c,*c); //数组是int类型意味着返回2个字节 28 28 printf("%p %d\n",(c+1),*(c+1)); //实际上(c+1)与c是夹着一个地址,因为数组类型符号是int,如果数组类型是long,则夹着3地址 29 29 } 30 30 31 31 也就是要注意类型所占的字节数,还有就是什么时候该看数组类型符号或者指针类型符号。 32 32 3)&叫取首地址符号,*叫解引用符号。 33 33 34 34 4)数组名是指一个首地址,所以,point=a(point是一个指针,a是一个数组名), a的前面不需要加&符号。 35 35 变量名指的是一个值,a[1]指的也是一个值,这些值包含着一个或多个字节,在想要让指针指向这些值的字节的地址时, 36 36 需要在变量名以及a的前面加上&符号,即意思是要让指针赋值符号(=)右边的东西是地址。 37 37 38 38 5)数组或变量的数据是一个一个字节的存放的,而且字节的地址是呈现连续的,赋值的时候,从左到右看 39 39 越往右,字节的地址号越大。因此,对于多字节数据类型的数组而言,看起来有种“首尾相连”的效果, 40 40 因为一个元素的最低位字节其地址的加一地址对应的字节,就是下一个元素的最高位字节。 41 41 42 42 简单点来说就是低地址存放高字节,这种现象称为大端排列(常用单片机)。注意:有些时候则是低地址存放低字节,这种现象称为小端排列(ARM)。 43 43 44 44 6)指针可分为:函数指针,数组指针(多维指针),变量指针,结构体指针。 又可分为:多级指针,多维指针。 地址可分为:多级地址,多维地址。 45 45 46 46 7)只有字符数组的最后一个元素会紧接一个隐藏元素,该元素值为0,映射的字符为“\0”。 47 47 48 48 8)数据指针型函数,也叫指针函数(即返回值是一个地址)。 49 49 50 50 9)char (*p)[2]; //声明一个1维指针(也叫1维数组指针) 51 51 分析方括号([])对多维指针的操作时,要遵循一个原则:先明确指针的维数,再分析有多少组方括号,方括号里面的数字是多少,由此得到地址是如何跳转的; 52 52 然后根据方括号的组数得知地址最终会发生多少次的解引用,如果解引用的次数少于地址的维数, 53 53 那么最终得到的还是一个地址,也如果解引用的次数等于地址的维数+1,那么得到是一个数据值。 54 54 每次对多维地址进行一次解引用后,地址的维数将会变小。 55 55 一维数组名就是一个一级0维地址,二维数组名就是一个一级1维地址,多维数组名就是一个一级多维地址。每一个数组名都是一个地址。这些地址是固定的。 56 56 一级多维指针的特点是:解引用的写法很特殊;运算时地址的跳转很特殊。 57 57 探究代码如下: 58 58 int Array[2][3][2]={{{1,2},{3,4},{5,6}},{{7,8},{9,10},{11,12}}}; //Array是一个一级2维地址 59 59 60 60 printf("%d\n", Array); 61 61 printf("%d\n", Array[1]); //与上一行代码相比,发生了 3*2*4=24个地址 的跳转 62 62 printf("%d\n", Array[1][1]); //与上一行代码相比,发生了 2*4=8个地址 的跳转 63 63 64 64 printf("%d\n",*(Array[1][1]));//对0维地址进行1次解引用,得到一个数据值,为9 65 65 66 66 printf("%d\n",*(*(Array[1]))); //对1维地址进行2次解引用,得到一个数据值,为7 67 67 printf("%d\n",*(Array[1])); //对1维地址进行1次解引用,得到的是一个0维地址,且与Array[1]值一样,但Array[1]是一个1维地址 68 68 69 69 10) #include<stdio.h> 70 70 #include<stdlib.h> 71 71 int main() 72 72 { 73 73 74 74 //下面是存在着非法读写的演示,虽然非法读写是可以实现,但是这只能存在于同一个进程里面,而且这种情况没有什么有利的实际意义 75 75 76 76 int *p; //int类型指针,操作4个字节 77 77 p=(int *)malloc(2); //向堆申请了2个字节,但不进行初始化,calloc方式的申请会进行初始化 78 78 if(p) 79 79 printf("Memory Allocated at: %p\n",p); 80 80 else 81 81 printf("Not Enough Memory!\n"); 82 82 printf("%x\n",*p); //由于只申请了2个字节,所以非法读取了2个字节 83 83 *p=0x12345678; //由于只申请了2个字节,所以非法写入了2个字节 84 84 printf("%x\n",*p); //由于只申请了2个字节,所以非法读取了2个字节 85 85 free(p); //释放堆中申请过的2个字节,并且有可能把内存中的值也清0,这要取决于运行的内核 86 86 //下面是非法读写了4个字节 87 87 printf("%x\n",*p); 88 88 *p=0x87654321; 89 89 printf("%x\n",*p); 90 90 return 0; 91 91 } 92 92 93 93 11)经探究发现,不同类型的指针指向的地址跟指针类型不一致时,有可能会报错,也有可能只是警告而已 94 94 95 95 12)unsigned char (*q)(); //声明一个函数指针 96 96 指针形式调用函数时不给定传递参数值的话,默认是传递-1 , 指针调用函数的格式为:"(*指针名)(形参列表)" 或 "指针名(形参列表)" 97 97 98 98 13)一级和多级指针的使用: 99 99 int val=0x1122; 100 100 char *p3=&val; 101 101 char **p2=&p3; 102 102 103 103 printf("%x\n", p3); 104 104 printf("%x\n", p3+1); //跳转1个地址(因为p3是个一级指针而且类型修饰符为char) 105 105 106 106 printf("%x\n", *(p3)); //操作1个字节(因为p3是个一级指针而且类型修饰符为char) 107 107 printf("%x\n", *(p3+1));//操作1个字节(因为p3是个一级指针而且类型修饰符为char) 108 108 109 109 printf("%x\n", (p2)); 110 110 printf("%x\n", (p2+1)); //跳转4个地址(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针) 111 111 112 112 printf("%x\n", *(p2)); //操作4个字节(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针) 113 113 114 114 14)对多级多维指针的探究: 115 115 //假设已经掌握对多级0维指针,和一级多维指针的使用 116 116 117 117 unsigned char (**p)[3]; //这是一个二级2维指针 118 118 int Array3[10]={0x804a0e0,0x55667788,2,3,4,5,6,7,8,9}; //之所以第一个元素设为0x804a0e0,是因为如果该值取的不当,下面对(*(*p))进行解引用的时候,有可能在程序执行时导致内核塌陷,看起来好像是程序语法错误,也就是说要保证解引用的指针是在正确范围内的 119 119 p=Array3; //Array3是一个一级1维地址,先让Array3转变为二级2维地址,再让二级2维指针p所指向 120 120 121 121 printf("%x\n", p); //原本p是一个二级2维指针,在这里p表示为一个二级2维地址 122 122 printf("%x\n", p+1); //发生4个地址的跳转(因为地址长度为4个字节),因为(p+1)是一个二级2维地址,也就是此行语句输出值比上一行语句大4 123 123 124 124 printf("%x\n", *p); //解引用得到4个字节的值,因为p是一个二级2维地址。*p 得到的是一个一级2维地址 125 125 printf("%x\n", (*p+1)); //跳转3个字节,因为 *p 属于一级2维地址,也就是此行语句输出值比上一行语句大3。因为一级指针地址的跳转,是取决于维数,*p是一个一级2维地址,那么跳转数为:sizeof(unsigned char)*[3]=3 126 126 127 127 printf("%x\n", *(*p)); //对一级2维地址(*p)进行解引用,得到一级1维地址*(*p) 128 128 129 129 printf("%d\n", *(*(*p))); //对一级1维地址*(*p)进行解引用,得到1个字节的值,值为0xe0也就是224,因为指针 p 的类型修饰符为char,而sizeof(unsigned char)=1 130 130 131 131 printf("%d\n", *(*(*p))+1); //该行打印值比上一行大1,为225 132 132 133 133 //总结:对多级多维指针进行解引用的时,每次解引用都会遵循先降级再降维,当级数没降到1,那么维数不起作用。 134 134 // 当已经是一级指针了后,维数起作用,当做一级多维指针或一级1维指针处理 ,一级1维地址再解引用就得到值了 135 135 136 136 15)指针常量和常量指针 137 137 int a =3; 138 138 int b = 1; 139 139 int c = 2; 140 140 int const *p1 = &b;//const 在前,定义为常量指针 141 141 int *const p2 = &c;//*在前,定义为指针常量 142 142 //常量指针p1:指向的地址可以变,但内容不可以重新赋值,内容的改变只能通过修改地址指向后变换。 143 143 //p1 = &a是正确的,但 *p1 = a是错误的。 144 144 //指针常量p2:指向的地址不可以重新赋值,但内容可以改变,必须初始化,地址跟随一生。 145 145 //p2= &a是错误的,而*p2 = a 是正确的。 146 146 147 147 16)假设a是数组名,p是指针名,那么p=&a等效于p=a 148 148 int abc[4]={1,2,3,4}; 149 149 int (*p)[4]; 150 150 p=abc; //等效于p=&abc; 151 151 for(i=0;i<4;++i) 152 152 { 153 153 printf("%d\n",p[0][i]); 154 154 } 155 155 156 156 17)在sizeof()函数参数列表里,解引用符*的作用稍微发生了变化。 157 157 //下面证明了,解引用符号“ * ”在不同的场合应用,其作用发生了改变,如在sizeof()函数的参数中时,对数组名进行解引用,将会影响打印出来的数组“维积” 158 158 printf("%d\n", sizeof((**pp))); //打印出数组“维积”,为4 159 159 printf("%d\n", sizeof(*p)); //打印数组的“维积”,为4*sizeof(int)=16 160 160 printf("%d\n", sizeof(p)); //打印出指针“维积”,为3*4*4=48 161 161 printf("%d\n", sizeof(*(**p[3][4]))); //打印出指针“维积”,为5*4=20 162 162 163 163 18)关于指针和数组的一种特殊数据结构 164 164 int (**p[3][4])[2][5]; //定义一个二级3维指针2维数组 165 165 int pp[5][6]; 166 166 int test; 167 167 //p=&test; //因为p是数组名,是一个常量,所以p=&test;这句有错误 168 168 169 169 18)int array[10]; 170 170 double *a=&array[5]; 171 171 double *b=array; 172 172 printf("a-b=%d\n",a-b); //打印结果为:2。 4*5/8=2 此行代码是这样理解的: a-b得到一个double类型的地址值,然后转换成int类型,那么有20/8=2 173 173 174 174 ------------------------------------------*/ 175 175 #include"stdio.h" 176 176 #include"stdlib.h" 177 177 178 178 179 179 void main() 180 180 { 181 181 /* 182 182 int i; 183 183 int a[10]={[4]=4,5,6,7,[1]=1,2,3,110}; //数组的初始化技巧 184 184 for (i=0;i<10 ;++i ) 185 185 { 186 186 printf("%d\n",a[i]); 187 187 } 188 188 */ 189 189 /* 190 190 int abc[4]={1,2,3,4}; 191 191 int i=0; 192 192 int (*p)[4]; 193 193 p=&abc; //p=abc;等效于p=&abc; 194 194 printf("%x,%x\n",&abc,abc); 195 195 for(i=0;i<4;++i) 196 196 { 197 197 printf("%d\n",p[0][i]); 198 198 } 199 199 */ 200 200 /* 201 201 int Array[2][3][2]={{{1,2},{3,4},{5,6}},{{7,8},{9,10},{11,12}}}; 202 202 printf("%d\n",*(*(*(Array+1)))); 203 203 printf("%d\n",*(*(Array+1))); 204 204 printf("%d\n",*(Array+1)); 205 205 printf("%d\n",(Array+1)); 206 206 //printf("%d\n",*(*(Array+1))); 207 207 */ 208 208 /* 209 209 int *p; 210 210 int c[]={0x1234,0x5678}; 211 211 int a=4; 212 212 int *b=&a; 213 213 p=(int *)malloc(4); 214 214 //printf("%p %d\n",b,*b); 215 215 //printf("%p %d\n",c,*c); 216 216 //printf("%p %d\n",(c+1),*(c+1)); 217 217 //printf("%x",*p); 218 218 *p=0x12345678; 219 219 printf("%p\n",p); 220 220 printf("%x\n",*p); 221 221 free(p); 222 222 printf("%p\n",p); 223 223 printf("%x\n",*p); 224 224 b++; 225 225 printf("%p %d\n",b,*b); 226 226 b++; 227 227 printf("%p %d\n",b,*b); 228 228 b++; 229 229 printf("%p %d\n",b,*b); 230 230 b++; 231 231 */ 232 232 /* 233 233 char d[6] = {0x01,0x02,0x03,0x04,0x05,0x06}; 234 234 char (*p)[2]; 235 235 p = d; 236 236 printf("%p\n", (p)); 237 237 printf("%x\n", *(p)); 238 238 printf("%p\n", *(*(p))); 239 239 printf("%p\n", (p+1)); 240 240 printf("%x\n", *(p+1)); 241 241 printf("%p\n", *(*(p+1))); 242 242 */ 243 243 /* 244 244 //-------------一级和多级指针的使用----------// 245 245 int val=0x1122; 246 246 char *p3=&val; 247 247 char **p2=&p3; 248 248 249 249 printf("%x\n", p3); 250 250 printf("%x\n", p3+1); //跳转1个地址(因为p3是个一级指针而且类型修饰符为char) 251 251 252 252 printf("%x\n", *(p3)); //操作1个字节(因为p3是个一级指针而且类型修饰符为char) 253 253 printf("%x\n", *(p3+1));//操作1个字节(因为p3是个一级指针而且类型修饰符为char) 254 254 255 255 printf("%x\n", (p2)); 256 256 printf("%x\n", (p2+1)); //跳转4个地址(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针) 257 257 258 258 printf("%x\n", *(p2)); //操作4个字节(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针) 259 259 //------------------------------------------// 260 260 */ 261 261 /* 262 262 //-------------对多维指针的方括号运算以及多次解引用----------// 263 263 printf("%d\n", Array); 264 264 printf("%d\n", Array[1]); 265 265 printf("%d\n", Array[1][1]); 266 266 267 267 printf("%d\n",*(Array[1][1])); 268 268 269 269 printf("%d\n",*(*(Array[1]))); 270 270 printf("%d\n",*(Array[1])); 271 271 //-----------------------------------------------------------// 272 272 */ 273 273 /* 274 274 //----------------------对多级多维指针的探究-----------------// 275 275 //假设已经掌握对多级0维指针,和一级多维指针的使用 276 116 277 117 unsigned char (**p)[3]; //这是一个二级2维指针 278 118 int Array3[10]={0x804a0e0,0x55667788,2,3,4,5,6,7,8,9}; //之所以第一个元素设为0x804a0e0,是因为如果该值取的不当,下面对(*(*p))进行解引用的时候,有可能在程序执行时导致内核塌陷,看起来好像是程序语法错误,也就是说要保证解引用的指针是在正确范围内的 279 119 p=Array3; //Array3是一个一级1维地址,先让Array3转变为二级2维地址,再让二级2维指针p所指向 280 120 281 121 printf("%x\n", p); //原本p是一个二级2维指针,在这里p表示为一个二级2维地址 282 122 printf("%x\n", p+1); //发生4个地址的跳转(因为地址长度为4个字节),因为(p+1)是一个二级2维地址,也就是此行语句输出值比上一行语句大4 283 123 284 124 printf("%x\n", *p); //解引用得到4个字节的值,因为p是一个二级2维地址。*p 得到的是一个一级2维地址 285 125 printf("%x\n", (*p+1)); //跳转3个字节,因为 *p 属于一级2维地址,也就是此行语句输出值比上一行语句大3。因为一级指针地址的跳转,是取决于维数,*p是一个一级2维地址,那么跳转数为:sizeof(unsigned char)*[3]=3 286 126 287 127 printf("%x\n", *(*p)); //对一级2维地址(*p)进行解引用,得到一级1维地址*(*p) 288 128 289 129 printf("%d\n", *(*(*p))); //对一级1维地址*(*p)进行解引用,得到1个字节的值,值为0xe0也就是224,因为指针 p 的类型修饰符为char,而sizeof(unsigned char)=1 290 130 291 131 printf("%d\n", *(*(*p))+1); //该行打印值比上一行大1,为225 292 132 293 133 //总结:对多级多维指针进行解引用的时,每次解引用都会遵循先降级再降维,当级数没降到1,那么维数不起作用。 294 134 // 当已经是一级指针了后,维数起作用,当做一级多维指针或一级1维指针处理 ,一级1维地址再解引用就得到值了 295 295 */ 296 296 /* 297 297 int (**p[3][4])[2][5]; //定义一个二级2维指针2维数组 298 298 int pp[5][6]; 299 299 int test; 300 300 //p=&test; //因为p是数组名,是一个常量,所以p=&test;这句有错误 301 301 302 302 //下面证明了,解引用符号“ * ”在不同的场合应用,其作用发生了改变,如在sizeof()函数的参数中时,对数组名进行解引用,将会影打印出来的响数组“维积” 303 303 printf("%d\n", sizeof((**pp))); //打印出数组“维积”,为4 304 304 printf("%d\n", sizeof(*p)); //打印数组的“维积”,为4*sizeof(int)=16 305 305 printf("%d\n", sizeof(p)); //打印出指针“维积”,为3*4*4=48 306 306 printf("%d\n", sizeof(*(**p[3][4]))); //打印出指针“维积”,为5*4=20 307 307 */ 308 308 /* 309 309 int a =3; 310 310 int b = 1; 311 311 int c = 2; 312 312 int const *p1 = &b;//const 在前,定义为常量指针 313 313 int *const p2 = &c;//*在前,定义为指针常量 314 314 //常量指针p1:指向的地址可以变,但内容不可以重新赋值,内容的改变只能通过修改地址指向后变换。 315 315 //p1 = &a是正确的,但 *p1 = a是错误的。 316 316 //指针常量p2:指向的地址不可以重新赋值,但内容可以改变,必须初始化,地址跟随一生。 317 317 //p2= &a是错误的,而*p2 = a 是正确的。 318 318 */ 319 319 320 320 int array[10]; 321 321 double *a=&array[5]; 322 322 double *b=array; 323 323 printf("a-b=%d\n",a-b); //打印结果为:2。 4*5/8=2 此行代码是这样理解的: a-b得到一个double类型的地址值,然后转换成int类型,那么有20/8=2 324 324 325 325 }
这是我对指针学习的归纳记载,如有疑问欢迎联系作者本人一起探讨~
尊重作者的劳动,转载请记得注明来源:http://www.cnblogs.com/weifeng727/p/5584151.html
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 如何0基础学习C/C++? 2020-06-06
- C++ this指针 2020-06-03
- vtk学习记录(三)——初识vtkRenderer 2020-05-16
- 纯虚函数与基类指针数组的运用 代码参考 2020-04-30
- C++基础 学习笔记六:复合类型之数组 2020-04-25
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash