nullnull哈尔滨工业大学 计算机学院2003年8月傅忠传第五章
数组和指针第五章
数组和指针本章的学习难点本章的学习难点1.数组的概念及其使用。 3.指针的概念以及数组与指针之间的关系 。2.字符数组以及字符串处理函数在字符串处理操作中的应用 。本章目录本章目录数组
指针
指针和数组间的联系
指针数组
*指向指针的指针
*带参数的main函数和命令行参数
*动态数组的实现
*关于面向过程的程序设计
*关于防御性程序设计
*关于程序质量的重要性 数组数组数组类型的应用场合
定义、初始化和引用
一维数组应用举例
一维数组名作函数参数
二维数组及二维数组作函数参数应用举例
字符数组
6.1.字符数组与字符串的关系
6.2.字符数组的输入输出
6.3.字符串处理函数
*6.4.字符数组应用举例1、2 数组类型的应用场合数组类型的应用场合 排序算法与数组
两个数由小到大排序:
三个数由小到大排序:……
十个数由小到大排序:……
一百个数由小到大排序:数 组数组的概念数组的概念数组由若干个相同类型的相关数据项按顺序存
储在一起,构成数组(array) ;数组实际上
是同种类型、有序的数据的集合。 数组名如果用一个统一的名字标识这组数据,
那么这个名字就称为数组名。 数组元素构成数组的每一个数据项称为数组的
元素(element)。说明同一数组中的元素必须具有相同的数据类
型,而且这组数据在内存中将占据一段连
续的存储单元。 数组定义的通用格式数组定义的通用格式格式类型 数组名[下标1][下标2] ……[下标n];其中:类型为数组元素的基类型,即每个
元素的类型。下标值n
示为所在维的数组
元素个数,该维的数组下标的上界是n-1;
C语言中数组下标下界始终为0。维数是
下标的个数。数组分类数组分类一维数组二维数组与多维数组一维数组的定义
一维数组的初始化
一维数组的引用二维数组的定义
二维数组的初始化
二维数组的引用定义、初始化、引用一维数组的定义一维数组的定义格式类型 数组名[常数表达式];举例int a[10]; //各元素都为整形。
定义一个包括10个整形元素的一维数组。
元素为:a[0]、a[1]、a[2] ……a[9]
注明⒈数组名定名规则和变量名相同,遵循标识符定名规则。
⒉数组名后使用方括号括起来的常数表达式,不能用圆括号。
int a(10); ×
⒊常数表达式表示元素的个数,即数组长度,而不是数组的上界。
上例不能使用a[10]——越界错误!
⒋常数表达式中可以包括常量和符号常量,不能包括变量。如变长数组:设n为整形。——动态数据结构
scanf("%d", &n);
int a[n]; ×⒌数组必须先定义,然后使用。
⒍一维数组元素在内存中的排列顺序是线性排列即连续存储的。
一维数组元素的引用一维数组元素的引用使用说明C规定只能逐个引用数组元素,
而不能一次引用整个数组。引用形式数组名[下标]其中:下标可为整形常量或整形表
达式。举例a[0]=a[5]+a[n+3]-a[2*3]使用循环语句完成数组的赋值与输出。
main( )
{int i, a[10];
for (i=0; i<=9; i++) a[i]=i;
for (i=9; i>=0; i--)printf("%3d",a[i]);
}注明在数组的引用中,其下标值必须要
落在0与n-1之间——越界错误! 下
标越界也不自动监测。一个数组元素实质上就是一个变量
名,数组元素和变量一样使用。数组元素下标的括号必须是方括号。一维数组的初始化一维数组的初始化⒈在定义数组时,对数组元素赋初值。
int a[10]={0,1,2,3,4,5,6,7,8,9}
a[0]=0; a[1]=1; a[2]=2; ……a[9]=9
⒉可以只给一部分元素赋初值。
int a[10]={0, 1, 2, 3, 4}
a[0]=0; a[1]=1; a[2]=2; a[3]=3; a[4]=4
初值只赋前5个元素。⒊如想使一个数组全部为值n,可为:
int a[10]={0,0,0,0,0,0,0,0,0,0}
与fortran语言不同,不能为:
int a[10]={0*10}
⒋在对全部数组元素赋初值时,可以不指定数组长度,例如:
int a[5]={1, 2, 3, 4, 5}
可以写成:
int a[ ]={1,2,3,4,5}
⒌当数组被说明为静态(static)存储类型或外部存储类型(即在所有函数外部定义)时,则在不显式给出初值的情况下,数组元素将在程序编译阶段自动初始化为0。
static int a[4] 等价于
static int a[4]={0,0,0,0}二维数组的定义二维数组的定义格式类型 数组名[常数表达式1] [常数表达式2] ;举例int a[3][4];可看成3行*4列矩阵:int a[0][4]
int a[1][4]
int a[2][4];
每行都是一个包含4个元素的
一维数组。二维数组的排列顺序二维数组的排列顺序元素为:a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3] ★按行存储★多维数组多维数组格式类型 数组名[常数1] [常数2] ……[常数m];举例int a[2][2][4];存储顺序 a[0][0][0] →a[0][0][1] →a[0][0][2] →a[0][0][3] →
a[0][1][0] →a[0][1][1] →a[0][1][2] →a[0][1][3] →
a[1][0][0] →a[1][0][1] →a[1][0][2] →a[1][0][3] →
a[1][1][0] →a[1][1][1] →a[1][1][2] →a[1][1][3]★按行存储★二维数组元素的引用二维数组元素的引用引用形式数组名[下标1][下标2]其中:下标可为整形常量或整形表
达式。举例a[2][3]=a[1][2]+b[7]/2注明在数组的引用中,其下标值必须要
落在该维的上下界之内。一个数组元素实质上就是一个变量
名,数组元素和变量一样使用。在数组 int a[3][4]中,
a[3][4]=5 ×
因为3和4已超出上界。在数组 int a[3][4]中,a[2][1]不能
写成 a[2, 1] ×
只能写成 a[2][1]。二维数组的初始化二维数组的初始化⒈分行给二维数组赋初值。
int a[3][4]={{1,2,3,4},{5,6,7,8},
{9,10,11,12}};
⒉也可将所有数据写在一个花括号内,
按数组存储顺序对各元素赋值。
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}⒋如果对全部元素赋初值(即提供全部初
始数据),则定义数据时对第一维长度可
以不指定,但第二维长度不能省。
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
等价于
int a[ ][4]={1,2,3,4,5,6,7,8,9,10,11,12}; 一维数组应用举例 一维数组应用举例 冒泡法排序
Fibonacci级数(作业)
*折半查找Fibonacci级数Fibonacci级数用数组来处理求Fibonacci的前20项。
例如:1,1,2,3,5,8,13,21,
34,65,……#include
main( )
{ int i;
static int f[20]={1, 1};
for (i=2; i<20; ++i) f[i]=f[i-1]+f[i-2];
for (i=0; i<20; ++i)
{if (i%5==0) printf("\n");
printf("%12d", f[i]);
}
}冒泡法排序冒泡法排序用冒泡法对10个数排序(由小到大)。4
8
2
7
5
92
4
8
5
7
92
4
5
8
7
92
4
5
7
8
92
4
5
7
8
92
4
5
7
8
94
8
2
7
5
94
8
2
7
5
94
8
2
5
7
94
8
2
5
7
94
2
8
5
7
9冒泡程序冒泡程序t=a[j]; a[j]=a[j-1]; a[j-1]=t注:可以使用a[0]折半查找折半查找1,5,6,9,11,17,25,34,38,41下界low上界up中值mid共有10个已排好序的数据:查找9。折半查找程序折半查找程序#include
main( )
{int up=9, low=0, mid, found=0, find;
int a[10]={1, 5, 6, 9, 11, 17, 25, 34, 38, 41};
scanf(〞%d 〞, &find);
printf(〞\n 〞);
while (up>=low && !fount)
{mid=(up+low)/2;
if(a[mid]==find)
{found=1; break;}
else if(a[mid]>find)
up=mid-1;
else low=mid+1;
}
if(found) printf(〞found number is %dth 〞mid);
else printf(〞no found 〞);
}一维数组名作函数参数 一维数组名作函数参数 使用简单变量作函数参数,能由实参向形参传递一个数据。使用数组名作函数参数,属于“地址调用”能由主调函数向被调函数传递数组的首地址,并能由被调函数向主调函数传递多个数据。
数组名作为函数参数数组名作为函数参数传递方式属于赋地址调用,将实参数组首地址
传给虚参,虚参也是一数组名。虚参必须是数组名。实参要求可为另一数组名。哑实结合哑实数组具有相同的首地址,即哑实
数组第一个元素占用同一存储单元,
以后各元素按顺序一一结合。函数传值(数组名)示意图函数传值(数组名)示意图地址值主调函数实参地址值被调函数实参实参形参调用时地址值地址值形参形参执行调用函数地址值地址值从被调用函数返回修改已改变数组名作参数的说明数组名作参数的说明
⒈用数组名作函数参数时,应该在主调函数
和被调函数分别定义数组——实参数组、形
参数组,不能只在一方定义,并且实参数组
与形参数组类型必须一致。
2.在被调函数中声明的形参数组的大小n,
实际上不起任何作用,因为C编译对形参
数组的大小不做检查,只将实参首地址传
给形参数组。
3.实参数组和形参数组,既可同名,也可不
同名,因它们的数组名代表的是数组的首地
址,所以经过“由实参向形参的单向值传递”
后,它们便指向了内存中的同一段连续的存
储单元。 4.若在被调函数中改变形参数组的元素值,
则实参数组中的元素值也会随之发生改变。
注意这种改变不是形参传给实参造成的(C
语言不允许这种反向的值传递),而是由于
形参和实参两个数组在内存中因指向同一地
址而共享同一段内存造成的。 选择出运行结果选择出运行结果#define MAX 10
int a[MAX], i;
main( )
{printf("\n"); sub1( ); sub3(a); sub2( ); sub3(a);
}
sub2( )
{int a[MAX], i, max=5;
for(i=0; i
float average(float array[10]);/*声明*/
main( )
{float score[10], aver;
int i;
printf("input 10 scores:\n");
for(i=0; i<10; i++)scanf(" %f ",&score[i]);
printf(" \n ");
aver=average(score);/*数组名*/
printf(" average score is %5.2f ", aver);
}求平均值—1求平均值—1float average(float array[10])
{int i;
float aver, sum=0;
for(i=0; i<10; i++)
sum=sum+array[i];
aver=sum/10;
return (aver);
}/*定义*/二维数组名作函数参数二维数组名作函数参数转置矩阵(作业)
*杨辉三角形
*魔幻矩阵
*读程序、写结果
*矩阵行列转换魔幻矩阵魔幻矩阵 函数f中的形参a为一个10×10
的二维数组,n的值为5,一下程
序段的运行结果为 。f(int a[10][10], int n)
{int i, j, k;
j=n/2+1; a[1][j]=1; i=1;
for(k=2; k<=n*n; k++)
{i=i-1; j=j+1;
if(i<1)&&(j>n)) {i=i+2; j=j-1;}
else {if(i<1) i=n;
if(j>n) j=1;}
if(a[i][j]==0) a[i][j]=k;
else {i=i+2; j=j-1; a[i][j]=k;}
}
}12345678910111213141516171819202122232425输出运行结果输出运行结果写出以下的程序运行结果。main( )
{int a[3][3]={1,3,5,7,9,11,13,15,17};
sum=func(a);
printf("\nsum=%d\n", sum);
}
func(int a[ ][3])
{int i, j, sum=0;
for(i=0; i<3; i++)
for(j=0; j<3; j++)
{a[i][j]=i+j;
if(i==j) sum=sum+a[i][j];
}
return(sum);
}Sum=6矩阵行列转换矩阵行列转换 将一个二维数组行和列元素互换,存
到另一个数组中。main( )
{int a[2][3], b[3][2], i, j;
for (i=0; i<=1; i++)
for (j=0; j<=2; j++)
scanf("%d",&a[i][j]);
for (i=0; i<=1; i++)
for (j=0; j<=2; j++)
b[j][i]=a[i][j];
for (i=0; i<=2; i++)
for (j=0; j<=1; j++)
printf("%5d, %c",&b[i][j], 1-j?' ':"\n");
}转置矩阵转置矩阵求5×5阶矩阵A的转置矩阵。#include
main ()
{int a[5][5]={1,2, …,25}, i, j, t;
for (i=0; i<=4; i++)
for (j=0; j<=i; j++)
{t=a[i][j];
a[i][j]=a[j][i];
a[j][i]=t;
}
for (i=0; i<=4; i++)
for (j=0; j<=4; j++)
Printf(“%d,%c”, a[i][j],j-4?" ":"\n" );
}#include
main ()
{int a[5][5]={1,2, …,25}, i, j, t;
for (i=0; i<=4; i++)
for (j=0; j<=4; j++)
{t=a[i][j];
a[i][j]=a[j][i];
a[j][i]=t;
}
for (i=0; i<=4; i++) 是否正确?
for (j=0; j<=4; j++)
printf("%d,%c", a[i][j],j-4?" ":"\n" );
}思考题:
求矩阵中最大元素
的值及其所在位置?杨辉三角形杨辉三角形打印出以下的杨辉三角形。1
1 1
2 1
1 3 3 1
4 6 4 1
1 5 10 10 5 1
……用一维数组用二维数组二维数组实现二维数组实现#include
main ()
{int a[11][11], i, j, n;
a[1][1]=1; a[2][1]=1; a[2][2]=1;
scanf("%d",&n);
for (i=3; i<=n; i++)
{a[i][1]=1;
for (j=2; j<=i-1; j++)
a[i][j]=a[i-1][j-1]+a[i-1][j];
a[i][i]=1;}
for(i=1; i<=n; i++)
{for(j=1; j<=i; j++)printf("%8d", a[i][j]);
printf("\n"); }
}一维数组实现一维数组实现#include
main ()
{int a[11], i, j, k, n, ij, m;
scanf("%d",&n);
printf("%8d\n%8d%8d\n",1,1,1);
for (i=2; i<=n; i++)
{for (j=0; j<=i; j++)
{ij=1; m=1;
for(k=1; k<=i-j; k++) ij=ij*k;
for(k=j+1; k<=i; k++) m=m*k;
a[j]=m/ij;}
for(k=0; k<=i; k++) printf("%8d",a[k]);
printf("\n");
}
}字符数组的定义字符数组的定义格式char 数组名[常数1] [常数2] ……;举例char c[10];c[0]='I'; c[1]=' '; c[2]='a'; c[3]='m';c[4]=' ';
c[5]='h'; c[6]='a'; c[7]='p'; c[8]='p';c[9]='y';字符数组的初始化字符数组的初始化⒈将逐个字符赋给数组中各元素。
char c[10]={'I',' ','a','m',' ','h','a','p',
'p','y'};
⒉花括号中初值的个数大于数组长度,
则按语法错误处理。
字符数组的引用字符数组的引用说明引用字符数组中的一个元素,即得到
一个字符。举例输出一个字符串。main( )
{char c[10]={'I',' ','a','m',' ','h','a','p','p','y'};
int i;
for(i=0; i<=9; i++) printf("%c", c[i]);
printf("\n");
}字符串和字符串结束标志字符串和字符串结束标志提示在C语言中无字符串数据类型,将字符串
作为字符数组处理。有效字符串 字符数组中,第一个字符串结束
标志(\0)前的字符串,称为有效字符串。举例 有效字符串为 :"China"
存储字符串"China"时,a后自动加'\0'。字符数组赋初值补充字符数组赋初值补充 由于字符串在内存中存储时,后边自动
加'\0',字符数组初始化可为:char c[ ]={"I am happy"};也可为:char c[ ]="I am happy";与下面的语句等价吗?char c[ ]={'I',' ','a','m',' ','h','a','p',
'p','y'};×字符数组赋初值补充字符数组赋初值补充 用二维字符数组可存放多个字符串,第二维
的长度表示字符串的长度,不能省略,应按最长
的字符串长度设定;第一维的长度代表要存储的
字符串的个数,可以省略。 char weekday[7][10]= {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
可写成:
char weekday[ ][10]={ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
不能写成:
char weekday[ ][ ]={ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; 字符数组与字符串的关系字符数组与字符串的关系1.字符串是采用字符数组来表示的,只是在有效字符串后自动加字符串结束标志'\0'。
2.字符数组不是字符串,只有当字符型一维数组中的最后一个元素值为’\0’时,它才构成字符串。
3.对于一个字符串常量,那么这个字符串常量本身代表的就是该字符串在内存中所占连续存储单元的首地址,是一个地址常量 。
4.如果将字符串赋值给了一个一维数组,那么这个一维数组的名字就代表这个首地址。 字符串的输入和输出字符串的输入和输出利用循环,逐个字符输入输出。用格式赋%c输入或输出一个字符。将整个字符串一次输入或输出。用格式赋%s输入或输出一个字符串。字符串输入字符串输出字符串输入字符串输入⒈scanf函数对数组元素逐个进行输入 。
char c[10];
for(i=0; i<10; i++)
scanf("%c",&c[i]); 举例char c[10];
scanf("%s",c);说明⒉scanf函数中的输入项c是字符数组名,
不要再加&,它应在先前已被定义 。
char c[10];
scanf("%s",c); China↙⒊从键盘上输入的字符串应短于已定义的
字符数组的长度 ;否则,系统错。
char c[10];
scanf("%s",c); China↙字符串输出字符串输出⒉逐个字符输出,遇字符串结束符‘\0’,
输出结束。
for(i=0; c[i]!='\0'; i++)
printf("%c", c[i]);举例char c[ ]="China";
printf("%s\n",c);说明结果:
China⒈输出字符不包括结束符‘\0’,只作为结
束标志,输出 遇‘\0’时,输出结束。
⒊用%s格式符输出字符串时,printf函
数中的输出项是字符数组名,而不是
数组元素名。
printf("%s",c[0]); printf("%s",c);⒋如果数组长度大于字符串实际长度,
也只输出到遇‘\0’结束 。
char c[10]="China";
printf("%s",c); China⒌如果一个字符数组中包含一个以上的
‘\0’,则遇第一个'\0'时就结束 。
char c[10]="China";
printf("%s",c); China字符串处理函数字符串处理函数puts函数gets函数!strcat函数!strcpy函数! strcmp函数! strlen函数strlwr函数strupr函数#include 输出字符串函数----puts输出字符串函数----puts功能将一个字符串输出到终端。格式puts(&string:str);举例char c[]="China\nBeijing";
puts(c);China
Beijing读取字符串函数----gets读取字符串函数----gets功能从终端输入一个字符串到字符数组。格式&string: gets(&string:str);举例char c[10];
gets(c);China↙说明送给字符数组的是6个字符,而不
是5个字符。函数返回值为字符数组c的起始地址。用puts和gets函数只能输入或输出一
个字符串,而不能写成:
puts(c1,c2,c3); gets(c1,c2,c3);字符串连接函数----strcat字符串连接函数----strcat功能将字符串str2连接到字符串str1后面。格式&string: strcat(&string:str1, str2);举例返回目的字符串str1的首地址char c1[10]="abc", c2[10]="xyz";
strcat(c1,c2);说明⒈str1必须足够大,以便容纳连接
后的新字符串。⒉连接前两个字符串的后面都有'\0',
连接时将str1后面的‘\0’取消,只
在新串最后保留一个'\0'。字符串复制函数----strcpy字符串复制函数----strcpy功能格式&string: strcpy(&string:str1, str2);举例返回目的字符串str1的首地址char c1[10]="abc", c2[10]="xyz";
strcpy(c1,c2);说明⒈str1必须足够大,以便容纳复制
后的新字符串。⒉str1必须写成数组名形式,str2可
以是字符数组名,也可以是字符串
常量。
例如:strcpy(str1, "China");将字符串str2复制到字符串str1中去。⒊复制时,连同字符串str2后面的'\0'
一起复制到字符数组str1中。⒋不能用赋值语句将一个字符串常量,
或字符数组直接给一个字符数组赋
值。 str1="abcd"; ×
str1=str2; ×字符串比较函数----strcmp字符串比较函数----strcmp功能对str1和str2进行比较,当str1=str2,
函数值为0;str1>str2,函数值为正
整数;str1
main( )
{char c1[20], c;
int n, i;
scanf("%s",c1);
n=strlen(c1) -1;
for(i=0; i<=n; i++)
{c=c1[i];
c1[i]=c1[n-i];
c1[n-i]=c;
}
printf("n=%d\nstring=%s\n", n+1, c1);
}解法2解法2#include
main( )
{char c1[20], c;
int n, i;
scanf("%s",c1);
n=strlen(c1)-1;
for(i=0; i<=n/2; i++)
{c=c1[i];
c1[i]=c1[n-i];
c1[n-i]=c;
}
printf("n=%d\nstring=%s\n", n, c1);
}解法3解法3#include
main( )
{char c1[20], c;
int n, i, j;
scanf("%s", c1);
n=strlen(c1)-1;
for(i=0; i
main( )
{char c[3][20], str[20];
int i;
for(i=0; i<=2; i++)
gets(c[i]);
strcpy(str, c[0]);
if (strcmp(str, c[1])<0) strcpy(str, c[1]);
if (strcmp(str, c[2])<0) strcpy(str, c[2]);
printf("\nthe largest string :\n%s\n", str);
}指针指针5.2.1.指针的概念
5.2.2.为什么引入指针的概念
5.2.3.变量的指针与变量的指针
作为函数参数
5.2.4.字符指针
*5.2.5.字符指针作为函数参数 指针的概念指针的概念1. 什么是变量的地址?
什么是变量的内容?
2. 什么是直接寻址?
什么是间接寻址?
3. 取地址运算符&与
间接访问运算符*? 变量的地址与变量的内容变量的地址与变量的内容以一个整形变量为例:变量a第一个字节的地址2002即为变量a的地址。存储476 00000001 11011100 即为变量a的内容。 直接寻址直接寻址20022003内容一般变量的寻址方式采用直接寻址:&a变量地址a本质:变量是通过变量地址来访问变量内容的。 直接按变量名来存取变量内容的访问方式,
称为直接寻址。间接访问间接访问i_pointer=&i;初始化*i_pointer的值为3*i_pointer 专门用于存放地址型数据的变
量i_pointer就是指针变量。 通过指针变量来间接存取它所指向的变量的访问方
式,称为间接寻址。一般采用指针间接访问变量:int i,*i_pointer;取地址运算符取地址运算符格式得到某一变量存储空间的首地址。&V功能举例int A;20022003变量A内容&A的运算结果是2002。即是变量A的首地址。间接访问运算符间接访问运算符格式将指针P所指变量的内容取出来。*P 间接访问运算符
(假设变量P为指针变量)功能举例int A,*p; 设P为指向整形的指针变量20022003变量A内容*P的运算结果是476。即是变量A的内容。p=&A;
p初始化指针P*P和变量A作用是等价的。为什么引入指针的概念为什么引入指针的概念指针提供通过变量地址访问变量的手段。
指针为C的动态内存分配系统提供支持 。
指针为动态数据结构(例如链表、队列、二叉树等)提供支持,操作系统的编写 。
指针可以改善某些子程序的效率。 现实中地址的例子:
Email地址、寝室号、手机GPS定位系统(关机)本质:变量是通过变量地址来访问的。进一步说明指针重要性进一步说明指针重要性 任意从键盘输入两个整数,编程将其
交换后再重新输出。 (输出结果是否正确)进一步说明指针重要性进一步说明指针重要性main()
{void swap(int x,int y);
int a,b;
printf("Please enter a,b:");
scanf("%d,%d",&a,&b);
printf("Before swap: a=%d,b=%d\n",a,b);
swap(a,b);
printf("After swap: a=%d,b=%d\n",a,b);
}
void swap(int x,int y)
{int temp;
temp=x; x=y; y=temp;}出错原因出错原因158main
函数ab158swap
函数xytemp调用swap函数158ab158xytemp执行swap函数①②③1515 8 158abxytemp从swap函数返回81515变量的指针和指针变量变量的指针和指针变量变量指针指针就是地址,变量的指针就是变
量的首地址。 指针变量就是C语言中专门用于存放地址型数
据的变量。 一般情况下,指针变量中的地址是内存中
另一个普通变量的首地址。如果一个指针变量中
存放的是另一个变量的首地址,我们就称第一个
变量是指向第二个变量的指针。 指针变量的定义指针变量的定义 由于变量有类型之分,指向变量的变量
指针也有类型之分。格式类型 *变量1, *变量2,……;举例int *p1,*p2, n;
float *p3, *p4, f;P1=&n;说明无指向指向n⒈指针变量前面的*号,表示该变
量的类型为指针型变量。不是进
行指针运算。
⒉在定义指针变量时,必须指定基
类型。
是由于指针型变量有运算:使指
针加1;使指针移到下一位置。 符号*在变量说明语句中是个指针类型的说
明符,前面的类型关键字用于说明指针可以指
向哪一种类型的变量,我们称其为指针的基类
型。 ⒊指针变量必须先定义,后使用。
指针变量的引用指针变量的引用⒈一般变量只能存放数据,而不能存放
变量的地址;指针变量只能存放变量
的指针,即变量首地址,必须用相同
基类型的变量的地址对其进行赋值。
int n, *p;
p=n; ×
p=&n; √⒉与指针变量有关的两个特殊运算符:
* :间接访问运算符。
&:取地址运算符。
int n, *p;
p=&n;
此时*p和n表示的是同一变量。
⒊指针变量必须经初始化后才能使用,
否则指针变量所指向的存储单元是不
确定的,对其所作的赋值等操作将是
很危险的。
⒋由于指针的值就是地址,因此,指针
运算实质上就是对地址的运算。因此,
指针运算只能参与赋值运算、算术运算
和关系运算。其中,指针可参与的算术运算只有两种:加和减,即加、减一个整数或自增、自减运算。 ++p表示指向
下一个变量。--p指向上一个变量。⒌运算符*和++、--优先级等同,连续运算,采用右结合。下列各语句的含义如下:
a=*p++ 先运算p++,但为后增运算,因而先将*p的值赋给a,然后p加1。
a=(*p)++ 先取*p的值,赋给a。然后将p所指向的变量内容加1。 指针变量作函数参数指针变量作函数参数传递方式属于赋地址调用,将实元指针传给
虚参,虚参也是一指针。虚参要求必须是指针变量。实参要求是指针变量、数组名。哑实结合在哑实结合时,实元指针将其地址值
传给哑元指针。程序举例2程序举例2 输入两个整数,按从大到小
顺序排序。#include
void swap(int *p1, int *p2)
{ int p;
p=*p1; *p1=*p2; *p2=p;
}
main()
{int a,b,*px1,*px2;
scanf("%d,%d",&a,&b);
px1=&a; px2=&b;
if(a
main( )
{int *p1, *p2, *p, a, b;
scanf("%d, %d", &a, &b);
p1=&a; p2=&b;
if (a>b)
{p=p1; p1=p2; p2=p; }
printf("\na=%d, b=%d\n\n", a, b);
printf("max=%d, min=min%d\n", *p1, *p2);
}程序举例3—1程序举例3—1 任意从键盘输入10个整数,然后对
它们由小到大进行排序,并将排序后的
结果输出,要求用形参为指针的函数编
程实现排序和数组元素的输出。#include
void display( );
void sort( );
main( )
{int t[10], i;
printf("Input ten numbers:\n");
for(i=0; i<10; i++) scanf(" %d ", &t[i]);
printf("Sort data:\n");
sort(t, 10);
display(t, 10);
}程序举例3—2程序举例3—2void sort(int *a, int n)
{int i, j, k, temp;
for(i=0; i
void get_matrix(int *p,int n);
void put_matrix(int *p,int n );
void convert( int *p,int n);
#define m 3
main( )
{int a[m][m];
printf("Input %d×%d matrix:\n", m, m);
get_matrix(a, m);
convert(a, m);
printf("The converted matrix:\n");
put_matrix(a, m);
}程序举例4—2程序举例4—2get_matrix(int *p, int n)
{int *q;
for(q=p; q
main( )
{char *str="I love China!";
str=str+7;
printf("%s", str);
}运行结果为:China!#include
main( )
{char *str;
str="I love China!";
str=str+7;
printf("%s", str);
}字符指针作为函数参数 字符指针作为函数参数 传递方式属于赋地址调用,将实参字符指针
传给虚参,虚参也是字符指针。虚参要求必须是字符指针。实参要求可为另一字符指针名。哑实结合哑实字符指针具有相同的首地址,即
哑实字符串第一个字符占用同一存储
单元,以后各字符按顺序一一结合。程序举例程序举例试编写字符处理函数mid(s,s1, m, n) ——截取函数
Left(s, s1,n) ——左截函数
Right(s, s1,n) ——