【C语言】指针

2023-05-16

指针就相当于遥控器。指针变量就是一个遥控器,专门存放内存单元地址的变量。因此可以认为指针变量就是地址变量。32位的内存地址范围是:0x00000000~0xffffffff,指针变量要存储这些值,需要的内存空间是32位,即4个字节。所以,指针变量固定地占4个字节的内存空间。

目录

1、指针变量的指针

1.1 指针变量的定义

1.2指针变量的初始化和赋值

1.3使用指针变量

1.3.1 *运算符

 2、指向数组的指针

2.1指针和数组名

2.2指针的赋值运算

2.3指针的算术和关系运算

2.3.1指针加减整数

2.3.2指针相减

2.3.3指针的关系运算

2.3.4指针的自增、自减

2.3.5利用指针引用数组元素

2.3.6指针作函数的参数

 3、指向字符串的指针

3.1字符指针和字符数组

3.2利用字符指针处理字符串

 4、指针数组和指向指针的指针

 4.1指针数组

4.1.1练习

 4.2指向指针的指针

4.2.1练习

4.3数组指针

5、函数指针与指针函数

5.1函数指针

​5.2指针函数


1、指针变量的指针

1.1 指针变量的定义

指针变量简称指针,其本质就是一个变量,它不同于普通变量的地方是只能存储地址,不能存放除地址以外的值。任何变量都需要先定义后使用。定义指针变量的格式为:

类型说明符 * 指针变量名

说明:

(1)类型说明符:说明的是指针变量存储的内存地址中所存数据的数据类型

(2)* :不是乘法运算符,它表示定义的是指针变量。

(3)指针变量名使用合法的用户标识符命名即可。

例如:int *p1,int *p2;定义了两个指针p1和p2,它们可以存储整型数据的地址。

注意:

(1)int *p1,p2;与int *p1,*p2;表示的意义不一样,它定义的是一个指针变量p1和一个整型变量p2

(2)注意指针变量名是p1和p2,而不是*p1和*p2      

1.2指针变量的初始化和赋值

在C语言中,用指针来表示一个变量指向另一个变量这样的指向关系。假如有变量i和p,当p变量中存放了i变量的地址时,就说p指向变量i。例如:int  i=3;int *p;p=&i;

在定义一个指针变量后,编译器不会自动为其赋值,此时指针变量的值是不确定的。有可能这个不确定的值正是某块有用的内存地址,那么直接使用它可能会带来内存错误。为了防止这种情况,可以使用NULL对其初始化,NULL的意思是“空”,表示指针哪里都不指向。NULL是指针类型中逻辑值为假的常量,除了NULL,其余指针常量的逻辑值都是真。

以p为例,来说明指针变量的初始化和赋值格式:

(1)为指针变量p初始化 int *p=NULL;

(2)先定义指针变量p,然后再为它赋值。int *p;p=NULL;

注意:变量名是p,不要写为*p=NULL。

1.3使用指针变量

正如用遥控器可以控制空调一样,可以通过指针访问它所指向的内存区域。这需要使用运算符“*”

1.3.1 *运算符

*运算符除了在定义指针变量时作为指针变量的标识外,还可以使用它达到“间接引用”的目的,即:通过指针访问其所指向的内存空间。

其使用格式: * 指针变量名; 这种格式表示取指针所指向的目标变量的值

例如:int i=3;int *p;p=&i;j=*p;

当p中存入了i的地址,*p与i等价,也为3,。将*p的值赋给j后,j的值为3。

验证运算符*和&的作用

 使用指针间接访问它所指向的变量

 2、指向数组的指针

2.1指针和数组名

数组名代表数组的首地址,可以将其看作是一个存放了数组首地址的指针。不同于普通指针的是,数组名是个常量,不能修改它的值。例如:int i;int a[10];a=&i;

说明:

(1)a是常量,不能修改它的值,因此a=&i是错误的

(2)a的类型是int[10],也可以看作int *。当一个指针存放了数组的首地址时,这个指针可以当作数组名使用,反之亦然。

假设有数组a和指针p的定义:

int *p,a[10];若需要指针指向数组的首地址,可以有两种方式:

1. p=&a[0];实现的功能是:将数组a起始元素a[0]的地址赋给指针p,p指向数组起始元素的地址,即p指向a数组的首地址。

2. p=a;实现的功能与p=&a[0];等价,也是让p指向a数组的首地址。

当指针p指向数组a的首地址后,指针p和数组名a等价,这样,既可以通过数组名a访问数组元素,也可以通过指p访问数组元素。例如:若有下标变量i,那么下面的操作均合法:

        1. *p=0;实现的功能是将p所指向的a数组首位元素a[0]赋值为0,与a[0]=0;等价。

        2.  也可以将数组名a当作指针使用。*a=0;实现的功能与*p=0;等价。

        3. 指针p可以当作数组名使用p[i]=0;实现的功能是将p所指向的a数组的元素a[i]赋值为0,与a[i]=0;等价。

