概念:指针是一个整型值,这个值代表一个内存地址,可以理解为指针是内存地址的门牌号码。通过指针可以找到所代表的内存地址上储存的内容。
一、指针变量的声明
字符 * 放在两个变量之间表示乘号,放在类型后边就表示声明该类型的指针。既然指针是值那就可以赋给变量,这个变量就是指针变量。指针是什么 "具体类型" 呢?可以说指针有具体类型 也可以说指针没有具体类型。说指针有具体类型,是因为不管什么类型声明的指针,它们都占有相同的字节长度,单成一系;说指针没有具体类型,指针类型的声明是随着它指向的目标变化的,int*只能声明整型指针,float*只能声明float指针。可以这样理解:指针是毛,它指向的目标变量是,
皮之不存毛将焉附,毛随着皮走。说到指针类型,还有一种特殊指针就是无类型(void*)指针,无类型指针可以指向任何数据。但无类型指针无法直接使用,我们知道,指针本身是一个记录另外一个内存地址码的整型值。如果不知道指向地址的数据类型,每次读取多少数据,一次读取走多远就成了问题。所以,无类型指针在使用时,最终还是要通过赋值、强转等方式赋予它具体的类型。这种指针的用途,主要是提高函数的通用性,使函数能够适用多种数据类型;但归根结底,函数内部还是要将无类型指针具体化的,不能无类型到底。
继续说指针类型,指向int类型的指针用int*声明,指向char的指针用char*声明,包括我们自定义的类型加上*就是相应的指针声明。
例如:int* iPtr; //声明int型指针变量iPtr,iPtr中存有一个整数标明一个int值(变量)的地址
注意,声明指针变量要一个一个声明,用","隔开的方式不可行
二、*、&运算符
字符 "*" 可以作乘号,还可以进行指针声明,它还是一个指针的运算符,把它放到指针变量的前面,返回的就是指针指向的地址里存储的值。"&"是"*"的逆运算符,我们把"&"放到一个变量的前面,就可以得到该变量所在的地址,就是经常说的取址。说着绕嘴,举个例子理解起来就很简单:
int i=100; //声明一个int型变量并赋值100
int* iPtr=&i; //声明一个int型指针变量iPtr并让它指向变量i
//即把i所在的内存地址赋给iPtr(&i意为取i的地址,简称取址)
printf("%d",*iPtr); //运行结果:100 (通过指针变量把存在内存中的值又找了回来)
总结:声明或从地址中取原值用"*",通过变量名找地址用"&"。
三、指针变量的初始化
声明指针变量之后,编译器会为指针变量本身分配一块内存,但是这块内存里到低存着什么谁也不清楚。对于指针而言就是说不知道它到底指向哪里,它指向的地方能不能使用。所以指针声明后必须进行初始化。
前面的举例,int* iPtr=&i;就是指针变量的声明与初始化一同完成了。
有时,我们需要提前声明一些指针,等待后边使用,这时我们可以用NULL先初始化。用NULL初始化的指针称为空指针(指向的内存地址为不存在的0),如果我们忘了为其再初始化而直接使用,编译器会报错。
四、指针的运算
指针本质上就是一个代表了内存地址的无符号整数,当然可以进行运算,但是规则并不是整数运算的规则。
1.指针与整数值的加减运算
指针与整数值的运算,表示指针的移动。这种移动一次是多少呢?具体与指针指向的数据类型相关,该数据类型占有几个字节指针就移动几个字节。说着不好理解,还是举例说明吧:
为说明的更清楚,这里先使用一下数组的概念,所谓数组就是占用连续内存空间存储若干同类型值(称为元素)的集合。
int A[10] = { 21,22,36,44,58,89,54,65,87,14 }; //声明含有10个int类型元素的数组并赋初值
int* pA = &A[0]; //取得第一个元素的地址赋给int型指针变量pA
printf("%i\n", *pA);//运行结果:21(第0个元素)
pA = pA + 1;//+1表示向后移动1个int型所占字节数,指向第1个int型元素(从0开始计数)
printf("%i\n", *pA);//运行结果:22(如果抛开所占字节,实际指针移动1个元素更好理解)
pA = pA + 5;//+5表示向后再移动5个int型所占字节数,指向第6个int型(起始位置是+5前指针所在位置1)
printf("%i\n", *pA);//运行结果:54
pA = pA - 2;//-2表示向前退2个int型所占字节数,指向第4个int型元素(从+5后的位置往回退)
printf("%i\n", *pA);//运行结果:58
总结:指针的加减整数运算,是相对于某一连续内存地址存储相同类型元素而言的,否则就不能使用加减整数运算。这里强调"连续"内存空间和同类型元素,要多理解一下。至于+1代表移动几个字节,相同类型在不同编译器上所占字节也可能不一样,记不记两可。指针指到某位置后如果不做其它操作,它就指着那,所以有个"当前位置"的概念。
2.指针与指针之间的加法没有意义。
3.相同类型的指针允许进行减法运算,返回它们之间的距离,如果再乘上该类型单个元素所占字节数,那么这两个指针之间共占用多少字节就可以计算出来了。
4.指针之间可以进行比较运算,比较的是哪个地址更大,可以获得在内存中位置的前后关系。
附:计算常用类型指针所占字节数小程序
#include<stdio.h>
int main(void)
{
printf("int类型占 %zd字节,int*类型占 %zd字节\n", sizeof(int),sizeof(int*));
printf("char类型占%zd字节,char*类型占%zd字节\n", sizeof(char),sizeof(char*));
printf("short类型占%zd字节,short*类型占%zd字节\n", sizeof(short),sizeof(short*));
printf("double类型占%zd字节,double*类型占%zd字节\n", sizeof(double),sizeof(double*));
printf("long类型占%zd字节,long*类型占%zd字节\n", sizeof(long),sizeof(long*));
char c = getchar(); //阻塞程序运行
return 0;
}
使用VS2022运行结果:
int类型占 4字节, int*类型占 8字节
char类型占1字节,char*类型占8字节
short类型占2字节,short*类型占8字节
double类型占8字节,double*类型占8字节
long类型占4字节,long*类型占8字节
说明:一般资料介绍指针类型均占4个字节,我使用VS2022编译器结果是8个字节,但无论如何在同一系统内无论是什么类型的指针它们所占字节数都是相同的。