C语言第七课:指针(中)

二、指针变量与一维数组

要记住的方法就是以下3点:

  1. 指针=&数组名[某数]
  2. *指针=指针指定的变量的值
  3. 指针+i=&数组名[某数+i](一维数组特别的性质)

举个例子:

int *p,*q,a[3]={5,10,15};
p=&a[0];
q=&a[1];

我们定义了一个数组a,它有三个元素。三个元素分别是a[0]=5,a[1]=10,a[2]=15。然后定义了指针p和指针q,让p指向的是a[0],让q指向的是a[1],所以*p代表的就是5,*q代表的就是10。因为指针p关联的是a[0],所以p+1关联的就是a[1],p+2关联的是a[2]。同理,因为指针q关联的是a[1],所以,a[0]就是q-1,a[2]就是q+1。

当然,我们依然可以通过指针来改变数组里元素的值。比如:

int *p,*q,a[3]={5,10,15};
p=&a[0];
q=&a[1];
*p=*p*2;
*(q+1)=*p*2;

因为指针p指向的是a[0],所以语句*p=*p*2的意思就是a[0]=a[0]*2;所以a[0]的值变成了10。同样,因为q+1指向的是a[2],p指向的是a[0],所以语句*(q+1)=*p*2就相当于a[2]=a[0]*2,所以a[2]的值变成了20。

明白这些以后,我们可以来练习一道题目了:

例:一个整型数组里的5个元素由键盘输入,将每个元素变为原来的两倍后再依次输出。请用指针来编程。

方法一(我们先不用指针来完成这道练习,很简单):

#include<stdio.h>

int main()
{
    int i,a[5];
    printf("请输入5个整数:\n");
    for(i=0;i<=4;i++)
    {
        scanf("%d",&a[i]);
        a[i]=a[i]*2;
    }
    printf("加倍后的整数位:\n");
    for(i=0;i<=4;i++)
    {
        printf("%d\t",a[i]);
    }
    printf("\n");
    
    return 0;
} 

方法二(用指针来完成这道练习):

#include<stdio.h>

int main()
{
    int i,a[5];
    int *p;
    p=&a[0];
    printf("请输入5个整数:\n");
    for(i=0;i<=4;i++)
    {
        scanf("%d",p+i);
        *(p+i)=*(p+i)*2;
    }
    printf("加倍后的整数位:\n");
    for(i=0;i<=4;i++)
    {
        printf("%d\t",*(p+i));
    }
    printf("\n");
    
    return 0;
} 

跟之前的代码相比,我们要定义一个指针变量p,并且将指针变量与数组的第一个元素相关联。剩下的改动,我们对比一下代码,一下就能明白了:首先,因为p=&a[0],所以p+1=&a[1],p+2=&a[2],p+3=&a[3]......p+i=&a[i]。(指针+i=&数组名[某数+i](一维数组特别的性质))。所以原来程序里面的&a[i]可以写成p+i。然后,因为指针p=&a[0],所以*p=a[0](指针=&数组名[某数];*指针=指针指定的变量的值);所以*(p+1)=a[1],*(p+2)=a[2]......*(p+i)=a[i]。所以原来程序中的a[i]可以用*(p+i)代替。

关于这个指针的程序,再多讲一点(再上面代码的基础上再变动一点点):

#include<stdio.h>

int main()
{
    int i,a[5];
    int *p;
    p=&a[0];
    printf("请输入5个整数:\n");
    for(i=0;i<=4;i++)
    {
        scanf("%d",p+i);
        *(p+i)=*(p+i)*2;
    }
    printf("加倍后的整数位:\n");
    for(p=&a[0];p<=&a[4];p++)
    {
        printf("%d\t",*p);
    }
    printf("\n");
    
    return 0;
}
for(p=&a[0];p<=&a[4];p++)
{
    printf("%d\t",*p);
}

这段代码的意思就是:一开始的时候让p关联a[0],然后每执行一次循环就自加1;开始时p关联a[0],所以*p就是a[0]的值,p自加后,也就是p=p+1,因为p关联a[0]的时候,p+1是关联a[1]的,所以此时我们让p=p+1,也就是说让p关联上了a[1],那么此时,我们再输出p的值,输出来的就是a[1]的值。依次类推,随着p的不断自加,还可以输出a[2],a[3],a[4]的值。

最后,关于指针变量与一维数组,再给大家强调两点:
 1.&数组名[某数] 相当于 数组名+某数 比如:(p=&a[0]可以改为p=a+0)
 2.数组名[某数] 相当于*(数组名+某数) 比如:(a[i]=a[i]*2可以改为*(a+i)=*(a+i)*2)

这两条性质对于读程序类的题目至关重要,如果不了解,读程序的时候可能会有点懵逼。

所以方法一和方法二的代码我们可以用上面这两条性质稍作修改:

方法一的代码:

#include<stdio.h>