2.2指针的赋值运算

 以下几种给指针变量赋值的方式都合法:

(1)p=&i; 完成的功能:将变量i的地址赋值给指针p,即:p\rightarrowi。

(2)p=a; 完成的功能:将数组a的首地址赋值给指针p,即:p\rightarrowa[0]。

(3)p=&a[i]; 完成功能:将数组元素a[i]的地址赋值给指针p,即:p\rightarrowa[i]

(4)p1=p2;完成功能:将指针变量p2的值赋值给指针p1,即:p1与p2指向同一个地址。

2.3指针的算术和关系运算

2.3.1指针加减整数

指针可以与整数进行加减操作,其结果也是一个指针,确切的说是个地址值。通常,“指针+整数”用于将指针向后移动“d*整数”个内存单元(其中d为指针指向的变量所占的字节数)。同理,“指针-整数”用于将指针向前移动“d*整数” 个内存单元(其中d为指针指向的变量所占的字节数)。

注意:编译器不会检查指针移动后,目的地址是否可用,如果移动失误,很可能会修改一些不能修改的内存单元,给程序带来致命的后果。因此限制这种“指针和整数的加减运算”智能在指针指向数组,不超出数组界限时使用。

2.3.2指针相减

当两个指针指向同一块内存区域时(例如:指向同一个数组),可以执行减法操作,结果为一个整数值,表示两个指针指向的位置之间相差几个元素。注意:如果两个指针不是指向同一块内存区域时,指针相减的结果是不可预测的,应该避免这种无意义的操作。就像同一条街道上的两个门牌号码相减,大致可以判断出中间相隔多少个房子。而不同街道上的门牌号码之间相减,是没有意义的。

2.3.3指针的关系运算

(1)表达式p<q为真,表示p指向的元素在前面,q指向的元素在后面

(2)表达式p>q为真,表示p指向的元素在后面,q指向的元素在前面

(3)表达式p==q为真,表示p和q指向同一元素

2.3.4指针的自增、自减

当指针指向数组时,可以指向自增、自减运算。另外,也可以通过指针间接地对其所指向的变量进行自增、自减运算。大致可以分为8种格式:

(1)指针变量++  例如p++,即p++=p,p=p+1

(2)++指针变量  例如++p,即p=p+1,++p=p

(3)指针变量--    例如p--,即p--=p,p=p-1

(4)--指针变量   例如--p,即p=p-1,--p=p

(5)指针变量*++  例如*p++,即*p++=*p,p=p+1

        或(*p)++,即(*p)++=(*p),(*p)=(*p)+1

(6)++*指针变量  例如 ++*p或++(*p),即(*p)=(*p)+1,++*p=*p                      

(7)*指针变量--   例如 *p--即*p--=*p,p=p-1

         或(*p)--即(*p)--=(*p),(*p)=(*p)-1

(8)--*指针变量  例如--*p或--(*p)即(*p)=(*p)-1,--*p=*p         

注意:*和++、--的优先级相同,属于第二级,结合方向是自右向左。

2.3.5利用指针引用数组元素

当指针指向数组的首地址的时候,指针和数组名等价。此时,可以用两种来访问数组,分别是下标法和指针法。

 

2.3.6指针作函数的参数

函数的参数不仅可以是整型、实型、字符型,还可以是指针类型。当指针作函数的实际参数时,它可以所存地址传送到函数中,完成双向地址传递。当指针作函数的实际参数时,它可以将所存在地址传送到函数中,完成双向地址传递。当指针作函数的形式参数时,它可以接收实际参数传递的地址值,在函数内部可以存取或修改此地址下的数据。

一、指针作函数的形参,接收实参变量的地址,可以修改实参变量的值。

 普通变量作函数的形参,从实参到形参传递的是变量的值,实现的是"单向值传递"。形参的改变无法传回给实参。在函数内部只能通过形参使用实参的值,无法修改它。

指针变量作函数的形参,从实参到形参传递的是变量的地址,实现的是“双向地址传递”。形参的改变可以传回给实参。在函数内部可以通过形参使用并修改实参的值。

二、指针和杉树分别做函数的参数,接收实参所传递的地址,修改实参地址中所存储的值。指针和数组分别作函数的参数,实参与形参的对应关系有四种形式。如下表所示:

实参形参
数组名数组
数组名指针变量
指针变量数组
指针变量指针变量

将数组a中的n个整数按相反顺序存放

练习:将数组a中的元素按照从小到大的顺序排列

