printf("%d",*p);/*输出数组的值,并且每输出一个空一格*/
}
运行情况如下:
输入:
546512342
输出:
212345465
该问题的解决方法,采取的是在上一章所学的选择排序法来进行排序的.
5.2.2指向二维数组的指针
1.二维数组的地址
例如有定义语句:
inta[3][3];
✧二维数组名a是数组的首地址。
✧二维数组a包含三个行元素:
a[0]、a[1]、a[2]。
✧三个行元素的地址分别是:
a、a+1、a+2。
而a[0]、a[1]、a[2]也是地址量,是一维数组名,即*(a+0)、*(a+1)、*(a+2)是一维数组首个元素地址。
如图5-5:
2.二维数组元素的地址
a[0]、a[1]、a[2]是一维数组名,所以a[i]+j是数组元素的地址。
数组元素a[i][j]的地址可以表示为下列形式,&a[i][j]、a[i]+j、*(a+i)+j
如图5-6所示:
3.二维数组元素的表示法
数组元素可用下列形式表示:
a[i][j]、*(a[i]+j)、*(*(a+i)+j)
a是二维数组,根据C的地址计算方法,a经过两次*操作才能访问到数组元素。
所以:
*a是a[0],**a才是a[0][0]。
看一看,想一想若a是二维数组名请理解下列表示方法的含义
a
a[0],*(a+0),*a,&a[0][0]
a+1,&a[1]
a[1]+2,*(a+1)+2,&a[1][2]
a[0]是a[0][0]的地址,*a[0]是a[0][0]。
4.指向二维数组元素的指针变量
【例5-6】用指向数组元素的指针变量输出数组元素,请注意数组元素表示方法。
main()
{inta[3][4]={{0,1,2,3},{10,11,12,13},{20,21,22,23}},i,j,*p;
for(p=a[0],i=0;i<3;i++)
{for(j=0;j<4;j++)
printf("%4d",*(p+i*4+j));/*元素的相对位置为i*4+j*/
printf("\n");
}
}
程序分析与解释:
此程序定义了一个二维数组a和一个指向整型变量的指针变量p。
并将数组首地址赋值给指针变量p,通过改变变量i,j的值,来输出数组元素的值,整个过程中,指针变量p的值没有发生改变。
5.2.3指向字符串的指针变量
C语言将字符串是作为数组对待的,与数值型数组一样,我们也可用字符型的指针变量指向字符串,然后通过指针变量来访问字符串存贮区域。
设有如下语句:
char*cp;
cp="love”;
则cp指向字符串”love”常量的首字符’a’,如图5-7所示,程序中可通过cp来访问这一存贮区域。
1.指向字符串的指针变量的定义及初始化
【例5-7】通过初始化使指针指向一个字符串。
main()
{
charstr1[]="Goodmorning!
";
/*定义一个字符数组*/
char*str2="Goodnight!
";
/*定义一个指向字符串的指针变量*/
printf("%s\n",str1);
printf("%s\n",str2);
}
C语言中对字符常量是按照字符数组来处理的,在内存中开辟了一个字符数组用来存放该字符串常量。
对字符指针str2进行初始化,实际上是把字符串的第一个元素的地址(即存放字符串的首地址)赋给了str2,见图5-8。
有人认为str2是一个字符串变量,认为在定义的时候把"Goodnight!
"这几个字符赋给该字符串变量,这种认为是不对的。
定义指针变量str2部分:
char*str2="Goodnight!
";
等价于下面两行:
char*str2;
str2="Goodnight!
";
在输出时,要用:
printf(“%s\n”,str2);
%s是输出字符串格式控制符,在输出项要用字符指针变量名str2,则系统先输出指针所指向的字符,然后再自动使指针值加1,使之指向下一个字符,然后再输出一个字符,……,直到遇到字符串结束符’\0’为止。
注意,在内存中,字符串的最后都被自动加上了一个’\0’,如图5-8所示,因此在输出时能确定字符串的中止位置。
提醒
✧通过字符数组名或者字符指针变量可以输出一个字符串,而对数值型数组是不能企图用数组名输出它全部元素的,例如:
inta[3]={1,2,3};
printf(“%d”,a)
这种是错误的,数值型数组只能逐个元素输出。
✧对字符串中字符的存取,可以用下标法也可以用指针法。
【例5-8】已知字符串str,从中截取一子串。
要求该子串是从str的第m个字符开始,由n个字符组成。
【解题思路】
定义字符数组c存放子串,字符指针变量p用于复制子串,利用循环语句从字符串str截取n个字符。
考虑到几种特殊情况:
(1)m位置后的字符数有可能不足n个,所以在循环读取字符时,若读到‘\0’停止截取,利用break语句跳出循环。
(2)输入的截取位置m大于字符串的长度,则子串为空。
(3)要求输入的截取位置和字符个数均大于0,否则子串为空。
源程序如下:
main()
{
charc[80],*p,*str="Thisisastring.";
inti,m,n;
printf("m,n=");
scanf("%d,%d",&m,&n);
if(m>strlen(str)||n<=0||m<=0)
printf("NULL\n");
else
{
for(p=str+m-1,i=0;iif(*p)
c[i]=*p++;
else
break;/*如读取到'\0'则停止循环*/
c[i]='\0';/*在c数组中加上子串结束标志*/
printf("%s\n",c);
}
}
5.3结构体
在前面,已经介绍过了基本数据类型的变量(如整型、字符型、浮点型变量),也介绍了一种构造类型数据——数组,其中数组中各元素属于同一种类型。
但是只有这些数据类型是不够的,有时需要将不同数据类型组合成一个有机的整体,以便引用。
这些组合在一个整体中的数据是互相联系的,例如:
一个学生的信息有学号、姓名、性别、年龄、住址、成绩等;一本图书的信息有分类编号、书名、作者、出版社、出版日期、价格、库存量等。
那么如何描述这些类型不同的相关数据呢?
在C语言中允许用户自己指定这样一种数据结构,它是由若干个类型不同的(当然也可以相同)的数据项组合在一起,称为结构体(structure)。
构成结构体的各个数据项称为结构体成员。
它相当于其他高级语言中的“记录”。
如果要用C语言编写实用程序,结构的知识是不可缺少的!
同时,结构还是C++等后续语言的基础。
5.3.1结构体的定义与引用
1.结构体定义的一般格式
struct结构体名
{
数据类型1成员名1;
数据类型2成员名2;
……
数据类型n成员名n;
};
提醒
✧不要忽略了最后的分号。
✧struct为关键字;
✧结构体名是用户定义的类型标识,用作结构体类型的标志。
✧结