目录
一、指针是个啥?
1、数据在内存中的存储和读取方式
如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。编译系统根据程序中定义的变量类型,分配一定长度的空间。内存区的每一个字节有一个编号,这就是"地址",它相当于旅馆中的房间编号。在地址所标志的内存单元中存放的数据相当于旅馆中居住的旅客。
2、指针的含义
一个变量的地址称为该变量的"指针"。例如:地址0x2000是变量 i 的指针。如果有一个变量专门用来存放另一个变量的地址(即指针),则称它为"指针变量"。指针变量就是地址变量,用来存放地址,指针变量的值是地址(即指针)。
二、指针变量
1、指针变量的声明格式
定义指针变量的一般形式为:类型名 *指针变量名 如:int *pointer;
其中 int 是表示指针 pointer 可以指向的变量的类型只能是整型,不能是 float 等别的数据类型。* 表示该变量的类型为指针型变量。pointer 是指针变量名。上面这个例子表示:pointer 是指向整型数据的指针变量。
注意:指针变量中只能存放地址(指针),不要将一个整数复制给一个指针变量,如:int *pointer = 100;是不合法的。
2、怎样引用指针变量
(1)给指针变量赋值:
如:int a;int *p = &a; //把变量 a 的地址赋值给变量 p
或:int a[10]; int *p = a; //int *p=后面必须是地址变量!
(2)引用指针变量指向的变量:
如果已执行:int *p = &a;即指针变量 p 指向整型变量 a,则:
printf("%d",*p);其作用是以整数形式输出指针变量 p 所指向的变量的值,即变量 a 的值。
如果有赋值语句:*p = 1;表示将整数 1 赋给 p 指针当前指向的变量,如果 p 指向变量 a,则相当于把1赋给 a,即"a = 1;"
(3)引用指针变量的值:
如:printf("%d",p);作用是以十六进制数形式输出指针变量 p 的值,如果 p 指向了 a,就是输出了 a 的地址,即:&a。
综上:
(1)& 取地址运算符。 &a 是变量 a 的地址。
(2)* 直接访问运算符。 *p代表指针变量 p 指向的对象。
三、通过指针引用数组
1、数组元素的指针(数组指针)
一个变量有地址,一个数组包含多个元素,每个数组元素都在内存中占有存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素。所谓数组元素的指针就是数组元素的地址。
int a[10] = {0,1,2,3,4,5,6,7,8,9}; //定义 a 为包含 10 个整型数据的数组,并初始化
int *p; //定义 p 为指向整型变量的指针变量
p = &a[0]; //把 a[0] 元素的地址赋值给指针变量 p
p = a; //C语言中数组名代表数组中首元素的地址,所以这条语句和上面的等价
2、在引用数组元素时指针的运算
当指针指向数组元素的时候,允许对指针进行加和减的运算。比如,指针变量 p 指向数组元素 a[0] ,那么可以直接用 p + 1 表示指向下一个元素 a[1]。注意:指向 p + 1 不是简单的将 p 的值(地址)加 1,而是加上一个数组元素所占的字节数。
3、通过指针引用数组元素
引用一个数组元素,有两种方法:(1)下标法:如 a[i] 的形式。(2)指针法:如 *(a+i) 或 *(p+i)。其中 a 是数组名(数组首个元素的地址),p 是指向数组的指针变量,其初值 p = a;。
注意:利用指针引用数组元素有不少技巧,但是容易混淆。分析一下下面这几种情况:(p 指向数组 a 的首元素,即 p=a)
(1)p++; *p;表示指针 p 指向数组下一个元素 a[1]。然后执行 *p ,得到元素 a[1] 的值。
(2)*p++;由于++和*同优先级,结合方向为自右向左,因此等价于 *(p++) 。先取 *p 值 a[0],然后使 p 加 1。
(3) *(++p);区别于上一种情况,是先是 p 加1,然后取 *p,得到元素 a[1] 的值。。
(4)++(*p);先取 *p 的值 a[0],然后将 a[0] 中存储的内容值加 1。
四、通过指针引用字符串
在C程序中,字符串是存放在字符数组中的。想要引用一个字符串,可以用以下两种方式:
(1)用字符数组存放一个字符串,可以通过数组名和下标引用字符串中的一个字符,也可以通过数组名和格式声明 "%s" 输出该字符串。比如:定义一个字符数组,其中存放字符串"Hello World!",输出该字符串和第七个字符。
#include<stdio.h>
int main(){
char string[] = "Hello World!"; //定义字符数组 string ,数组长度为13,'\0'
printf("%s\n",string); //用 %s 格式声明输出 string,可以输出整个字符串
printf("%c\n",string[7]); //用 %c 格式输出一个字符数组元素 o
return 0;
}
(2)用字符指针变量指向一个字符串变量,通过字符指针变量引用字符串常量。比如:通过字符指针变量输出一个字符串。下面这个例子实际上是把字符串的第一个元素的地址赋给指针变量string,使string指向字符串的第一个字符。
#include<stdio.h>
int main(){
char *string = "Hello Wrold!"; //定义字符指针变量string,并将其初始化
printf("%s\n",string); //输出字符串
return 0;
}
五、指向函数的指针
1、函数指针的定义
如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针。可以定义一个指向函数的指针变量,用来存放某一函数的起始地址,这就意味着此指针变量指向该函数。例如:
int (*p)(int,int);
//定义p是一个指向函数的指针变量,它可以指向函数的类型为整型且有两个整型参数的函数。p的类型用int(*)(int,int)表示。
2、用函数指针变量调用函数
如果想调用一个函数,除了可以通过函数名调用以外,还可以通过指向函数的指针变量来调用该函数。比如:
#include<stdio.h> //用函数求整数a,b中的大者
int main(){
int max(int,int); //函数声明
int (*p)(int,int); //定义指向函数的指针变量 p
int a,b,c;
p = max; //使 p指向 max函数
printf("请输入两个整数:a,b");
scanf("%d,%d",&a,&b);
c = (*p)(a,b); //通过指针调用 max函数,如果通过函数名调用函数可以写成 c=max(a,b)
c = max(a,b); //这是通过函数名调用函数的方式
printf("a=%d\nb=%d\nc=%d\n",a,b,c);
return 0;
}
int max(int x,int y){ //定义 max函数
int z;
if(x>y)
z = x;
else
z= y;
return z;
}
3、指向函数的指针变量的定义和使用
定义指向函数的指针变量的一般形式为:
类型名 (*指针变量名)(函数参数列表); 如:"int (*p)(int,int);",这里的"类型名"是指函数返回值的类型。
(1)定义指向函数的指针变量,并不意味着这个指针变量可以指向任何函数,它只能指向在定义时指定的类型函数。如"int (*p)(int,int);",表示指针变量 p 只能指向函数返回值为整型且有两个整型参数的函数。
(2)如果用指针调用函数,必须先使指针变量指向该函数。如:p=max;这里把 max函数的入口地址赋给了指针变量 p。
(3)在给函数指针变量赋值时,只须给出函数名而不必给出参数。如:p=max;
(4)用函数指针变量调用函数时,只需将(*p)代替函数函数名即可,在(*p)之后的括号中根据需要写上实参。如:c = (*p)(a,b);
(5)指向函数的指针变量不能进行算术运算,如:p++、p--、p+n 等是无意义的。
六、返回指针值的函数
1、定义返回指针值的函数的一般形式
类型名 * 函数名(参数列表);
2、返回指针值的函数的概念说明
一个函数可以返回一个整型值、字符值等,也可以返回指针型的数据,即地址。其概念与以前类似,只是返回值类型是指针类型而已。例如:"int *max(int x,int y);",其中 max是函数名,调用它以后会返回一个 int* 型(指向整型数据)的指针,即整型数据的地址。x,y是函数 max 的形参,为整型。
注意在 *max 两侧没有括号,在 max 的两侧分别为 * 运算符和()运算符。而()优先级高于 * ,因此 max 先与()结合成函数形式。这个函数前面有一个 * ,表示这个函数是指针型函数,函数值是指针,前面的 int 表示返回的指针指向整型变量。
七、指针数组
1、指针数组的概念说明(区别于数组指针)
一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都存放一个地址,相当于一个指针变量。比如定义一个指针数组:"int *p[4];"。
由于 [ ] 比 * 优先级高,因此 p 先与 [4] 结合,形成 p[4] 的数组形式,表示 p 数组有 4 个元素。然后再与 p 前面的 * 结合,表示此数组是指针类型的,每个数组元素都可以指向一个整型变量。
2、定义一维指针数组的一般形式
类型名 * 数组名 [数组长度]; 比如:int *name[4] = {"aaa","bbb","ccc","ddd"};//分别指向4个字符串
八、指向指针数据的指针
1、指向指针数据的指针变量,简称指向指针的指针。(双重指针 || 二维指针)
例如下图中,name是一个指针数组,它的每一个元素都是一个指针型的变量,其值为地址。name 既然是一个数组,那么它的每一个元素都由相应的地址。数组名 name 代表该指针数组首元素的位置。name + i 是 name[i] 的地址,name + i 就是指向指针型数据的指针。还可以设置一个指针变量 p,它指向指针数组的元素。
2、定义一个指向指针数据的指针变量
char ** p;
p 前面有两个 * 号,* 运算符的结合性是从右到左,因此 ** p 相当于 *(*p) ,显然(*p)是指针变量的定义类型。如果没有前面的 * ,那就是定义了一个指向字符数据的指针变量。现在它前面又加了一个 * 号,即 char ** p,可以把它分成两部分看,即:char * 和 (*p),后面的(*p)表示 p 是指针变量,前面的 char * 表示 p 指向的是 char * 型的数据。也就是说,p 指向一个字符指针变量,如果引用 *p ,就得到 p 所指向的字符指针变量的值。
二维指针的初始化:
int **p = 100;
1)首先为二维指针 p 申请了一个地址空间: 0x2000,p的内容为一个地址, *p 为0x3000
2)*p 是一个一级指针,*p 的内容为一个地址,**p 为 0x4000
3)*p 指针指向的地址存放整型数据:100
九、指针变量的类型及含义
变量定义 | 类型表示 | 含义 |
int i; | int | 定义整型标量 i |
int *p; | int * | 定义 p 为指向整型数据的指针变量 |
int a[5]; | int [5] | 定义整型数组 a,他有 5 个元素 |
int *p[4]; | int * [4] | 定义指针数组 p,他由 4 个指向整型数据的指针组成 |
int (*p)[4]; | int (*)[4] | p 为指向包含 4 个元素的一维数组的指针变量 |
int f(); | int () | f 为返回整型函数值的函数 |
int *p(); | int *() | p 为返回一个指针的函数,该指针指向整型数据 |
int (*p)(); | int (*)() | p 为指向函数的指针,该函数返回一个整型值 |
int **p; | int ** | p 是一个指针变量,它指向一个指向整型数据的指针变量 |