//将数组a中的元素按照从小到大的顺序排列
#include<stdio.h>
#define N 10
void fun(int *x){
	int t,i,j;
	for(i=0;i<=N-2;i++){
		 for(j=i+1;j<=N-1;j++){
		    if(*(x+i)>*(x+j)){
			t=*(x+i);
			*(x+i)=*(x+j);
			*(x+j)=t;	
		}
	}
	}
	
}
int main(){
	int i,a[N];
	printf("请输入%d个数组元素:",N);
	for(i=0;i<=N-1;i++){
		scanf("%d",&a[i]);
	}
	printf("打印输出数组元素:");
	for(i=0;i<=N-1;i++){
		printf("%d,",a[i]);
	}
	fun(a);
	printf("\n");
	printf("数组升序排列后:");
	for(i=0;i<=N-1;i++){
		printf("%d,",a[i]);
	}
	
	
}

 3、指向字符串的指针

3.1字符指针和字符数组

C语言中,可以将字符串存放到字符数组中,数组名表示该字符串第一个字符存放的地址。如果将字符串的首地址或者字符数组名赋给一个字符型的指针变量,指针变量便指向了字符串。即:字符指针变量可以指向任一字符串的首地址。

分别定义字符数组和字符指针并为其初始化,以字符串的格式输出。

分别定义字符数组和字符指针,以字符串的格式输入、输出值。

修改字符数组名和字符指针的值

 运行程序时出错,因为str数组名是一个常量,不能够修改它的值

3.2利用字符指针处理字符串

 4、指针数组和指向指针的指针

 4.1指针数组

 数组的每一个元素都可以看作是一个变量,而指针是存储地址值的变量,因此,指针也可以作为数组元素存储在数组中,这时,数组称之为是指针数组。指针数组的定义格式是:

类型说明符 * 数组名 [整型常量或整型常量表达式]

例如:char *name[5];

name就是一个包含5个元素的指针数组,它的每个元素都是char *类型的,即:指向字符类型的指针。

4.1.1练习

 用指针数组输出多个字符串

对图书目录的图书名称进行排序

 4.2指向指针的指针

前面介绍的都是一级指针,一级指针可以指向普通的变量,本节要研究的是指向指针的指针,它实际上是多级指针。多级指针包含二级指针、三级指针以及更高级的指针。平时,使用最多的应该是二级指针。当某个指针变量所指向的不是普通变量,而是一个一级指针变量时,这个指针变量就称之为是二级指针。二级指针的基本格式为:

类型说明符 **指针名;

例如:char **p;

其中第一个*表示p指针指向的变量是char*类型的变量,即:指针变量。第二个*表示p本身的指针类型。

4.2.1练习

利用二级指针对图书目录中的图书名称进行排序

4.3数组指针

数组指针是指向一维或更多维数组的指针。数组指针的定义格式是:

类型说明符(*指针名)[数组最后一维的长度];

例如:int (*p)[4];

p是一个指针,指向一个最后一维长度是4的整型数组,4可以说是数组指针p的步长。若执行p+1,p在内存中实际移动的导航度是4*sizeof(int)。

二维数组的每一行都可以看作是一维数组组成的,因此,若需要一次操作二维数组的每一行,就可以先定义一个数组指针,然后让此指针依次指向二维数组的每一行。若利用p引用二维数组i行j列的一个元素a[i][j],有多种方式,包括:*p[i][j]、*(*p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]。

5、函数指针与指针函数

5.1函数指针

每个函数在编译时都会被分配一个入口地址,即:第一条指令的地址。如果将该地址赋给一个指针,那么指针变量就会存储了该函数的入口地址,该指针就指向了该函数,通常称这种指向函数的指针为函数指针。函数指针定义的一般格式为:

数据类型 (*指针名)(形参表列)

例如:int *p(int x,int y);

5.2指针函数

当一个函数的返回值是指数类型时,该函数称之为是指针函数。定义指针函数的一般格式如下:

函数类型 *函数名(形参表列)

{

说明部分

语句部分

}

注意:指针函数的声明和函数指针的格式非常相似,它们的区别在于函数指针比指针函数的声明多一对小括号。

int (*p)(int a[],int n);//定义函数指针

int *max(int a[],int n);//指针函数的声明

设计一个字符串查找函数,完成的功能是:在字符串中查找指定的字符串,并从第一次找到该字符串的位置开始输出字符串的内容。

#include<stdio.h>
#include<string.h>
char *seek(char *p1,char *p2)
{
	int i,flag;
	char *p;
	for(p=p1;*p!='\0';p++)
	{
		flag=1;
		for(i=0;*(p2+i)!='\0';i++){
				if(*(p2+i)!=*(p+i))
				{
			     flag=0;
			     break;
				}
     }
	if(flag==1){
		return p;
	}
  }
	return NULL;
}
int main(){
	char s1[30],s2[10],*s;
	puts("enter string:");
	gets(s1);
	puts("enter word:");
	gets(s2);
	s=seek(s1,s2);
	if(s!=NULL){
		puts(s);
	} 
	else{
		puts("can't find this word."); 
	}
	return 0;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C语言】指针 的相关文章

随机推荐