子函数 N-S图前写 完整 函数头,调用处写 具体 调用语句注意参数个数,尽量少用全局变量,使用全局变量要声明全局变量与局部变量通常不重复定义,参数不能重复定义!
gauss( a[][COLNUM] ) { …… }/*COLNUM 必须是常量,多维数组名作参数只第一维长度可省略 */
float p(int n,float x)
{
if(n==0) p(n,x)=1;
else if (n==1) p(n,x)=x;
else p(n,x)=p(n-1,x)+p(n-2,x)*x;
return(p(n,x) );
}/*赋值号左边只能是变量,变量名规则要注意 */
exchange(a[0],a[1])--->exchang(int i,int j){intt tmp;tmp=i;i=j;j=tmp}
excange(a) ---> excange(int b[]){float tmp;tmp=b[0];b[1]=tmp;}
第十章本章重点,
10.1 地址、指针、变量的地址和指针及指针变量
10.2 指针变量的定义、引用及指针变量作参数
10.3(1--3) 数组与指针
10.4 字符串与指针
10,8 指针运算小结
§ 10.1地址 指针 变量的地址或指针 指针变量内存区的每一个字节有一个编号,该编号就内存单元的 地址,又称 指针 。若在程序中定义一个变量,在编译时会给其分配若干内存单元,其中 第一个存储单元的编号称为该变量的地址,又称为该变量的指针
int i; short j,k;
scanf(“%d %d”,&j,&k)
i=j+k; printf(“%d”,k);
通过变量地址存取其值的方式称,直接访问,方式,将变量的地址存放在另一变量 p中,
通过 p访问变量的方式称为 间接访问 方式
short *p
p=&j;scanf(“%d”,p)
p=&k;scanf(“%d”,p)
引:专门设置一种变量,用来存放地址,称之为指针类型的变量,简称指针变量
( 1)利用指针变量向指向的内存单元输入值时应将值放到从起始地址开始的几个字节中?
short j; p=&j; scanf(“%d”,&j);
short *p;scanf(“%d”,p)
答:定义指针变量时已指明它所指向的内存单元中存储的数据类型,称之为指针变量的基类型,由此决定
( 2)如何输出指针变量指向的内存单元的值?
printf(“%d”,j);
printf(“%d”,*p);
答:使用指针运算符 *表示取所指向存储单元的内容思考,输出时如何知道输出几个存储单元中的数据?
§ 10.2 指针变量基类型 *指针变量名;
§ ----定义与赋值例,float * p; float a; p=&a; scanf(“%f”,p);printf(*p);
(1)指针运算符,*” 在变量定义时和参与运算时意义不同
(2) 在定义指针变量时必须指定基类型注意:只能将变量的地址赋给一个指针变量,而不能将一个常数赋给一个指针变量,两者类型不同,零除外 (代表 NULL)!且变量的类型和指针的基类型要一致!
float a; int * pointer_1;
pointer_1=2001;/*错 */ pointer_1=&a; /*错 */
10.2,2 指针变量的引用例 10.1 通过指针变量访问整型变量
#include <stdio.h>
void main ( )
{ int a,b;
int *pointer_1,*pointer_2;
a=100;b=10;
pointer_1=&a;
pointer_2=& b;
printf(“%d,%d\n”,a,b);
printf(“%d,%d\n”,*pointer_1,*pointer_2);
}
运算符“&”和,*”,(优先级同,自右向左 ):
int a;int *pointer; pointer_1=&a;
(1)& * pointer_1 的含义是什么?
与 &a 相同
(2) *&a的含义是什么?
与a等价。
(3) ( *pointer_1)++与 *pointer_1++区别如何?
前者 a++;后者得到的是a的值,且 pointer_1最后指向单元 a 的,下一个,单元,实际移动了 sizeof(int)个字节例 10,2 输入a和b两个整数,考虑如下输出
#include <stdio.h>
void main()
{ int *p 1,*p 2,*p,a,b;
scanf( ″%d,%d ″,&a,&b);
p 1=&a;p2=&b;
if(a<b)
{p=p1;p1=p2;p2=p;}
printf( ″a =%d,b =%d \n ″,a,b);
printf( ″max=%d,min=%d \n ″,*p 1,*p 2);
}
10.2,3 指针变量作为函数参数例 10,3 通过函数实现两数互换排序
#include <stdio.h>
void main()
{ void swap(int *p1,int *p2);
int a,b;
int *pointer1,*pointer2;
scanf(“%d,%d”,&a,&b)
pointer1=&a; pointer2=&b;
if(a<b)swap(pointer1,pointer2) ;
printf(“%d,%d”,a,b);
}
void swap(int *p1,int *p2)
{ int temp;
temp= *p 1;
*p1= *p2;
*p2= temp;
}
/*temp使用前未赋初值,
可能指向一个非法单元 */
*
*
*
void swap1(int x,int y) void swap2(int *p) void swap3(int *p1,int *p2)
{ int temp; { int temp; { int *temp;
temp=x; temp= *p; temp= p1;
x=y; *p= *(p +1); p1 = p2;
y=temp; *(p +1)= temp p2=temp;
} } }
void main( )
{ int a[]={3,5},b[ ]={3,5},c[ ]={3,5};
swap1 (a[0],a[1]); swap2 (b); swap3 (&c[0],&c[1]);
printf(“%d,%d\n%d,%d\n%d,%d\n”,a[0],a[1],b[0],b[1],c[0],c[1]);
}
数组元素作参数是将数组元素的值传递到形参对应的内存空间中,
数组名作参数是将数组名的值(即数组首地址)传递到形参对应的单元中
§ 10.3 数组与指针
int a[10];
*p;
p = &a[0];
或 p = a;
等价于
int *p=&a[0]
或 int *p=a
10.3.1 指向数组元素的指针
10.3,2通过指针引用数组元素
(1)下标法,用下标 /变址运算符 [ ],如 p[i]或 a[i]
(2) 指针法,用指针运算符,如 *p或 *( a+i),与前等价例 10.5 输出数组中的全部元素,注意 a与 p区别
for(i=0;i<10;i++)
printf( ″%d ″,a[i]);
for(i=0;i<10;i++)
printf( ″%d ″,*(a+i));
for(p=a;p<(a +10 ); p++ )
printf( ″%d ″,*p); /*此处不可用 a*/
for( i=0,p=a; i<10; i++)
printf(“%d”,p[i]); /*p可与数组名同样使用 */
例 10.6 用指针变量输出数组元素,注意找问题。
#include <stdio.h>
void main()
{ int *p,i,a[10];
p=a;
for(i=0;i<10;i++ )
scanf( ″%d ″,p++);
printf( ″\n ″);
for( i=0 ;i<10;i++,p++ )
printf( ″%d ″,*p);
}
,p=a
10.3,3 用数组名或指向数组元素的指针作实参或形参
void main()
{
f( int arr[],int n) ;
int array[10];
┇
f (array,10);
┇
}
void f (int arr[],int n )
{
┇
}
f (int *arr,int n)
int *p;
p=array
f (p,int n)
例 10,7 数组反序存放,用数组名作实参和形参 P237
inv (a,10);
实参名与形参名
void inv( int x[ ],int n) /*形参 x是数组名 */
{ int temp,i;
for(i=0;i< n/2;i++)
{
temp=x[i];
x[i]=x[n-1-i];
x[n-1-i ]= temp;
}
return; /*注意仅当返回值类型为空时可省略 */
}
void inv( int *x,int n) /*形参 x为指针变量 */
{ int *p,*i,*j,m,temp;
m= n/2-1;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{t emp= *i; *i= *j; *j= temp;}
/*注意变量名最好规范,本例不好 */
}
例 10.8 数组反序存放,用指针变量作形参和实参 P240
p=a; inv (p,10);
实参为指针变例 10,9 用选择法对10个整数按由大到小顺序排序
#include <stdio.h>
void main()
{ void sort( int x[ ],int n) ;
int *p,i,a[ 10];
p=a;
for(i=0;i<10;i++)
scanf( ″%d ″,p++); /*可用 &a[i]*/
p=a;
sort(p,10); /*可用 a*/
for(p=a,i=0;i<10;i++)
{printf( ″%d ″,*p);p++;}
} /*最好 a[i]*/
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[i]; x[i] = x[k]; x[k] =t;}
}
}
/*实际 x为指针变量,但可像数组名一样用 */
/*注意排序的边界,尤其是冒泡 */
题目:指针程序设计:
要求:用多个函数实现,参数为一维数组时实参用数组名,主函数中访问元素用下标法,形参用指针,子函数中访问元素用指针法;为二维数组时实参和形参都用数组名,访问元素用下标法作业,10.3 10.9 写源码报告,10.6 10.15 写源码补充:第二次综合实验题,输入正整数 n,用 malloc函数动态建立 n个元素的数组,再用选择法 \冒泡法 \和插入法排序回顾:
1、地址 指针 指针类型 变量的指针 指针变量 基类型
2,short i;short *p; p=&i; scanf(“%d”,i);printf(“%d”,*p)
3、用指针访问数组元素 int a[10]; int *p=a;
(1)下标法 for(i=0;i<10;i++)scanf(“%d”,& p[i]);/*同 p+i*/
for(i=0;i<10;i++)printf(“%d”,p[i]); /*同 *(p+i)*/
(2) 指针法 for(p=a;p<a+10;p++)scanf(“%d”,p);
for(p=a;p<a+10;p++)printf(“%d”,*p);
4、数组名与指针作参数调用语句,inv (a,10); 或 p=a;inv(p,10)
函数头,void inv(int b[],int n);或 inv(int *p,int n)
注,(1)函数声明要与函数头格式保持一致!且要正确!
(2) 基类型不同的指针变量属于不同的数据类型,不能相互赋值
( 3)指针的基类型不仅可以是某简单数据类型,还可以是构造数据类型,如二维数组名是指向“一行” 的指针本节要点:
二维数组与指针字符串与指针
void指针类型结构体概念及使用
10.3,4 多维数组与指针
1,多维数组元素的地址:行优先顺序存储,数组名是指向首行的指针,其基类型是一维数组
int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}
a可看作由 3个“元素”组成,每个“元素”是“一行”
表 示 形 式 含义 地 址
a 指向首行,首行 地址,2000
a[0],*(a+0),*a 代表行 0,相当,行 0数组,的数组名 2000
a+1,&a[ 1] 指向行 1,行 1地址 2016
a[ 1],*(a+1) 代表行 1,相当行 1数组的数组名 2016
a[1]+2,*(a+1)+2 &a[1][2] 2024
*(a[1]+2),
*(*(a+1)+2)
a[1][2] 元素值 13
2,用指针访问多维数组
(1)用指向单个元素的指针变量访问二维数组各元素
#include <stdio.h>
void main()
{ int a [3][4]={ 1,3,5,7,9,11,13,15,17,19,21,23};
int *p; /*p的基类型是基本数据类型 int*/
for(p=&a[0][0] ;p<&a[0][0]+12;p++) /*p=a[0]也可 */
{
if((p-&a[0][0])%4= =0)
printf(” \n” );
printf( ″% 5d″,*p);
}
}
(2) 指向多个元素组成的一维数组的指针变量
(a) int ( *p )[4]; /*注意括号不能省,否则是指针数组 */
(b)对 int *p,p+1移动 4字节,对 int (*p)[4]p+1移动 16字节例 12 用指向一行的指针变量输出元素 a(i,j)值
#include <stdio.h>
void main ( )
{ int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int ( *p )[4]; / * p是基类型为一维数组的指针变量,
基类型数组含 4个实型元素 */
int i,j;
p=a;
scanf( ″ %d,%d ″,&i,&j);
printf(” a[%d,%d]=”%d”,i,j,*(*(p+i) +j));
}
3.基类型为一维数组的指针作函数参数例 10.13输出平均成绩与 2号学生成绩
#include <sydio.h>
void main()
{ void average( float *p,int n);
void search( float (*p)[4],int n);
float score[3][4]={{65,67,70,60},{80,
87,90,81},{90,99,100,98}};
average( &score[0][0],12);/ *可用 *score*/
search( score,2);/ *指向 0行,基类型为一维数组 */
}
void average( float *p,int n)
{ float *p _end;
float sum=0,aver;
p _end=p+n-1;
for(;p<=p _end;p++)
sum=sum+( *p);
aver=sum/n;
printf( ″average=%5.2f\n ″,aver);
}
void search( float (*p )[4],int n)
{ int i;
printf( ″the score of No,%d are:\n ″,n);
for(i=0;i<4;i++ )
printf( ″% 5.2f ″,*( *(p+n)+i));
}
§ 10.4 字符串与指针
10.4.3 字符数组与字符指针变量区别 (P257)
char str [7]=“China!”; 或 char str []=“I love China!”
scanf(“%s”,str); printf( ″%s\n ″,str);
char *string=“China!”; 或 char * str; str =,china!” ;
printf(“%s”,str)合法
printf(“%s”,str) 不合法注 (1)字符数组会开辟可修改的内存单元,而字符串常量所在内存单元不能被修改
( 2)对二维字符数组 char name[3][20],name[0]、
name[1],name[2]分别代表各行,相当各行对应数组的数组名,故输入可用 for(i=0;i<3;i++) gets(name[0])
10.8.3 void指针类型 P277
定义一个指针变量,其基类型为 void,使用时根据需要进行强制类型转换如 stdlib.h中声明有如下动态内存分配函数
void *malloc(unsigned int size)
作用分配一长度为 size字节的连续空间,返回一个指向分配区域首址的指针,分配不成功则返回 NULL.
int n,*p; scanf(“%d”,&n); p=(int *)malloc(n*sizeof(int));
考虑为什么要进行强制类型转换?
(int*)不要是否可以?
小结:
1、地址 指针 指针类型 变量的指针 指针变量 基类型
2,short i;short *p; p=&i; scanf(“%d”,i);printf(“%d”,*p)
3、用指针访问数组元素
int a[10],b[2][3]; int *p1=a;int(*p2)[3];p2=a;
(1)下标法 for(i=0;i<10;i++)scanf(“%d”,&p[i]);/*同 p+i*/
for(i=0;i<10;i++)printf(“%d”,p[i][j]);
(2) 指针法 for(p=a;p<a+10;p++)scanf(“%d”,p);
for(p=a;p<a+10;p++)printf(“%d”,*(*(p+i)+j));
4、数组名与指针作参数调用语句,inv (b,2); 或 p2=a;inv(p2,2)
函数头,void inv(int b[][3],int n);或 inv(int (*p)[3],int n)
5、字符数组与字符串常量的区别要注意,且会以下技巧
char name[3][20]; for(i=0;i<3;i++) gets(name[0]);
6、基类型为 void的指针变量
int n,*p; scanf(“%d”,&n); p=(int *)malloc(n*sizeof(int));
作业:矩阵转置,用基类型为一维数组的指针变量作形参,
访问矩阵元素用指针法。 注意:
for(i=0;i<3;i++)
for(j=i;j<3;j++) /*还可写为 j=i+1;但不可写为 j=0;*/
{ tmp=a[i][j];a[i][j]=a[j][i];a[j][i]=tmp;}
10.7指针数组和指向指针的指针
10.7,1 指针数组的概念例 int a[4]; int *p [4 ]={a,a+1,a+2,a+3};
char *name[5]={“Follow me”,”BASIC”,”Great
Wall”,,"FORTRAN","Computer design"};
例 10.2 6 将若干字符串按字母顺序(由小到大)输出。
#include <stdio.h>
#include <string.h>
void main()
{ void sort( char *name[ ],int n);
void printf( char *name[ ],int n);
char *name[ ] ={"Follow me","BASIC","Great
Wall″,"FORTRAN","Computer design"};
int n=5;
sort(name,n);
print(name,n);
}
void sort( char *name[ ],int n)
{ char *temp;
int i,j,k;
for(i=0;i<n-1;i++ )
{k=i;
for(j=i+1;j<n;j++ )
if( strcmp(name[k ],name[j] ) >0)k =j;
if(k !=i)
{temp=name[i];name[i]=name[k];name[k]=temp;}
}
} void print( char *name[],int n)
{int i;
for(i=0;i<n;i++) printf(“%s”,name[i]);
}
注 1:矩阵转置
for(i=0;i<3;i++)
for(j=i;j<3;j++) /*还可写为 j=i+1;但不可写为 j=0;*/
{ tmp=a[i][j];a[i][j]=a[j][i];a[j][i]=tmp;}
注 2:字符串常量在内存中占有一定的空间,故 P258
char *a; a=“I love China”可以,而 char *a; scanf(“%s”,a)
危险 ;但字符串常量只能读不能写,如 a[0]=?y?不可,但对于
char b[]=,I love China!”,由于重新分配了数组空间,并将字符串常量复制到了新数组中,故 b[0]=?y?可以,P255*?[ ]
注 3:对于 int a[3][3];若定义 int *p,则初始化时用 p=a[0],访问元素用 *(p+3*i+j);若定义 int (*p)[3],则应用 p=a初始化,
访问元素用 *(*(p+i)+j);读入元素时将第一个 *去掉即可,
注 4:地址不同于一般常数,属于指针类型,不可将一个整常数赋给一个指针 (0除外 ).又 如 p246例 11,
int a[3][4];int *p=a[0];p++;p-a[0]=?
3、动态内存分配函数,
/*假设动态内存分配区大小共 1000字节 */
char alloc[1000];/*用以标志此存储区,alloc始终指向首址 */
char *allocp=allocbuf; /*allocp用以记录可用地址首址 */
char *alloc(int n) /*子函数,从动态内存分配区分配 n字节 */
{if(allocp+n<=allocbuf+1000)
{ allocp+=n; return(allocp-n); }
else return(NULL);
}
free(char *p)
{if(p>=allocbuf&&p<allocbuf+1000)allocp=p; }
#include<stdio.h>
#include <malloc.h>
void main( )
{ int i,j,n,tmp,*a;
printf(“输入数组长度,”); scanf(“%d”,&n);
a=(int *)malloc(n*sizeof(int));
if(a==NULL){printf(“空间分配失败,\n”); exit(0);}
printf(“输入 %d个整型数据,\n”,n);
for(i=0; i<n; i++) scanf(“%d”,a+i);
for(i=0; i<n; i++)
for(j=0; j<n-i-1; j++)
if(p[j]<p[j+1]){tmp=a[j],a[j]=a[j+1],a[j+1]=tmp;}
for(i=0; i<n; i++) printf(“%8d”,a[i]);
free(a);/*释放指针 a所指的内存区 */
}
10.5 指向函数的指针
10.5,1 用函数指针变量调用函数一个函数在编译时被分配给一个入口地址,函数名即为该入口地址,这个 函数的入口地址又称函数的指针,
可用指针变量指向一个函数,之后 *p就代表这个函数定义形式,
数据类型 (*指针变量名 ) (函数参数列表 )/*括号不可省 */
如对函数 int max(int x,int y){return(x>y?x:y);}可如下定义一个函数指针变量来指向它
int (*p)(int,int );p=max;之后 *p(4,5)就代表 max(4,5)
例 10.2 3 设一个函数 process,输入两个数,第一次调用 process时求大者,第二次求小者,第三次求和。
#include <stdio.h>
void main()
{ int max( int,int) ; /* 函数声明 */
int min( int,int) ; /* 函数声明 */
int add( int,int); /* 函数声明 */
void process (int,int,int(*fun)(int,int)); /* 函数声明 */
int a,b;
scanf( ″%d,%d ″,&a,&b);
process(a,b,max);
process(a,b,min);
process(a,b,add);
}
int add( int x,int y) /* 函数定义 */
{int z;
z=x+y;
return(z);
}
void process(int x,int y,int (*fun)(int,int))
{int result;
result=( *fun)(x,y);
printf( ″%d\n ″,result);
}
/*增强程序通用性,如通用定积分计算函数可如下定义
float integral(float a,float b,float(*fun)(float)) */
10.6 返回指针值的函数一般定义形式为类型名 *函数名(参数表列) ;
例如,int *a( int x,int y) ;
float score[50][4]; float *p;
float * search(float (*pointer)[4],int n )
{ float *pt;
pt= *(pointer+n);
return(pt);
} ……
p= search(score,m);
for(i=0;i<4;i++)printf(“%5.2f”,*(p+i));
例 24,有4门课程,要求输入学号后输出该学生全部成绩
10.7指针数组和指向指针的指针
10.7,1 指针数组的概念例 int a[4]; int *p [4 ]={a,a+1,a+2,a+3};
char *name[5]={“Follow me”,”BASIC”,”Great
Wall”,,"FORTRAN","Computer design"};
10.7.2 指向指针的指针定义,基类型 **变量名
#include <stdio.h>
void main()
{ char *name[ ]={"Follow me","BASIC","Great
Wall″,"FORTRAN","Computer design"};
char **p;
int i;
for(i=0;i<5;i++)
{p=name+i;
printf( ″%s\n ″,*p);
}
}
p
例2 7 使用指向指针的指针
10.7,3 指针数组作 main函数的形参形式,void main( int argc,char *argv[ ])
main函数是由操作系统调用的。其形参的值不能在程序中得到,实际上实参是和命令一起给出的,调用形式为命令名 参数 1,参数 2,…,参数 n
其中 argc代表命令行中参数个数,由系统给出,argv是指向字符串的指针数组如假设 file1.c中有如上 main函数,对于命令行,
file1.exe China Beijing
执行后 argc=3,argv argv[0]
argv[1]
argv[2]
file1.exe
China
Beijing
设 file1.c中有如下语句,
void main( int argc,char *argv[])
{ while(argc>1)
{ ++argv;
printf(“% s\n”,argv);
- -argc;
}
}
在 DOS命令状态下输入的命令行为
file1.exe China Beijing
则执行以上命令行将会输出以下信息:
China
Beijing
gauss( a[][COLNUM] ) { …… }/*COLNUM 必须是常量,多维数组名作参数只第一维长度可省略 */
float p(int n,float x)
{
if(n==0) p(n,x)=1;
else if (n==1) p(n,x)=x;
else p(n,x)=p(n-1,x)+p(n-2,x)*x;
return(p(n,x) );
}/*赋值号左边只能是变量,变量名规则要注意 */
exchange(a[0],a[1])--->exchang(int i,int j){intt tmp;tmp=i;i=j;j=tmp}
excange(a) ---> excange(int b[]){float tmp;tmp=b[0];b[1]=tmp;}
第十章本章重点,
10.1 地址、指针、变量的地址和指针及指针变量
10.2 指针变量的定义、引用及指针变量作参数
10.3(1--3) 数组与指针
10.4 字符串与指针
10,8 指针运算小结
§ 10.1地址 指针 变量的地址或指针 指针变量内存区的每一个字节有一个编号,该编号就内存单元的 地址,又称 指针 。若在程序中定义一个变量,在编译时会给其分配若干内存单元,其中 第一个存储单元的编号称为该变量的地址,又称为该变量的指针
int i; short j,k;
scanf(“%d %d”,&j,&k)
i=j+k; printf(“%d”,k);
通过变量地址存取其值的方式称,直接访问,方式,将变量的地址存放在另一变量 p中,
通过 p访问变量的方式称为 间接访问 方式
short *p
p=&j;scanf(“%d”,p)
p=&k;scanf(“%d”,p)
引:专门设置一种变量,用来存放地址,称之为指针类型的变量,简称指针变量
( 1)利用指针变量向指向的内存单元输入值时应将值放到从起始地址开始的几个字节中?
short j; p=&j; scanf(“%d”,&j);
short *p;scanf(“%d”,p)
答:定义指针变量时已指明它所指向的内存单元中存储的数据类型,称之为指针变量的基类型,由此决定
( 2)如何输出指针变量指向的内存单元的值?
printf(“%d”,j);
printf(“%d”,*p);
答:使用指针运算符 *表示取所指向存储单元的内容思考,输出时如何知道输出几个存储单元中的数据?
§ 10.2 指针变量基类型 *指针变量名;
§ ----定义与赋值例,float * p; float a; p=&a; scanf(“%f”,p);printf(*p);
(1)指针运算符,*” 在变量定义时和参与运算时意义不同
(2) 在定义指针变量时必须指定基类型注意:只能将变量的地址赋给一个指针变量,而不能将一个常数赋给一个指针变量,两者类型不同,零除外 (代表 NULL)!且变量的类型和指针的基类型要一致!
float a; int * pointer_1;
pointer_1=2001;/*错 */ pointer_1=&a; /*错 */
10.2,2 指针变量的引用例 10.1 通过指针变量访问整型变量
#include <stdio.h>
void main ( )
{ int a,b;
int *pointer_1,*pointer_2;
a=100;b=10;
pointer_1=&a;
pointer_2=& b;
printf(“%d,%d\n”,a,b);
printf(“%d,%d\n”,*pointer_1,*pointer_2);
}
运算符“&”和,*”,(优先级同,自右向左 ):
int a;int *pointer; pointer_1=&a;
(1)& * pointer_1 的含义是什么?
与 &a 相同
(2) *&a的含义是什么?
与a等价。
(3) ( *pointer_1)++与 *pointer_1++区别如何?
前者 a++;后者得到的是a的值,且 pointer_1最后指向单元 a 的,下一个,单元,实际移动了 sizeof(int)个字节例 10,2 输入a和b两个整数,考虑如下输出
#include <stdio.h>
void main()
{ int *p 1,*p 2,*p,a,b;
scanf( ″%d,%d ″,&a,&b);
p 1=&a;p2=&b;
if(a<b)
{p=p1;p1=p2;p2=p;}
printf( ″a =%d,b =%d \n ″,a,b);
printf( ″max=%d,min=%d \n ″,*p 1,*p 2);
}
10.2,3 指针变量作为函数参数例 10,3 通过函数实现两数互换排序
#include <stdio.h>
void main()
{ void swap(int *p1,int *p2);
int a,b;
int *pointer1,*pointer2;
scanf(“%d,%d”,&a,&b)
pointer1=&a; pointer2=&b;
if(a<b)swap(pointer1,pointer2) ;
printf(“%d,%d”,a,b);
}
void swap(int *p1,int *p2)
{ int temp;
temp= *p 1;
*p1= *p2;
*p2= temp;
}
/*temp使用前未赋初值,
可能指向一个非法单元 */
*
*
*
void swap1(int x,int y) void swap2(int *p) void swap3(int *p1,int *p2)
{ int temp; { int temp; { int *temp;
temp=x; temp= *p; temp= p1;
x=y; *p= *(p +1); p1 = p2;
y=temp; *(p +1)= temp p2=temp;
} } }
void main( )
{ int a[]={3,5},b[ ]={3,5},c[ ]={3,5};
swap1 (a[0],a[1]); swap2 (b); swap3 (&c[0],&c[1]);
printf(“%d,%d\n%d,%d\n%d,%d\n”,a[0],a[1],b[0],b[1],c[0],c[1]);
}
数组元素作参数是将数组元素的值传递到形参对应的内存空间中,
数组名作参数是将数组名的值(即数组首地址)传递到形参对应的单元中
§ 10.3 数组与指针
int a[10];
*p;
p = &a[0];
或 p = a;
等价于
int *p=&a[0]
或 int *p=a
10.3.1 指向数组元素的指针
10.3,2通过指针引用数组元素
(1)下标法,用下标 /变址运算符 [ ],如 p[i]或 a[i]
(2) 指针法,用指针运算符,如 *p或 *( a+i),与前等价例 10.5 输出数组中的全部元素,注意 a与 p区别
for(i=0;i<10;i++)
printf( ″%d ″,a[i]);
for(i=0;i<10;i++)
printf( ″%d ″,*(a+i));
for(p=a;p<(a +10 ); p++ )
printf( ″%d ″,*p); /*此处不可用 a*/
for( i=0,p=a; i<10; i++)
printf(“%d”,p[i]); /*p可与数组名同样使用 */
例 10.6 用指针变量输出数组元素,注意找问题。
#include <stdio.h>
void main()
{ int *p,i,a[10];
p=a;
for(i=0;i<10;i++ )
scanf( ″%d ″,p++);
printf( ″\n ″);
for( i=0 ;i<10;i++,p++ )
printf( ″%d ″,*p);
}
,p=a
10.3,3 用数组名或指向数组元素的指针作实参或形参
void main()
{
f( int arr[],int n) ;
int array[10];
┇
f (array,10);
┇
}
void f (int arr[],int n )
{
┇
}
f (int *arr,int n)
int *p;
p=array
f (p,int n)
例 10,7 数组反序存放,用数组名作实参和形参 P237
inv (a,10);
实参名与形参名
void inv( int x[ ],int n) /*形参 x是数组名 */
{ int temp,i;
for(i=0;i< n/2;i++)
{
temp=x[i];
x[i]=x[n-1-i];
x[n-1-i ]= temp;
}
return; /*注意仅当返回值类型为空时可省略 */
}
void inv( int *x,int n) /*形参 x为指针变量 */
{ int *p,*i,*j,m,temp;
m= n/2-1;
i=x;j=x+n-1;p=x+m;
for(;i<=p;i++,j--)
{t emp= *i; *i= *j; *j= temp;}
/*注意变量名最好规范,本例不好 */
}
例 10.8 数组反序存放,用指针变量作形参和实参 P240
p=a; inv (p,10);
实参为指针变例 10,9 用选择法对10个整数按由大到小顺序排序
#include <stdio.h>
void main()
{ void sort( int x[ ],int n) ;
int *p,i,a[ 10];
p=a;
for(i=0;i<10;i++)
scanf( ″%d ″,p++); /*可用 &a[i]*/
p=a;
sort(p,10); /*可用 a*/
for(p=a,i=0;i<10;i++)
{printf( ″%d ″,*p);p++;}
} /*最好 a[i]*/
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[i]; x[i] = x[k]; x[k] =t;}
}
}
/*实际 x为指针变量,但可像数组名一样用 */
/*注意排序的边界,尤其是冒泡 */
题目:指针程序设计:
要求:用多个函数实现,参数为一维数组时实参用数组名,主函数中访问元素用下标法,形参用指针,子函数中访问元素用指针法;为二维数组时实参和形参都用数组名,访问元素用下标法作业,10.3 10.9 写源码报告,10.6 10.15 写源码补充:第二次综合实验题,输入正整数 n,用 malloc函数动态建立 n个元素的数组,再用选择法 \冒泡法 \和插入法排序回顾:
1、地址 指针 指针类型 变量的指针 指针变量 基类型
2,short i;short *p; p=&i; scanf(“%d”,i);printf(“%d”,*p)
3、用指针访问数组元素 int a[10]; int *p=a;
(1)下标法 for(i=0;i<10;i++)scanf(“%d”,& p[i]);/*同 p+i*/
for(i=0;i<10;i++)printf(“%d”,p[i]); /*同 *(p+i)*/
(2) 指针法 for(p=a;p<a+10;p++)scanf(“%d”,p);
for(p=a;p<a+10;p++)printf(“%d”,*p);
4、数组名与指针作参数调用语句,inv (a,10); 或 p=a;inv(p,10)
函数头,void inv(int b[],int n);或 inv(int *p,int n)
注,(1)函数声明要与函数头格式保持一致!且要正确!
(2) 基类型不同的指针变量属于不同的数据类型,不能相互赋值
( 3)指针的基类型不仅可以是某简单数据类型,还可以是构造数据类型,如二维数组名是指向“一行” 的指针本节要点:
二维数组与指针字符串与指针
void指针类型结构体概念及使用
10.3,4 多维数组与指针
1,多维数组元素的地址:行优先顺序存储,数组名是指向首行的指针,其基类型是一维数组
int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}
a可看作由 3个“元素”组成,每个“元素”是“一行”
表 示 形 式 含义 地 址
a 指向首行,首行 地址,2000
a[0],*(a+0),*a 代表行 0,相当,行 0数组,的数组名 2000
a+1,&a[ 1] 指向行 1,行 1地址 2016
a[ 1],*(a+1) 代表行 1,相当行 1数组的数组名 2016
a[1]+2,*(a+1)+2 &a[1][2] 2024
*(a[1]+2),
*(*(a+1)+2)
a[1][2] 元素值 13
2,用指针访问多维数组
(1)用指向单个元素的指针变量访问二维数组各元素
#include <stdio.h>
void main()
{ int a [3][4]={ 1,3,5,7,9,11,13,15,17,19,21,23};
int *p; /*p的基类型是基本数据类型 int*/
for(p=&a[0][0] ;p<&a[0][0]+12;p++) /*p=a[0]也可 */
{
if((p-&a[0][0])%4= =0)
printf(” \n” );
printf( ″% 5d″,*p);
}
}
(2) 指向多个元素组成的一维数组的指针变量
(a) int ( *p )[4]; /*注意括号不能省,否则是指针数组 */
(b)对 int *p,p+1移动 4字节,对 int (*p)[4]p+1移动 16字节例 12 用指向一行的指针变量输出元素 a(i,j)值
#include <stdio.h>
void main ( )
{ int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int ( *p )[4]; / * p是基类型为一维数组的指针变量,
基类型数组含 4个实型元素 */
int i,j;
p=a;
scanf( ″ %d,%d ″,&i,&j);
printf(” a[%d,%d]=”%d”,i,j,*(*(p+i) +j));
}
3.基类型为一维数组的指针作函数参数例 10.13输出平均成绩与 2号学生成绩
#include <sydio.h>
void main()
{ void average( float *p,int n);
void search( float (*p)[4],int n);
float score[3][4]={{65,67,70,60},{80,
87,90,81},{90,99,100,98}};
average( &score[0][0],12);/ *可用 *score*/
search( score,2);/ *指向 0行,基类型为一维数组 */
}
void average( float *p,int n)
{ float *p _end;
float sum=0,aver;
p _end=p+n-1;
for(;p<=p _end;p++)
sum=sum+( *p);
aver=sum/n;
printf( ″average=%5.2f\n ″,aver);
}
void search( float (*p )[4],int n)
{ int i;
printf( ″the score of No,%d are:\n ″,n);
for(i=0;i<4;i++ )
printf( ″% 5.2f ″,*( *(p+n)+i));
}
§ 10.4 字符串与指针
10.4.3 字符数组与字符指针变量区别 (P257)
char str [7]=“China!”; 或 char str []=“I love China!”
scanf(“%s”,str); printf( ″%s\n ″,str);
char *string=“China!”; 或 char * str; str =,china!” ;
printf(“%s”,str)合法
printf(“%s”,str) 不合法注 (1)字符数组会开辟可修改的内存单元,而字符串常量所在内存单元不能被修改
( 2)对二维字符数组 char name[3][20],name[0]、
name[1],name[2]分别代表各行,相当各行对应数组的数组名,故输入可用 for(i=0;i<3;i++) gets(name[0])
10.8.3 void指针类型 P277
定义一个指针变量,其基类型为 void,使用时根据需要进行强制类型转换如 stdlib.h中声明有如下动态内存分配函数
void *malloc(unsigned int size)
作用分配一长度为 size字节的连续空间,返回一个指向分配区域首址的指针,分配不成功则返回 NULL.
int n,*p; scanf(“%d”,&n); p=(int *)malloc(n*sizeof(int));
考虑为什么要进行强制类型转换?
(int*)不要是否可以?
小结:
1、地址 指针 指针类型 变量的指针 指针变量 基类型
2,short i;short *p; p=&i; scanf(“%d”,i);printf(“%d”,*p)
3、用指针访问数组元素
int a[10],b[2][3]; int *p1=a;int(*p2)[3];p2=a;
(1)下标法 for(i=0;i<10;i++)scanf(“%d”,&p[i]);/*同 p+i*/
for(i=0;i<10;i++)printf(“%d”,p[i][j]);
(2) 指针法 for(p=a;p<a+10;p++)scanf(“%d”,p);
for(p=a;p<a+10;p++)printf(“%d”,*(*(p+i)+j));
4、数组名与指针作参数调用语句,inv (b,2); 或 p2=a;inv(p2,2)
函数头,void inv(int b[][3],int n);或 inv(int (*p)[3],int n)
5、字符数组与字符串常量的区别要注意,且会以下技巧
char name[3][20]; for(i=0;i<3;i++) gets(name[0]);
6、基类型为 void的指针变量
int n,*p; scanf(“%d”,&n); p=(int *)malloc(n*sizeof(int));
作业:矩阵转置,用基类型为一维数组的指针变量作形参,
访问矩阵元素用指针法。 注意:
for(i=0;i<3;i++)
for(j=i;j<3;j++) /*还可写为 j=i+1;但不可写为 j=0;*/
{ tmp=a[i][j];a[i][j]=a[j][i];a[j][i]=tmp;}
10.7指针数组和指向指针的指针
10.7,1 指针数组的概念例 int a[4]; int *p [4 ]={a,a+1,a+2,a+3};
char *name[5]={“Follow me”,”BASIC”,”Great
Wall”,,"FORTRAN","Computer design"};
例 10.2 6 将若干字符串按字母顺序(由小到大)输出。
#include <stdio.h>
#include <string.h>
void main()
{ void sort( char *name[ ],int n);
void printf( char *name[ ],int n);
char *name[ ] ={"Follow me","BASIC","Great
Wall″,"FORTRAN","Computer design"};
int n=5;
sort(name,n);
print(name,n);
}
void sort( char *name[ ],int n)
{ char *temp;
int i,j,k;
for(i=0;i<n-1;i++ )
{k=i;
for(j=i+1;j<n;j++ )
if( strcmp(name[k ],name[j] ) >0)k =j;
if(k !=i)
{temp=name[i];name[i]=name[k];name[k]=temp;}
}
} void print( char *name[],int n)
{int i;
for(i=0;i<n;i++) printf(“%s”,name[i]);
}
注 1:矩阵转置
for(i=0;i<3;i++)
for(j=i;j<3;j++) /*还可写为 j=i+1;但不可写为 j=0;*/
{ tmp=a[i][j];a[i][j]=a[j][i];a[j][i]=tmp;}
注 2:字符串常量在内存中占有一定的空间,故 P258
char *a; a=“I love China”可以,而 char *a; scanf(“%s”,a)
危险 ;但字符串常量只能读不能写,如 a[0]=?y?不可,但对于
char b[]=,I love China!”,由于重新分配了数组空间,并将字符串常量复制到了新数组中,故 b[0]=?y?可以,P255*?[ ]
注 3:对于 int a[3][3];若定义 int *p,则初始化时用 p=a[0],访问元素用 *(p+3*i+j);若定义 int (*p)[3],则应用 p=a初始化,
访问元素用 *(*(p+i)+j);读入元素时将第一个 *去掉即可,
注 4:地址不同于一般常数,属于指针类型,不可将一个整常数赋给一个指针 (0除外 ).又 如 p246例 11,
int a[3][4];int *p=a[0];p++;p-a[0]=?
3、动态内存分配函数,
/*假设动态内存分配区大小共 1000字节 */
char alloc[1000];/*用以标志此存储区,alloc始终指向首址 */
char *allocp=allocbuf; /*allocp用以记录可用地址首址 */
char *alloc(int n) /*子函数,从动态内存分配区分配 n字节 */
{if(allocp+n<=allocbuf+1000)
{ allocp+=n; return(allocp-n); }
else return(NULL);
}
free(char *p)
{if(p>=allocbuf&&p<allocbuf+1000)allocp=p; }
#include<stdio.h>
#include <malloc.h>
void main( )
{ int i,j,n,tmp,*a;
printf(“输入数组长度,”); scanf(“%d”,&n);
a=(int *)malloc(n*sizeof(int));
if(a==NULL){printf(“空间分配失败,\n”); exit(0);}
printf(“输入 %d个整型数据,\n”,n);
for(i=0; i<n; i++) scanf(“%d”,a+i);
for(i=0; i<n; i++)
for(j=0; j<n-i-1; j++)
if(p[j]<p[j+1]){tmp=a[j],a[j]=a[j+1],a[j+1]=tmp;}
for(i=0; i<n; i++) printf(“%8d”,a[i]);
free(a);/*释放指针 a所指的内存区 */
}
10.5 指向函数的指针
10.5,1 用函数指针变量调用函数一个函数在编译时被分配给一个入口地址,函数名即为该入口地址,这个 函数的入口地址又称函数的指针,
可用指针变量指向一个函数,之后 *p就代表这个函数定义形式,
数据类型 (*指针变量名 ) (函数参数列表 )/*括号不可省 */
如对函数 int max(int x,int y){return(x>y?x:y);}可如下定义一个函数指针变量来指向它
int (*p)(int,int );p=max;之后 *p(4,5)就代表 max(4,5)
例 10.2 3 设一个函数 process,输入两个数,第一次调用 process时求大者,第二次求小者,第三次求和。
#include <stdio.h>
void main()
{ int max( int,int) ; /* 函数声明 */
int min( int,int) ; /* 函数声明 */
int add( int,int); /* 函数声明 */
void process (int,int,int(*fun)(int,int)); /* 函数声明 */
int a,b;
scanf( ″%d,%d ″,&a,&b);
process(a,b,max);
process(a,b,min);
process(a,b,add);
}
int add( int x,int y) /* 函数定义 */
{int z;
z=x+y;
return(z);
}
void process(int x,int y,int (*fun)(int,int))
{int result;
result=( *fun)(x,y);
printf( ″%d\n ″,result);
}
/*增强程序通用性,如通用定积分计算函数可如下定义
float integral(float a,float b,float(*fun)(float)) */
10.6 返回指针值的函数一般定义形式为类型名 *函数名(参数表列) ;
例如,int *a( int x,int y) ;
float score[50][4]; float *p;
float * search(float (*pointer)[4],int n )
{ float *pt;
pt= *(pointer+n);
return(pt);
} ……
p= search(score,m);
for(i=0;i<4;i++)printf(“%5.2f”,*(p+i));
例 24,有4门课程,要求输入学号后输出该学生全部成绩
10.7指针数组和指向指针的指针
10.7,1 指针数组的概念例 int a[4]; int *p [4 ]={a,a+1,a+2,a+3};
char *name[5]={“Follow me”,”BASIC”,”Great
Wall”,,"FORTRAN","Computer design"};
10.7.2 指向指针的指针定义,基类型 **变量名
#include <stdio.h>
void main()
{ char *name[ ]={"Follow me","BASIC","Great
Wall″,"FORTRAN","Computer design"};
char **p;
int i;
for(i=0;i<5;i++)
{p=name+i;
printf( ″%s\n ″,*p);
}
}
p
例2 7 使用指向指针的指针
10.7,3 指针数组作 main函数的形参形式,void main( int argc,char *argv[ ])
main函数是由操作系统调用的。其形参的值不能在程序中得到,实际上实参是和命令一起给出的,调用形式为命令名 参数 1,参数 2,…,参数 n
其中 argc代表命令行中参数个数,由系统给出,argv是指向字符串的指针数组如假设 file1.c中有如上 main函数,对于命令行,
file1.exe China Beijing
执行后 argc=3,argv argv[0]
argv[1]
argv[2]
file1.exe
China
Beijing
设 file1.c中有如下语句,
void main( int argc,char *argv[])
{ while(argc>1)
{ ++argv;
printf(“% s\n”,argv);
- -argc;
}
}
在 DOS命令状态下输入的命令行为
file1.exe China Beijing
则执行以上命令行将会输出以下信息:
China
Beijing