指针(二)

来源:互联网 发布:mysql 语句编写 编辑:程序博客网 时间:2024/06/14 10:24

指针与函数

  • 指针变量做函数参数

函数的参数不仅可以是整型、实型、字符型,还可以是指针型,它的作用是将一个变量的地址传送到另外一个函数中。
观察下面这段代码:

#include<stdio.h>void swap(int *p1,int *p2){   int *p;   p=p1;   p1=p2;   p2=p;}int main(){   int a,b;   int *pa,*pb;   scanf("%d%d",&a,&b);   pa=&a;   pb=&b;   if(a<b)swap(pa,pb);   printf("%d,%d\n",*pa,*pb);   return 0;}

我们来考虑通过改变指针形参的值能否改变指针实参的值?
答案是不能,即实参和形参间的数据是单项值传递的,指针做函数参数也遵循该原则。

再来观察下面的代码:

#include<stdio.h>void swap(int *p1,int *p2){   int t;   t=*p1;   *p1=*p2;   *p2=t;}int main(){   int a,b;   int *pa,*pb;   scanf("%d%d",&a,&b);   pa=&a;   pb=&b;   if(a<b)swap(pa,pb);   printf("%d,%d\n",a,b);   return 0;}

我们再来分析上述使用指针做形参和实参的问题。
可以看到我们把刚才swap函数里面交换p1和p2这两个指针变量的值改为交换p1、p2这两个指针变量所指的那两个单元的内容。即交换指针所指变量的值。如果此时输入两个数1、2那么输出的结果将是2,1。
结论:被调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。

  • 数组名做函数参数

(我们知道形参与实参之间的数据传递是单向值传递方式,指针做函数参数也同样遵循这个原则,也就是说被调用函数不能改变实参指针变量的值,但是可以改变实参指针变量所指向变量的值,由于数组名就是数组的首地址)当用数组名作为参数时,如果形参数组中元素的值发生变化,实参数组元素的值也发生变化。即若有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下4种情况:

  1. 形参与实参都用数组名
  2. 实参用数组名,形参用指针变量
  3. 实参形参均用指针变量
  4. 实参为指针变量,形参为数组名

不管采用上述四种哪一种方式,他们都是地址的传递,只是形式不同而已。

注意:
指针变量在作实参时,必须有确定的值,即指向一个已定义的单元。如下面这种操作就是错误的:
这里写图片描述
实际上可以这么来做:

int main(){    int a[10],*p=a; //先定义一个一维数组,把数组的名字赋给指针变量    f(p,10);    ......}

下面举个栗子:用选择法对10个整数由小到大排序(四种方式实现)。

[方法1]:形参和实参都用数组名

#include<stdio.h>void sort(int[],int);int main(){   int i,a[10];   for(i=0;i<10;i++)      scanf("%d",&a[i]);   sort(a,10); //实参是数组名   for(i=0;i<10;i++)      printf("%3d",a[i]);   return 0;}void sort(int x[],int n){ //形参是数组名   int i,j,k,t;   for(i=0;i<n-1;i++){      k=i;      for(j=i+1;j<n;j++)         if(x[j]<x[k])k=j;      if(k!=i)         {t=x[k];x[k]=x[i];x[i]=t;}   }}

[方法2]:形参是数组名,实参是指针变量

#include<stdio.h>void sort(int[],int);int main(){   int i,a[10],*p;   p=a;   for(i=0;i<10;i++)      scanf("%d",p++);   p=a;   sort(p,10);  //实参是指针   for(i=0;i<10;i++)      printf("%3d",*p++);   return 0;}void sort(int x[],int n){ //形参是数组名   int i,j,k,t;   for(i=0;i<n-1;i++){      k=i;      for(j=i+1;j<n;j++)         if(x[j]<x[k])k=j;      if(k!=i)         {t=x[k];x[k]=x[i];x[i]=t;}   }}

[方法3]:实参是数组名,形参是指针变量

#include<stdio.h>void sort(int *,int);int main(){   int i,a[10];   for(i=0;i<10;i++)      scanf("%d",&a[i]);   sort(a,10); //实参是数组名   for(i=0;i<10;i++)      printf("%3d",a[i]);   return 0;}void sort(int *x,int n){ //形参是指针变量   int i,j,k,t;   for(i=0;i<n-1;i++){      k=i;      for(j=i+1;j<n;j++)         if(*(x+j)<*(x+k))k=j;      if(k!=i)         {t=*(x+k);*(x+k)=*(x+i);*(x+i)=t;}   }}

[方法4]:实参和形参都是指针变量

#include<stdio.h>void sort(int *,int);int main(){   int i,a[10],*p;   p=a;   for(i=0;i<10;i++)      scanf("%d",p++);   p=a;   sort(p,10); //实参为指针变量   for(i=0;i<10;i++)      printf("%3d",*p++);   return 0;}void sort(int *x,int n){ //形参为指针变量   int i,j,k,t;   for(i=0;i<n-1;i++){      k=i;      for(j=i+1;j<n;j++)         if(*(x+j)<*(x+k))k=j;      if(k!=i)         {t=*(x+k);*(x+k)=*(x+i);*(x+i)=t;}   }}

下面这个栗子:编写函数,删除字符串中的给定字符

#include<stdio.h>void delete(char d[],char f);int main(){   char str[]="How,are,you!",*p=str,c=',';   printf("original string is:%s\n",p);   delete(p,c);   printf("compressed string is:%s\n",str);   return 0;}void delete(char d[],char f){   int i=0,k=0;   while(d[i]!='\0'){      if(d[i]!=f)         d[k++]=d[i];      i++;   }   d[k]='\0';}

在上述这个栗子中实参分别是字符型指针变量和字符型变量,对应的子函数的形参分别是字符型数组名和字符型变量。

  • 返回指针的函数

返回指针的函数的定义形式:
类型说明符 *函数名([形式参数表]){
[说明部分]
语句
}
说明:表示函数的返回值是一个指针,其他和一般函数相同。如:

int *f(int x,int y){......}

看下面这个栗子:在给定的字符串s中,寻找一个特定的字符x,若找到x,则返回x在s中第一次出现的位置,并把s中该字符和该字符之前的字符按逆序输出。

#include<stdio.h>char *str(char *s,char x);int main(){   char s[40],*p,x;   gets(s);   x=getchar();   p=str(s,x);   if(*p){      printf("%c",*p);         while(p-s){            p--;            printf("%c",*p);         }   }   else      printf("char %c not found",x);   return 0;}char *str(char *s,char x){   int c=0;   while(x!=s[c]&&s[c]!='\0')      c++;   return (&s[c]);}

运行结果如下:
这里写图片描述

指针数组

指针数组:数组中的元素均为指针类型。适合用来指向字符串
定义形式:数据类型 *数组名[常量表达式]
int *pa[6];
注意:下标运算符[]比*优先级高,因此pa先与[6]结合,形成pa[6],具有6个元素。然后再与*结合,表示此数组中每一个元素都是指针型的。功能即定义一个由6个指针变量构成的指针数组,数组中的每一个元素都是一个指向一个整数的指针变量。
这里写图片描述
指针数组的初始化:必须用地址值为指针数组初始化。如:

int a[3][3]={1,2,3,4,5,6,7,8,9},*pa[3];pa[0]=a[0];pa[1]=a[1];pa[2]=a[2];

指针数组pa[3]相当于有三个指针,*pa[0],*pa[1],*pa[2],上面初始化的结果:
这里写图片描述
这就使得这三个指针分别指向了这个二维数组的每一行,这三个指针的初值就是这个二维数组的每一行的首地址。
注意: int *p[5];int (*p)[5];不同。前者是指针数组而后者改变了运算顺序,先运算括号内的说明p是一个指针,之后再结合下标运算符,说明这个指针变量指向尺寸是5的数组。
指针数组的使用:用指针数组和用数组地址引用数组元素是等价的。
这里写图片描述
上面这些用法都是等价的,区别在于pa[i]的值可变,而a[i]的值不可变
下面这个栗子实现了求N阶方阵副对角线上的元素之和

#include<stdio.h>#define N 4int main(){   int a[N][N],i,j,sum=0,*p[N];   for(i=0;i<N;i++)      p[i]=a[i];   for(i=0;i<N;i++)      for(j=0;j<N;j++)         scanf("%d",p[i]+j);   for(i=0;i<N;i++)      for(j=0;j<N;j++)         if(i+j==N-1)          //副对角元素上的元素行号与列号相加恰好         //就是二维数组的最大的元素下标,也就是说i+j=n-1。            sum+=p[i][j];   printf("sum=%d\n",sum);   return 0;}
  • 指针与字符串数组

字符串数组:数组中的每个元素都是存放字符的数组,也就是说字符串数组的每一行可存放一个字符串。
可以用赋初值的方式给字符串数组赋值。有两种方法:

  1. 直接给字符串数组赋初值
  2. 用指针数组处理多个字符串

直接给字符串数组赋初值:

char b[4][8]={"VC","FORTRAN","BASIC","Foxpro"};

存储形式如下:
这里写图片描述
由于字符串长短不一,定义时应考虑最长的串和结束标志的位置。防止造成内存单元浪费。

用指针数组处理多个字符串
若有定义:

char *f[4]={"VC","FORTRAN","BASIC","Foxpro"};

此定义还可以写成:

char *f[]={"VC","FORTRAN","BASIC","Foxpro"};

则数组f中的每个元素都存放着对应的一个字符串的首地址,各字符串依次存入各相应的首地址开始的连续存储单元中。
这里写图片描述
与第一种方法相比它不需要分配32个存储空间,大大节省了存储空间
下面这个栗子实现了用指针数组输出多个字符串

#include<stdio.h>int main(){   char *s[4]={"cat","pig","dog","all animals"};   int i;   for(i=0;i<4;i++)      printf("%s\n",s[i]);   return 0;}

下面这个栗子实现了将4个字符串从小到大排序后输出

#include<stdio.h>#include<string.h>void fsort(char *color[],int n);int main(){   int i;   char *p[]={"red","blue","yellow","green"};   fsort(p,4);   for(i=0;i<4;i++)      printf("%s\n",p[i]);   return 0;}//冒泡排序void fsort(char *color[],int n){   int k,j;   char *temp;   for(k=1;k<n;k++)      for(j=0;j<n-k;j++)      if(strcmp(color[j],color[j+1])>0){         temp=color[j];         color[j]=color[j+1];         color[j+1]=temp;      }}

初始时:
这里写图片描述
排序后:
这里写图片描述

指针小结

int *p; //p为指向整型数据的指针变量int *p[N]; //定义指针数组p,它由N个指向整数的指针元素组成int (*p)[N]; //定义指向N个元素的一维数组的指针变量pint *p(); //p为带回一个指针的函数,该指针指向整型数据int (*p)(); //p为指向函数的指针,该函数返回一个整型值

指针在使用前一定要赋值,指针可以指向任何数据类型,指向谁,就存谁的地址。
必须用地址值为指针变量初始化(&变量名,或数组名),不允许用整数。
相同类型的指针可以相互赋值。
优点:快速灵活、可实现动态分配;缺点:易出错。

原创粉丝点击