指针(二)
来源:互联网 发布: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种情况:
- 形参与实参都用数组名
- 实参用数组名,形参用指针变量
- 实参形参均用指针变量
- 实参为指针变量,形参为数组名
不管采用上述四种哪一种方式,他们都是地址的传递,只是形式不同而已。
注意:
指针变量在作实参时,必须有确定的值,即指向一个已定义的单元。如下面这种操作就是错误的:
实际上可以这么来做:
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;}
- 指针与字符串数组
字符串数组:数组中的每个元素都是存放字符的数组,也就是说字符串数组的每一行可存放一个字符串。
可以用赋初值的方式给字符串数组赋值。有两种方法:
- 直接给字符串数组赋初值
- 用指针数组处理多个字符串
直接给字符串数组赋初值:
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为指向函数的指针,该函数返回一个整型值
指针在使用前一定要赋值,指针可以指向任何数据类型,指向谁,就存谁的地址。
必须用地址值为指针变量初始化(&变量名,或数组名),不允许用整数。
相同类型的指针可以相互赋值。
优点:快速灵活、可实现动态分配;缺点:易出错。
- 指针(二)字符串指针
- 指针(二)
- 指针(二)
- 指针(二)
- 指针(二)
- 指针(二)
- 指针程序设计(二)
- 指针(二)
- 指针(二)
- 指针基础知识(二)
- 指针入门(二)
- 指针(二)
- 指针(二)
- 智能指针(二)
- 智能指针(二)
- 指针讲解(二)
- 指针(二)
- c++指针(二)
- 关于Python操作Mysql数据库时SQL语句的格式问题(mysql语句中的双引号问题)
- 微信小程序常见问题->上传文件后如何在后台(php)获取文件名解决方法
- C++命名空间
- labview定时循环控件不显示
- test
- 指针(二)
- caffe中nvcc编译目标GPU指令集的命令选项
- Cordova create project error 解决方法
- BZOJ 1013-球形空间产生器sphere(高斯消元)
- hdu 1907 Jone 尼姆博弈
- 对话框操作
- “玲珑杯”线上赛 Round #17 河南专场 D -.妩钶取玳°月(FFT)
- 动态链接库的显示加载和隐式加载的区别
- Java中级开发工程师知识点归纳