指针的概念
什么是指针?一个内存变量或数组变量在内存中的地址就是指针(pointer)。简单地说,内存地址就是指针,指针就是内存地址。内存地址的英文是address,例如:家庭地址,IP地址,都是使用这个单词。在C语言中,采用指针这个概念来形容内存地址,代表内存上的一个刻度的意思。
假设我们使用整数,对操作系统中所有的内存地址进行编号。那么在32位操作系统中,最大的内存地址就是4G-1。换句话说,32位操作系统指针的范围是0到4G之间,64操作系统指针的范围是0到4G*4G之间。
什么是指针变量?存放指针(内存地址)的变量就称为指针变量。在32位操作系统中,任何类型的指针变量的空间大小都是4个字节。指针变量记录的内存地址,也称为它指向的地址。
一、指针变量的定义是什么?
指针变量的定义,对比普通变量的变量的定义只多了一个*符号。
格式为:变量类型 * 指针变量名称[=地址];
例如:int i=0;int *p=&i;
其中&符号是取地址符号,用于获取一个变量的地址。
注意:*符号的左边和右边可以各有一个空格间隔,这样书写代码显得更清晰一些。*符号两旁都没有空格或者左边或右边有一个空格都是可以的,就如同赋值符号两边可以有空格也可以没有空格一样。
//测试指针变量空间
#include<stdio.h>
int main()
{
int i = 0x12345678;
short j = 20;
int *p = &i;
double d = 999.99;
double *pd = &d;
short *ps = &j;
char *pc = 0;
puts("普通变量:");
printf("sizeof(i)=%d\n", sizeof(i));
printf("sizeof(j)=%d\n", sizeof(j));
printf("sizeof(d)=%d\n", sizeof(d));
puts("指针变量:");
printf("sizeof(p)=%d\n", sizeof(p));
printf("sizeof(pd)=%d\n", sizeof(pd));
printf("sizeof(ps)=%d\n", sizeof(ps));
printf("sizeof(pc)=%d\n", sizeof(pc));
return 0;
}
普通变量占用的空间大小与其类型相关,有的占用2个字节,有的占用4或8个字节各不相同。相反,无论是什么类型的指针变量都只占用4个字节。在VS2015编译器中,可以把工程设置为32位程序或64位程序。如果把工程设置为64位程序,那么所有的指针变量就都占用8个字节了。
二、指针变量的功能
指针变量的核心功能是:对所指向的内存地址上的数据进行读取或写入操作!
指针变量对目标内存空间的操作,可以简单理解为对指向的目标变量的读或写的操作。
操作目标内存符号也是*符号,例如:*p=888;
这个赋值操作是对指针变量指向的目标变量进行赋值,因此变量i在这个赋值操作之后将变为888。:
#include<stdio.h>
int main()
{
int i = 0x12345678;
short j = 20;
int *p = &i;
double d = 999.99;
double *pd = &d;
short *ps = &j;
char *pc = 0;
*p = -1; // 代替普通变量赋值:i = -1;
*ps = -1; //代替普通变量赋值: j = -1;
*pd = 0; //代替普通变量赋值:d = 0;
printf("i=0x%x\n", i);
printf("j=%d\n",j);
printf("d=%lf\n",d);
return 0;
}
根据指针变量的类型不同,指针变量可以对目标内存进行1个字节、2个字节或4个或8个字节的操作。
char类型的指针变量,每次对所指向目标内存区域进行1个字节的操作。
short类型的指针变量,每次对所指向目标内存区域进行2个字节的操作。
int或long类型的指针变量,每次对所指向目标内存区域进行4个字节的操作。
double*类型的指针变量,每次对所指向目标内存区域进行8个字节的操作。
针变量有两个用途。一个用途是在定义指针变量时使用,另一个用途是在定义变量之后使用。定义变量之后指针变量前面再出现符号,那就都是用来进行赋值操作的,我们只要分辨清楚符号的这两种不同用途即可。
三、指针变量与数组
指针变量也可以使用类似于数组的下标符号[],对目标内存(变量)空间进行读或写的操作。例如:
int i=888;
int*p=&i;
p[0]=-1; //p=-1; 这两种写法是等价的!
因此,实际上指针变量有两种方法,可以对目标内存空间进行读写操作。一种是上一节介绍过的,通过指针变量与符号对指向的内存操作;第二种方法就是这节要介绍的,使用下标符号[]与指针变量联合来读写目标内存中的数据。
#include<stdio.h>
#include <stdlib.h>
int main()
{
int a[] = { 8,9,-1,2,3,4,5,666,45 };//数组也是一种指针变量 指针法 下标法 循环赋值
int i = 0;
int *p = a;
while (i < _countof(a))
printf("%d ", *(p+i));
// printf("%d ", p[i++]); //物理上的偏移跟下标法类似 : i*sizeof(int) 一次偏移4
p = &i;
printf("\n数组元素的个数是:%d", p[0]); //p[0] 与 *p 是等价写法
printf("\n数组元素的个数是:%d",*p); //p[0] 与 *p 是等价写法
printf("\n数组元素的个数是:%d", i); //两种写法都是读取 变量i 中的数据
return 0;
}
总结
一、使用指针变量读写指向的内存空间上的数据,每次操作的所覆盖的空间长度要依据这个指针变量的来源类型来决定。
二、指针变量的降级:一个指针变量前加一个*符号或后面加[]符号之后的类型,就会降级为为它的来源类型。例如:
int i = -1; //i:int类型
int p = &i; //p:int类型
int j = *p; //*p:int类型(与i和j的类型相同)
p[0]=10; //p[0]:int类型(与i和j的类型相同)三、对比数组与指针变量的定义: a)指针变量定义时使用的是符号,读写目标数据时也使用符号;
b)数组变量定义时使用的是[]符号,调用元素时也使用[]符号。四、对比数组与指针变量的调用: a)指针变量对目标内存空间的读写操作,可以使用两种方式:*符号或者[]符号;
b)数组变量对目标内存空间的读写操作,也可以使用两种方式:*符号或者[]符号五、可以把数组(的地址)赋值给指针变量,反之则不可: 就如同遥控器可以遥控一个空调或电视,反之一个空调或电视不能遥控一个遥控器。例如:
int a[20] = {0}; int *p=a; //正确 a=p; //错误
//数组也可以使用*符号
#include<stdio.h>
#include <stdlib.h>
int main()
{
int a[] = { 8,9,-1,2,3,4,5,666,45 };
int *p = a;
int i = -1;
while (++i < _countof(a))
*(a + i) = i * 7 - 19; //等价于a[i]
while (i--)
printf("%d ", p[i]);
return 0;
}