指针:
在没学习指针之前,这么几个问题总是围绕在我的耳边:
①什么是指针?
②指针能做什么?
③为什么要存在指针?
下面带着这些问题,我来谈谈学习完指针后,我对指针的认识。下面所用到的编译环境为vs2010
一、什么是指针?
在计算机科学中,指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址可以找到所需的变量单元,可以说,地址指向该变量单元。因此,将指针形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
二、为什么要存在指针?
地址标识这每一块的地址空间,指针则是为了存放地址才出现的。有了指针,让内存的访问变得更加方便。
三、指针类型和指针变量
指针类型:与char 、short 、int等一样,指针也是一种类型,它用来定义指针变量。我们在学习整型时,知道定义一个整型变量,系统会给这个变量开辟四个字节的空间来存储对应的内容。指针类型也一样,一个指针变量占用的空间大小与计算机处理器的位数有关。比如:32位的机器,指针类型为4个字节;64位的机器,指针类型为8个字节。这个是为什么呢?现在以32位机器来说明。32位的机器有32根地址线,想要保存一个地址则需32个比特位来进行保存,那么8个比特位为1个字节,所以32位的机器下,指针类型的大小为4个字节。
指针变量:顾名思义,存放指针的变量。
四、如何定义一个指针变量?
定义变量:开辟空间。初始化:开辟空间 + 赋初值。那么如何来定义一个指针变量并为它赋初值呢?
语法规则:①定义指针变量:type + * + 变量名1 ;变量名1 = &变量名2;
举个例子:
int a = 10; int *p; p = &a;
②初始化指针变量:type + * + 变量名1 = &变量名2 ;
举个例子:
int a = 10; int *p = &a;
type表示的是存放对应类型变量的地址。例如上面int *p中的int表示p所指向的变量a的类型。我用的是环境是vs2010,也可以写成char *p = &a,编译会编过,但是会有告警。因为指针的类型决定了对指针解引用时具有多大的权限,比如:char *p = &a;*p则只访问a所在地址的最低的一个字节,而int *p = &a;*p可以访问a所在地址的4个字节。
五、一级指针的运算
1、指针 + - 一个整数:
对指针变量+(-)一个数字相当于+(-)其指向类型的大小。
int n = 10; char *pc = (char *)&n; //这里强转n的地址的类型,是为了验证上面那句话。 int *pi = &n; printf("%p\n",&n); //运行结果:012FFDB0 printf("%p\n",pc); //运行结果:012FFDB0 printf("%p\n",pc+1); //运行结果:012FFDB1 printf("%p\n",pi); //运行结果:012FFDB0 printf("%p\n",pi+1); //运行结果:012FFDB4
2、对指针解引用操作(操作符(*))
我们来看一段程序:
int n = 10; int *pc = &n; printf("%d\n",n); //运行结果:10 printf("%d\n",*pc); //运行结果:10
可以看到,n和*pc打印出来的结果相同。所以*pc和n相同,可以相互替换,他们既可以做左值也可以做右值。
我们再来看一段代码(验证主题4的最后一句话):
int n = 0X11223344; char *pc = (char *)&n; int *pi = &n; printf("%x\n",*pc); //运行结果:44 printf("%x\n",*pi); //运行结果:11223344
我们可以明显看到:*pc和*pi打印出来的结果是不同的。所以指针的类型决定对指针解引用时访问的最大权限。
3、指针—指针
指针减指针指的是地址相差值
char arr[] = "abcdefg"; char *p = &arr; while(*p != '\0') p++; printf("%d\n",p-arr);
4、指针的关系运算:
for(vp = &values[N_VALUES-1];vp >= &values[0];vp--) { *vp = 0; }
**** 在c标准中,允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针进行比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
六、二级指针
指针变量也是变量,那么是变量就必定有自己的地址,那么我们还可以再定义一个新的指针变量来存放这个变量,那么这个新变量就称为二级指针。
int a = 10; int *pa = &a; int **ppa = &pa;
a的地址存放在指针变量pa中,pa的地址存放在指针变量ppa中。pa是一级指针变量,ppa是二级指针变量。
七、指针数组
指针数组:一个存放指针的数组。
语法规则:type + * + 变量名 + 【n】。
直接看一段代码:
int i = 0; int a[10] = {0}; int *arr[10]; for(;i < 10;i++) { arr[i] = &a[i]; } for(i = 0;i < 10;i++) { printf("%p ",&a[i]); printf("%p\n",arr[i]); } printf("\n");
这段代码中。先初始化了一个10个元素的数组a,再定义了一个10个元素指针数组arr,然后将a中每个元素的地址存入指针数组arr中,最后分别打印出a中每个元素的地址和arr中每个元素的内容。下来我们来看一下结果:
004FFAD0 004FFAD0 004FFAD4 004FFAD4 004FFAD8 004FFAD8 004FFADC 004FFADC 004FFAE0 004FFAE0 004FFAE4 004FFAE4 004FFAE8 004FFAE8 004FFAEC 004FFAEC 004FFAF0 004FFAF0 004FFAF4 004FFAF4 请按任意键继续. . .
可以很明显的看到,他们的内容是相同的。
八、数组指针
数组指针:一个有能力指向数组的指针。
语法规则:type + (* + 变量名) + 【】
**:这里需要注意这个中括号当中的数字必须与其指向的数组元素数相等。
看一段代码:
int a[10] = {0}; int (*arr)[10] = &a; printf("%p\n",a); printf("%p\n",&a); printf("%p\n",arr);
这里先初始化了一个数组a和一个数组指针arr,分别打印出a的地址和arr的内容。下来我们看一下结果:
00AFF8EC 00AFF8EC 00AFF8EC 请按任意键继续. . .
可以看到三个结果相同。这里单独的a与&a是一样的,都代表数组a的地址。
九、指针数组和数组指针
1、概念不同:
指针数组:数组内元素全为指针;
数组指针:存放数组的指针。
2、他们在定义的语法规则上就是不同的:
指针数组:type + * + 变量名 + 【n】; eg:int *arr[10];
数组指针:type + (* + 变量名) + 【】; eg:int (*brr)[10]。
这里我说一下我的区别技巧:变量名结合的优先级:因为arr先和【10】结合,所以arr是指针数组;因为brr先和*结合,所以brr是数组指针。
3、大小不同(32位机器)
指针数组的大小 == 4 * 数组元素个数;
数组指针的大小 == 4。
十、函数指针
概念:函数也是有地址的,那么指向函数的指针就叫做函数指针
语法规则:type + (* + 变量名)+ (形参)
举个例子:
int func(int x); /* 声明一个函数 */ int (*f)(int x); /* 声明一个函数指针 */ f = func; /* 将func函数的首地址赋给指针f */
这里就定义了一个函数指针f指向函数func,赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值之后,指针f就直接指向函数func。