标签:
/*----------------------------------------
指针练习(精华)
1)首先,要理解变量或数组的首地址,指的就是存放数据的RAM或ROM中地址号最小的那个字节地址。
2)指针前面的类型说明符,具有2重意义(既决定了对一级指针进行解引用时,将会操作的字节数,以及对一级指针进行算术运算时,会跳转的地址个数)。
①决定了指针加一时,指针会跳转多少个地址,
例如:
如果指针是
char类型的,(指针+n) 指针会跳转n*1个地址。
int 类型的,(指针+n) 指针会跳转n*2个地址。
long类型的,(指针+n) 指针会跳转n*4个地址。
②并且还决定了通过指针操作地址值时,实际上会返回多少个字节的值,且地址号大的字节先返回。
例如:
假设要操作指针的一次地址返回值,那么如果指针是
char类型的,返回1个字节。
int 类型的,返回2个字节。
long类型的, 返回4个字节。
数组前面的类型说明符,同样具有2重意义,且跟上面的很相似。
例如:
#include"stdio.h"
int c[]={0x1234,0x5678};
void main()
{
printf("%p %d\n",c,*c); //数组是int类型意味着返回2个字节
printf("%p %d\n",(c+1),*(c+1)); //实际上(c+1)与c是夹着一个地址,因为数组类型符号是int,如果数组类型是long,则夹着3地址
}
也就是要注意类型所占的字节数,还有就是什么时候该看数组类型符号或者指针类型符号。
3)&叫取首地址符号,*叫解引用符号。
4)数组名是指一个首地址,所以,point=a(point是一个指针,a是一个数组名), a的前面不需要加&符号。
变量名指的是一个值,a[1]指的也是一个值,这些值包含着一个或多个字节,在想要让指针指向这些值的字节的地址时,
需要在变量名以及a的前面加上&符号,即意思是要让指针赋值符号(=)右边的东西是地址。
5)数组或变量的数据是一个一个字节的存放的,而且字节的地址是呈现连续的,赋值的时候,从左到右看,
越往右,字节的地址号越大。因此,对于多字节数据类型的数组而言,看起来有种“首尾相连”的效果,
因为一个元素的最低位字节其地址的加一地址对应的字节,就是下一个元素的最高位字节。
简单点来说就是低地址存放高字节,这种现象称为大端排列(常用单片机)。注意:有些时候则是低地址存放低字节,这种现象称为小端排列(ARM)。
6)指针可分为:函数指针,数组指针(多维指针),变量指针,结构体指针。 又可分为:多级指针,多维指针。 地址可分为:多级地址,多维地址。
7)只有字符数组的最后一个元素会紧接一个隐藏元素,该元素值为0,映射的字符为“\0”。
8)数据指针型函数,也叫指针函数(即返回值是一个地址)。
9)char (*p)[2]; //声明一个二维指针(也叫二维数组指针)
分析方括号([])对多维指针的操作时,要遵循一个原则:先明确指针的维数,再分析有多少组方括号,方括号里面的数字是多少,由此得到地址是如何跳转的;
然后根据方括号的组数得知地址最终会发生多少次的解引用,如果解引用的次数少于地址的维数,
那么最终得到的还是一个地址,也如果解引用的次数等于地址的维数,那么得到是一个数据值。
每次对多维地址进行一次解引用后,地址的维数将会变小。
一维数组名就是一个一级一维地址,二维数组名就是一个一级二维地址,多维数组名就是一个一级多维地址。每一个数组名都是一个地址。这些地址是固定的。
一级多维指针的特点是:解引用的写法很特殊;运算时地址的跳转很特殊。
探究代码如下:
int Array[2][3][2]={{{1,2},{3,4},{5,6}},{{7,8},{9,10},{11,12}}};
printf("%d\n", Array);
printf("%d\n", Array[1]); //与上一行代码相比,发生了 3*2*4=24个地址 的跳转
printf("%d\n", Array[1][1]); //与上一行代码相比,发生了 2*4=8个地址 的跳转
printf("%d\n",*(Array[1][1]));//对1维地址进行1次解引用,得到一个数据值,为9
printf("%d\n",*(*(Array[1]))); //对2维地址进行2次解引用,得到一个数据值,为7
printf("%d\n",*(Array[1])); //对2维地址进行1次解引用,得到的是一个1维地址,且与Array[1]值一样,但Array[1]是一个2维地址
10) #include<stdio.h>
#include<stdlib.h>
int main()
{
//下面是存在着非法读写的演示,虽然非法读写是可以实现,但是这只能存在于同一个进程里面,而且这种情况没有什么有利的实际意义
int *p; //int类型指针,操作4个字节
p=(int *)malloc(2); //向堆区域存储空间申请了2个字节,但不进行初始化,calloc方式的申请会进行初始化
if(p)
printf("Memory Allocated at: %p\n",p);
else
printf("Not Enough Memory!\n");
printf("%x\n",*p); //由于只申请了2个字节,所以非法读取了2个字节
*p=0x12345678; //由于只申请了2个字节,所以非法写入了2个字节
printf("%x\n",*p); //由于只申请了2个字节,所以非法读取了2个字节
free(p); //释放堆中申请过的2个字节,并且有可能把内存中的值也清0,这要取决于运行的内核
//下面是非法读写了4个字节
printf("%x\n",*p);
*p=0x87654321;
printf("%x\n",*p);
return 0;
}
11)经探究发现,不同类型的指针指向的地址跟指针类型不一致时,有可能会报错,也有可能只是警告而已
12)unsigned char (*q)(); //声明一个函数指针
指针形式调用函数时不给定传递参数值的话,默认是传递-1 , 指针调用函数的格式为:"(*指针名)(形参列表)" 或 "指针名(形参列表)"
13)一级和多级指针的使用:
int val=0x1122;
char *p3=&val;
char **p2=&p3;
printf("%x\n", p3);
printf("%x\n", p3+1); //跳转1个地址(因为p3是个一级指针而且类型修饰符为char)
printf("%x\n", *(p3)); //操作1个字节(因为p3是个一级指针而且类型修饰符为char)
printf("%x\n", *(p3+1));//操作1个字节(因为p3是个一级指针而且类型修饰符为char)
printf("%x\n", (p2));
printf("%x\n", (p2+1)); //跳转4个地址(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针)
printf("%x\n", *(p2)); //操作4个字节(因为内存中字节所使用的地址长度为32位且指针p2是一个二级指针)
------------------------------------------*/
标签:
原文地址:http://www.cnblogs.com/weifeng727/p/5584151.html