《C语言》初识指针

本文详细介绍了指针的基本概念、定义、赋值、运算,包括指向运算、算术运算和关系运算,以及指针与一维、二维数组的关系,如行指针、列指针和多级指针的应用。
摘要由CSDN通过智能技术生成

一、指针的概念

一个变量的地址称为该变量的“指针”;

二、指针变量

1、指针变量的定义

专门存放变量地址的变量就是指针变量;

2、指针变量的赋值

①将a的地址赋给指针p:

  1. int a,*p

  2. p=&a

②指针变量的初始化:

int a,*p=&a;

③通过其他指针变量赋值:

  1. int a,*p1,*p2;

  2. p1=&a;

  3. p2=p1;

④用NULL给指针变量赋空值:

int *p=NULL; 

3、指针的运算

①指向运算符

指向运算符:作用在指针上,代表该指针所指向的存储单元,实现间接访问,因此又叫做“间接访问运算符”。

例如:

  1. int a=3,*p;

  2. p = &a;

  3. printf("%d",*p)

  4. //输出结果为3

指向运算符*为单目运算符,根据运算符的作用,指向运算符*和地址运算符&互逆;

*(&a)==a,&(*p)==p

注意:定义指针变量时,“*”作用是定义指针变量,在执行部分的表达式中,“*”作用是充当指向运算符,作用在指针上,代表指针所指向的存储单元,实现间接访问。

在执行过程中,对*p进行修改等于直接对p指向的变量进行修改:


#include <stdio.h>
int main()
{
	int a=123,*p;
	p = &a;
	printf("%d,%d\n",a,*p);//结果123,123
	*p = 456;
	printf("%d,%d\n",a,*p); //结果:456,456
	return 0;
}

②指针的算数运算

一个指针可以加减一个整数n,但其结果不是指针值直接加减n,而是与其所指向的变量的数据类型有关,指针变量的值应增加或减少n*sizeof(指针类型)

例如:int a=3,*p=&a;设a的起始地址为1000,执行p=p+后,

p的值变化三个整型(每个整形占2byte)的位置,p的值应该是1000+3*sizeof(int)=1000+6=1006;而不是10003;

p=p+n,p=p-n,p++,p--,++p,--p 的理解类似...

③指针的关系运算

与基本类型变量一样,指针可以关系运算,在关系表达式中允许对两个指针进行所有的关系运算。在指针进行关系运算前,指针必须指向确定的变量,即指针必须有初始值。另外只有相同类型的指针才能进行比较。

4、多级指针


①多级指针变量均用基类型定义,定义m级指针变量,变量名前l放m个* 

②各指针变量都得取低一级的指针变量的地址后才能应用

③引用m级指针变量访问最终的普通变量时,变量名前需要使用m个指针运算符*

eg:


#include "stdio.h"
int main()
{
	int a = 5;
	int *p1,**p2,***p3;
	p1 = &a; p2 = &p1; p3 = &p2;
	printf("%d\n",***p3);
	return 0;
}

 

三、指针与数组


1、指针与一维数组


 C语言规定,数组的首地址即数组名是第一个地址常量,是不能改变的,a++是非法的;

 若首地址是a,且指针变量p指向该数组的首地址(p=a;)则:

数组的第0个元素a[0]的地址是a(等价于p)

数组的第1个元素a[1]的地址是a+1(等价于p+1)

数组的第2个元素a[2]的地址是a+2(等价于p+2)

数组的第i个元素a[i]的地址是a+i(等价于p+i)但是注意a是常量,p是变量;

eg:利用指针法实现数组中元素的输入和输出:


#include "stdio.h"
int main()
{
	int a[10],*p,i;
	p = a;
	printf("请输入10个整数:");
	for(i=0;i<10;i++) 
		scanf("%d",p+i);
	printf("输出10个整数:"); 
	for(i=0;i<10;i++)
		printf("%3d",*(p+i));
	return 0;
}

感想:

实际上scanf输入值的时候,就是在将值赋给对应的地址!所以才有用地址运算符&;

a[i]等于*(a+i) ;        &a[i]等于a+1 ;

2、用数组名作为函数参数

当函数之间需要传递数组时,可通过传递数组的首地址,完成存取主调函数中的数组元素的操作。

如果实际参数是某个数组元素,那么因为数组元素是一个变量,因此传递方法和普通变量是一样的,采用传值的方式进行,函数中的形式参数的编号不会影响对应实参的数组元素。

如果实际参数是数组名,由于数组名代表数组首地址,当他作为实参进行函数调用时,是把数组首地址传给形参,实参和形参共用一段内存区域。当在函数中对形参进行操作时,实际上是在实参数组中进行的,在函数调用后,实参的元素值可能发生变化。

eg:将数组a中n个整数反序存放(算法1)