int main()
{
    int i,a[5];
    printf("请输入5个整数:\n");
    for(i=0;i<=4;i++)
    {
        scanf("%d",&a[i]);
        *(a+i)=*(a+i)*2;//修改的地方
    }
    printf("加倍后的整数位:\n");
    for(i=0;i<=4;i++)
    {
        printf("%d\t",*(a+i));//修改的地方
    }
    printf("\n");
    
    return 0;
}  

方法二的代码:
 

#include<stdio.h>

int main()
{
    int i,a[5];
    int *p;
    p=a+0;//修改的地方
    printf("请输入5个整数:\n");
    for(i=0;i<=4;i++)
    {
        scanf("%d",p+i);
        *(p+i)=*(p+i)*2;
    }
    printf("加倍后的整数位:\n");
    for(i=0;i<=4;i++)
    {
        printf("%d\t",*(p+i));
    }
    printf("\n");
    
    return 0;
} 

三、指针变量与一维数组相关函数

我们先看一下在第五课中讲过的一个程序:

例 :有两个小组,分别有 5 名学生和 10 名学生。请编程输入这些学生的成绩,并调用一个 aver 函数求这两个小组的平均分。

#include<stdio.h>

int main()
{
	float aver(float a[],int n);
	float zu1[5],zu2[10];
	int i;
	printf("请输入第一组学生成绩(5名学生):\n");
	for(i=0;i<=4;i++)
	{
		scanf("%f",&zu1[i]);
	}
	printf("请输入第二组学生成绩(10名学生):\n");
	for(i=0;i<=9;i++)
	{
		scanf("%f",&zu2[i]);
	}
	printf("第一组平均分是:%f\n",aver(zu1,5));
	printf("第二组平均分是:%f\n",aver(zu2,10));
	
	return 0;
} 

float aver(float a[],int n)
{
	float sum=a[0],pingjunshu;
	int i;
	for(i=0;i<n;i++)
	{
		sum=sum+a[i];
	}
	pingjunshu=sum/n;
	return(pingjunshu);
}

在这个程序里,我们在开头声明aver()这个函数和在正文解释这个函数的时候,我们都是在括号里用的数组,并且解释的时候也一直是用数组。在main()函数里使用aver()这个函数的时候,括号里面使用的也是数组的名字。所以这个程序的形参是数组名,实参也是数组名

如果题目要求我们形参使用指针变量,实参也使用指针变量。那我们得增加一些适当得指针变量。增加指针变量的方法其实就是以下3步:

  1. 函数声明:数组名[] 改成 *p
  2. 函数解释:数组名[i] 改成 *(p+i)
  3. 函数使用:数组名 改成 q(使用前需先关联)
#include<stdio.h>

int main()
{
	float aver(float *p,int n); //函数声明 a[]改成*p
	float zu1[5],zu2[10];
	int i;
	int *q1,*q2;
	q1=&zu1[0];
	q2=&zu2[0];
	printf("请输入第一组学生成绩(5名学生):\n");
	for(i=0;i<=4;i++)
	{
		scanf("%f",&zu1[i]);
	}
	printf("请输入第二组学生成绩(10名学生):\n");
	for(i=0;i<=9;i++)
	{
		scanf("%f",&zu2[i]);
	}
	printf("第一组平均分是:%f\n",aver(q1,5)); //函数使用 zu1改成q1
	printf("第二组平均分是:%f\n",aver(q2,10)); //函数使用 zu2改成q2 
    //这里q1与q2都是指针变量,所以在使用前需要定义好这两个指针变量,并且使用前需要先关联。 
	
	return 0;
} 

float aver(float *p,int n) //函数声明 a[]改成*p
{
	//函数解释 
	float sum=*p,pingjunshu; //a[0]改成*(p+0)即*p
	int i;
	for(i=0;i<n;i++)
	{
		sum=sum+*(p+i); //a[i]改成*(p+i)
	}
	pingjunshu=sum/n;
	return(pingjunshu);
}

四、指针变量与二维数组

指针变量与二维数组需要记住的也就是以下3点:

  1. 指针=&数组名[数a][数b]
  2. *指针=指针指定的变量的值
  3. 指针+i=&(数组名[数a][数b]后面第i个元素)(二维数组特别的性质)

干说比较抽象,我们通过例子来讲:

int *p,*q,a[2][3]={{1,2,3},{4,5,6}};
p=&a[0][0];
q=&a[1][1];

定义一个2行3例的元素,定义指针p与指针q,让p指向a[0][0],q指向a[1][1];所以p+1指向a[0][1],p+2指向a[0][2],p+3指向a[1][0],p+4指向a[1][1],p+5指向a[1][2];自加的规律是先把一行加完,然后再加下一行。同理,q+1指向a[1][2],q-1指向a[1][0],q-2指向a[0][2],q-3指向a[0][1],q-4指向a[0][0]。 

同样,也可以通过指针变量加*号来改变原来元素的值:

int *p,*q,a[2][3]={{1,2,3},{4,5,6}};
p=&a[0][0];
q=&a[1][1];
*p=*p*2;
*(q+1)=*p*2;

因为指针p指向的是a[0][0],所以语句*p=*p*2的意思就是a[0][0]=a[0][0]*2。因为q+1指向的是a[1][2],p指向的a[0][0],所以语句*(q+1)=*p*2的意思就是a[1][2]=a[0][0]*2。

明白这些以后,我们来练习一道题目:

例:已知整型二维数组a[3][4]={1,2,3,4,5,6,6,5,4,3,2,1}。请用指针变量输出二维数组各个元素的值。

#include<stdio.h>

int main()
{
	int a[3][4]={1,2,3,4,5,6,6,5,4,3,2,1};
	int *p;
	for(p=&a[0][0];p<=&a[2][3];p++)
	{
		if((p-&a[0][0])%4==0)
		{
			printf("\n");
		}
		printf("%d\t",*p);
	}
	printf("\n");
	
	return 0;
} 

我们定义一个指针变量p,让p关联上数组的第一个元素,然后for循环里面输出p的值再让p自加,一直到p等于数组里的最后一个元素为止。这样我们就实现了从数组第一个元素的值输出到数组的最后一个元素的值。

最后关于指针变量与二维数组还要记住这两条性质:

  1. &数组名[数a][数b] 相当于 数组名[数a]+数b 也相当于 数组名[0]+a*列数+b
  2. 数组名[数a][数b] 相当于 *(数组名[数a]+数b)

所以上面程序中的&a[0][0]可以写成a[0]+0,0省略后就是a[0];&a[2][3]可以写成a[0]+2*4+3(二维数组有4列),运算以下后半部分,结果就是a[0]+11。

五、指针变量与二维数组相关函数

例:有3名学生学习4门课,学生一的成绩分别是65,67,70,60。学生二的成绩分别是80,87,90,81。学生三的成绩分别是90,99,93,98。将上述成绩输入二维数组,并通过函数输出三人的总平均分。

#include<stdio.h>

int main()
{
	void shuchu(float a[][4],int n);
	float fenshu[3][4]={65,67,70,60,80,87,90,81,90,99,93,98};
	shuchu(fenshu,12);
	
	return 0;
}

void shuchu(float a[][4],int n)
{
	float sum=0;
	int i,j;
	for(i=0;i<=2;i++)
	{
		for(j=0;j<=3;j++)
		{
			sum+=a[i][j];
		}
	}
	printf("三人的总平均分为%f\n",sum/n);
}

仔细看这个程序,我们发现形参对应的部分里面都是数组名。实参也是数组名。

如果题目要求我们形参是指针变量,实参是数组名,那就按照以下三步来修改:

  1. 函数声明:数组名[][某数] 改成 *p
  2. 函数解释:数组名[i][j] 改成 *(p+i*列数+j)
  3. 函数使用:数组名 改成 *数组名
#include<stdio.h>

int main()
{
	void shuchu(float *p,int n);
	float fenshu[3][4]={65,67,70,60,80,87,90,81,90,99,93,98};
	shuchu(*fenshu,12);
	
	return 0;
}

void shuchu(float *p,int n)
{
	float sum=0;
	int i;
	//使用指针的时候,原先的双循环是没有必要的,原先双循环的意思就是从0加到11。
	//因为原来是二维数组,所以又得捣腾行又得捣腾列 ,所以用了双重for循环。
	//而当我们转换成为指针的时候,指针是不管行和列的,它就是排着往后加,所以用一个循环语句就够了。 
	for(i=0;i<=11;i++)
	{
		sum+=*(p+i);
	}
	//for(i=0;i<=2;i++)
	//{
		//for(j=0;j<=3;j++)
		//{
			//sum+=*(p+i*4+j);
		//}
	//}
	printf("三人的总平均分为%f\n",sum/n);
}

如果题目要求我们形参是指针变量,实参也是指针变量,那就按照以下三步来修改(前两步没变):

  1. 函数声明:数组名[][某数] 改成 *p
  2. 函数解释:数组名[i][j] 改成 *(p+i*列数+j)
  3. 函数使用:数组名 改成 q(使用前要先关联)
#include<stdio.h>

int main()
{
	void shuchu(float *p,int n);
	float fenshu[3][4]={65,67,70,60,80,87,90,81,90,99,93,98};
	int *q;
	q=&fenshu[0][0];
	shuchu(q,12);//使用指针q前需要先定义,并且和数组的第一个元素相关联 
	
	return 0;
}

void shuchu(float *p,int n)
{
	float sum=0;
	int i; 
	for(i=0;i<=11;i++)
	{
		sum+=*(p+i);
	}
	printf("三人的总平均分为%f\n",sum/n);
}
发布了13 篇原创文章 · 获赞 15 · 访问量 2165

猜你喜欢

转载自blog.csdn.net/weixin_44337241/article/details/104318661