概念:内存是以字节为单位的一片连续的存储空间,1k=1024字节,为了便于访问,给每个字节单元有一个唯一的编号,编号从0开始,第一字节单元编号为0,以后各单元按顺序连续编号,这些单元的编号叫做地址。
1.数据类型有字节的差别,假设从0开始编号(一般不会从0开始编号的)。比如int 4个字节,int a=99;则表示0-3这片存储单元分给a,首地址是0;定义指针变量int *p;(在指针变量定义中,*是一个说明符,它表示其后的变量是指针变量,p是指针变量,而不是*p。也可以写成int* p,这样比较容易看清p为一个变量)。p=&a 表示p指向a的地址,此时p的值是0,但是p指向的范围是0-3四个字节,而不是单单0那个字节,取首地址。&为取址符,指针变量p存地址,要对变量a取地址,才能放进p里。所有指针变量的都是4个字节,存地址。取a的值的时候可以用*p表示(前提:p取a的地址。并且,此时的*是指针运算符,又称指向运算符,表示取指针变量所指的变量的值),*p和a的值都是99。并且当p指向a之后,修改*p,a的值也会改变,但是如果自增自减不能用*p++,需要用(*p)++。
*和&的优先级一样,从右往左运算。p=&a。*p=a。&*p=p=*&p。
printf("%p ",p);%p是以十六进制输出指针的地址。
两个不同的指针可以指向同一个变量,并且指针之间可以相互赋值,两个指针变量都可以对所指对象进行修改。比如int p1,p2; p1=&a;p2=&a;等同于p1=&a;p2=p1;
如果指针变量p指向一个普通变量a,此时又不想指向a了,可以用这几种语句让p还原为初始状态(没有指向任何变量),p=NULL;或者p=0;或者p=' ';这里的p并非指向0地址单元,而是一个确定的空值。(0是特殊的,如果用2000赋值给p,p=2000这样的语句是错误的)
地址里存的值改变,变量才会改变,最典型的例子就是交换两个数的值。
#include<stdio.h> using namespace std; void swap1(int* p1,int* p2)///指针变量类型决定传参需要取址 { int temp=*p1; *p1=*p2; *p2=temp; return; } int main() { int a=1,b=50; printf("a=%d,b=%d ",a,b); swap1(&a,&b);///取址 printf("a=%d,b=%d ",a,b); return 0; }
继续定义变量double b=1.56;定义指针变量q指向b,double* q=b; double 8个字节,继3之后4-11这片存储单元分给b,首地址是4;q的存的地址值也是4。后续说明和int雷同。
2.数组指针变量,注意数组不要越界
int arr[100]; ///arr表示首地址地址 int *p; p=arr; ///可以写作p=&arr[0]; p=p+1; ///该表达式不是表示地址所在的字节+1,而是在数组里跳一个int类型的地址,即跳了4个字节
///arr+i表示下标为i的元素的地址(如果从第0个算,表示第i个元素地址)
3.多级指针
int a=100; int* p; int** pp; p=&a; ///指针也是数据类型,虽然存a的地址,但是自己也有地址 pp=&p; ///指针变量p的地址存到pp里,虽然pp也是指针变量,但是不能指向普通变量a,只能指向指针变量p ///一级指针和二级指针不是相同的数据类型,不能相互赋值 printf("*pp=%d ",*pp); printf("**pp=%d ",**pp);
4.二维数组指针
二维数组的存储空间也是连续的,只不过为了形象表示,一般分成很多行很多列。
int a[3][2]={1,2,3,4,5,6}; int *p; p=&a[0][0]; ///p取首地址,错误写法:p=a; 和 p=&a[0]; printf("&a[0][0]=%d ",p); printf("*p=%d ",*p); for(int i=0;i<3;i++) { for(int j=0;j<2;j++) { printf("1: (p+%d)+%d = %d ",i,j,*(a+i)+j); printf("2: a[%d]+%d = %d ",i,j,a[i]+j); printf("3: *(a[%d]+%d) = %d ",i,j,*(a[i]+j)); ///行数组用下标法 printf("4: *( *(a+%d)+%d ) = %d ",i,j,*( *(a+i)+j ) ); ///指针表示法 printf("5: ( *(a+%d) )[%d] = %d ",(* (a+i) )[j] ); ///列用下标表示法 } }
5.数组作为函数参数
int a[5]; int b[3][4]; int c[2][4][6]; void print1( int a[] ); void print2( int b[3][] ); void print3( int c[2][4][]);
6.指针数组
int a[]={10,11,12,13,14};
int *p[n]; ///[]优先级比*高,先形成一个p[n]数组,再定义成指针数组变量,它有n个指针类型的数组元素。
错误赋值:p=a,因为p是个不可知的表示,只存在p[0]、p[1]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。
*p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值
int main() { int i,a[]={10,11,12,13,14}, *p[5]; int c=1005; printf("a=%d ",a); p[0]=&c; printf("p[0]=%d, *p=%d, **p=%d ",p[0],*p,**p); for(i=0;i<5;i++) { p[i]=a+i; printf("*a=%d, *p=%d, p[%d]=%d, **p=%d ",*a,*p,i,p[i],**p); } return 0; } /* a=6881000 p[0]=6880976, *p=6880976, **p=1005 *a=10, *p=6881000, p[0]=6881000, **p=10 *a=10, *p=6881000, p[1]=6881004, **p=10 *a=10, *p=6881000, p[2]=6881008, **p=10 *a=10, *p=6881000, p[3]=6881012, **p=10 *a=10, *p=6881000, p[4]=6881016, **p=10 */
都说指针是C语言的灵魂,但是acm不怎么用指针,略知一二即可。