#include <stdio.h>
void reverse(int x[],int n){
	int temp,i;
	for(i=0;i<=(n-1)/2;i++)
	{temp=x[i];x[i]=x[n-1-i];x[n-1-i]=temp;}
 } 
 int main(){	
 	int a[9];
 	printf("请输入10个数存入数组:"); 
 	for(int i=0;i<10;i++)
 		scanf("%d",a+i);	
 	reverse(a,10);
 	for(int i=0;i<10;i++)
 		printf("%d",a[i]);
 	return 0;
 }

 eg:将数组a中n个整数反序存放(算法2:定义两个指针实现交换)

#include <stdio.h>
void reverse(int x[],int n){
	int *p,*q,temp;
	p = x;
	q = x+n-1;
	while(p<q){
		temp = *p; //注意要用指向运算符取值来交换
		*p = *q;
		*q = temp;
		p++,q--;
	}
 } 
 int main(){	
 	int a[9];
 	printf("请输入10个数存入数组:"); 
 	for(int i=0;i<10;i++)
 		scanf("%d",a+i);	
 	reverse(a,10);
 	for(int i=0;i<10;i++)
 		printf("%d",a[i]);
 	return 0;
 }

3、指针与二维数组 

 (1)二维数组的地址:

用指针可以指向一维数组,也可指向二维数组是具有行列结构的数据,二维数组元素地址于一维数组元素地址表示不同,二维数组的首地址称为二维数组的指针,存放这个指针变量称为指向二维数组的指针变量。

a[i]从形式上看是a数组中序号为i的元素,如果a是一维数组名,则a[i]代表a数组第i号元素所占内存单元的内容,a[i]是有物理地址的(a+i),是占内存单元的。

如果a是二维数组,则a[i]是一个地址,并不代表某个元素的值。

a是指向行的,a[i]是指向列元素的;

数组名a常称为行指针,a[i]常称为列指针(行中的某列),

=========================================================================

看以下举例容易懂:

若有如下定义:

int a[3][4],i,j;

当0<=i<3、0<=j<4时,a数组元素可以用以下五种表达式表示:

①a[i][j]

②*(a[i]+j)    //a[i]=*(a+i),所以内部先指向行;然后外部整体*(*(a+i)+j)后指向列,

             ------>!!!即先指向第(a+i)行,再指向该行的第(a[i]+j)列;!!!<------

③*(*(a+i)+j)    //同上

④(*(a+i))[j]     //每次指向a+1行后,再通过[j]指向列

⑤*(&a[0][0]+4*i+j)    //4*i代表 前行第一列和后行第一列隔4个存储单位

=========================================================================

 eg:用地址表示法输出二维数组各元素大的值: 

#include <stdio.h>
int main(){
	int a[2][3]={{1,2,3},{4,5,6}} ;
	int i,j,p,*x;
	printf("a数组为:\n");
	for(i=0;i<2;i++){
	 for(j=0;j<3;j++)
	 	printf("%3d",*(a[i]+j));
	 	printf("\n"); 
	}
}

​

(1)指向二维数组的指针变量

①指向数组元素的指针变量:

eg:用指针变量输出二维数组的值:

#include <stdio.h>
int main(){
	int a[2][3]={{1,3,5},{7,9,11}};
	int *p;
	for(p=a[0];p<a[0]+6;p++)
		printf("%3d",*p);
	return 0;
}

②指向一维数组的指针变量或行指针:

=========================================================================

行指针的说明形式如下:

类型符  (*指针变量名)[每行的元素个数]

例如:int (*p)[4] , a[3][4]; //注意不要掉*p的括号别掉了

含义:定义了一个指针p,指向了一个具有4个元素的一维数组(二维数组的行数组),即用p来定义二维数组中的行地址。引用了行指针p后,p++表示指向下一行地址,p的值应该以一行占用存储字节数为单位进行调整。

=========================================================================

eg:用指向一维数组的行指针,输出二维数组,输出一行后换行:

#include <stdio.h>
int main(){
	int i,j,x;
	int a[3][4]={{1,3,4,9},{23,17,36,34},{73,88,33,12}};
	int (*p)[4];
	p=a;
	for(i=0;i<3;i++){
		for(j=0;j<4;j++)
			printf("%3d",*(*p+j));
		p++;
		printf("\n");
	}
}

eg:用指向一维数组的行指针,输出二维数组,并求数组中的最大元素及其行列号:


#include <stdio.h>
int main(){
	int i,j,s,t,max;
	int a[3][4]={{1,3,4,9},{23,17,36,34},{73,88,33,12}};
	int (*p)[4];
	p = a;
	max = **p;s=0;t=0;
	for(i=0;i<3;i++){
		for(j=0;j<4;j++)
			if(*(*p+j)>max)
			{max=*(*p+j);s=i;t=j;}
		p++;
	}
	printf("最大值=%d,行号=%d,列号=%d\n",max,s,t);
	return 0;		
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值