指向结构体类型数据的指针

 指向结构体类型数据的指针

                        11.6 指向结构体类型数据的指针

     一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素。

   11.6.1   指向结构体变量的指针

下面通过一个简单例子来说明指向结构体变量的指针变量的应用。
例11.3   指向结构体变量的指针的应用。
                                        
#include "stdio.h"
#include "string.h"
void main()
{ struct student
    {long num;
     char name[20];
    char sex;
    float score;
    };
    struct student stu_1;
    struct student * p;
    p=&stu_1;
    stu_1.num=89101;
    strcpy(stu_1.name,"LiLin");
    stu_1.sex='M';
    stu_1.score=89.5;
    printf("No.:%ld\nname:%s\nsex:%c\nscore:%.2f\n",stu_1.num,stu_1.name,stu_1.sex,stu_1.score);
    printf("No.:%ld\nname:%s\nsex:%c\nscore:%.2f\n",( * p).num,( * p).name,( * p).sex,( * p).score);
}

运行后的结果是:
No.: 89101                                           图1:
name:LiLin                                          p-----→ 89101
sex: M                                                             “ LiLin ”     
score:89.50                                                       ‘ M ’ 
No.:89101                                                           89.5
name:LiLin
sex: M
score:89.50

在主函数中声明了 struct student 类型,然后定义一个 struct student 类型的变量 stu_1。同时又定义一个指针变量p,它指向一个 struct student 类型的数据。在函数的执行部分将结构体变量的起始地址赋给指针变量p,也就是使 p 指向stu_1(见图1),然后对 stu_1的各成员赋值。第一个printf 函数是输出 stu_1的各成员的值。用 stu_1.num 表示 stu_1中的成员 num,依次类推。第二个 printf 函数也是用来输出 stu_1 各成员的值,但使用的是( * p).num这样的形式。(* p)表示 p 指向的结构体变量,(*p).num 是 p 指向的结构体变量中的成员 num 。注意 * p两侧的括号不可省略,因为成员运算符 “ . ” 优先于“ * ”运算符,* p.num 就等价于*(p.num)了。

 可见两个 printf 函数输出的结果是相同的。

为了使用方便和使之直观,可以把( * p).num 改用 p->num来代替,它表示P
所指向的结构体变量中的 num 成员。同样,( * p).name 等价于 p->name。也就是说,以下3种形式等价:
                                                                    图2:p-----→1011
① 结构体变量. 成员名                                            LiLin
② ( * p). 成员名                                                             M              stu[0]
③     p->成员名                                                                 19
                                                                               p'-----→1012
上面程序中最后一个 printf 函数中                         XuXian
的输出项表列可以改写为                                             M              stu[1]
                                                                                              20
p->num,p->name,p->sex,p->score                    p''-----→ 1013 
                                                                                             WangMin
           其中—>称为指向运算符。                                     F            stu[2]
                                                                                                21
分析以下几种运算:
p->n           得到p指向的结构体变量中的成员n的值。
p->n++       得到p指向的结构体变量中的成员n的值,用完该值后使它加1。
++p->n       得到p指向的结构体变量中的成员n的值加1,然后再使用它。


11.6.2 指向结构体数组的指针

   已经介绍过可以使用指向数组或数组元素的指针和指针变量,同样,对结构体数组及其元素也可以用指针或指针变量来指向。

例11.4 指向结构体数组的指针的应用。
#include "stdio.h"
struct student
{ int num;
char name[20];
char sex;
int age;
};
struct student stu[3]={{1011, "LiLin",'M',19},{1012, "XuXian",'M',20},{1013, "WangMin",'F',21}};
void main()
{
struct student *p;
printf(" No.   Name              sex age\n");
for(p=stu;p<stu+3;p++)
printf("%5d %-20s %2c %4d\n",p->num,p->name,p->sex,p->age);
}
结果是:
No.     Name         sex        age
1011    LiLin            M          19
1012   XuXian         M          20
1013   WangMin     F           21

   p 是指向 struct student 结构体类型数据的指针变量。在for语句中先使 p 的初值为 stu ,也就是数组 stu 第一个元素的起始地址,见图2中p 的指向。在第一次循环中输出 stu[0]的各个成员值。然后执行p++,使 p 自加1。p 加1意味着p所增加的值为结构体数组 stu 的一个元素所占的字节数(在本例中为2+20+1+2=25字节)。执行p++后p 的值等于stu+1,p指向 stu[1],见图2中p'的指向。在第二次循环中输出 stu[1] 的各成员值。在执行 p++ 后,p的值等于 stu+2 ,它的指向见图2中的p'',再输出的各成员值。在执行p++ 后,p的值变为 stu+3 ,已不再小于 stu+3了,不再执行循环。

注意以下两点:
(1)如果 p 的初值为 stu ,即指向第一个元素,则 p 加1 后 p 就指向下一个元素。例如:
(++p)->num 先使 p 自加 1 ,然后得到它指向的元素中的 num 成员值(即10102).

(p++)->num 先得到p-->num 的值(即10101),然后使p自加1,指向stu[1].

请注意以上二者的不同。

(2)程序已定义了 p 是一个指向 struct student 类型数据的指针变量,它用来指向一个 struct student 类型的数据(在例11.4中p 的值是 stu 数组的一个元素(如 stu[0]、stu[1])的起始地址),不应用来指向 stu 数组元素中的某一成员。例如,这种的用法是不对的: p=stu[1].name;     编译时将给出“警告”信息,表示地址的类型不匹配。不要认为反正是存放地址的,可以将任何地址赋给它。如果要将某一成员的地址赋给 p,可以用强制类型转换,先将成员的地址转换成 p 的类型。例如:p=(struct student *)stu[0].name;   此时,p 的值是stu[0] 元素的 name 成员的起始地址。但是,p仍保持原来的类型。如果执行 printf("%s",p+1); 则会输出 stu[1] 中 name 的值。执行p+1 时,p 的值增加了结构体 struct student 的长度。

11.6.3 用结构体变量和指向结构体的指针作函数参数

将一个结构体变量的值传递给另一个函数,有3个方法:

(1)用结构体变量的成员作参数。例如,用 stu[1].num 或 stu[2].name 作函数实参,将实参值传给形参。用法和用普通变量作实参是一样的,属于“值传递”方式。应当注意实参与形参的类型保持一致。

(2)用结构体变量作实参。用结构体变量作实参时,采取的也是“值传递”的方式,将结构体变量所占的内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量。在函数调用期间形参也要占用内存单元。这种传递方式在空间和时间上开销较大,如果结构体的规模很大时,开销是很可观的。此外,由于采用值传递方式,如果在执行被调用函数期间改变了形参(也是结构体变量)的值,该值不能返回主调函数,这往往造成使用上的不便。因此一般较少用这种方法。

(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参。


11.5 有一个结构体变量 stu ,内含学生学号、姓名和3门课程的成绩。要求在 main 函数中赋予值,在另一函数 printf 中将它们输出。今用结构体变量作函数参数。程序如下:
#include "stdio.h"
#include "string.h"
#define FORMAT "%d\n%s\n%.2f\n%.2f\n%.2f\n"
struct student 
{
int num;
char name[20];
float score[3];
};
void main()
{
void print(struct student);
struct student stu;
stu.num=12345;
strcpy(stu.name,"LiLin");
stu.score[0]=67.5;
stu.score[1]=89;
stu.score[2]=78.5;
print(stu); 
}
void print(struct student stu)
{
     printf(FORMAT,stu.num,stu.name,stu.score[0],stu.score[1],stu.score[2]);
     printf("\n");
}
结果是:
12345
LiLin
67.50
89.00
78.50

struct student 被定义为外部的类型,这样,同一原文件中的各个函数都可以用它来定义变量。main 函数中的 stu 定义为 struct student 类型变量,printf
函数中的形参 stu 也定义为 struct student 类型变量。在 main 函数中对 stu 的各成员赋值。在调用 printf 函数时,以 stu 为实参向形参 stu 实行“值传递”.
在函数中结构体变量 stu 各成员的值。

例11.6 将上题改用指向结构体变量的指针作实参。
可以在上面程序的基础上作少量修改即可。请注意程序的注释。
#include "stdio.h"
#define FORMAT "%d\n%s\n%.2f\n%.2f\n%.2f\n"
struct student 
{
int num;
char name[20];
float score[3];
}stu={12345,"LiLin",67.5,89,78.5};
void main()
{
void print(struct student *);/*形参类型修改成指向结构体的指针变量*/
print(&stu);                             /*实参改为 stu 的起始地址*/
}
void print(struct student * p) /*形参类型修改了*/
{
     printf(FORMAT,p->num,p->name,p->score[0],p->score[1],p->score[2]); /*用指                                                       针变量调用各成员的值*/
     printf("\n");
}
结果是:
12345
LiLin
67.50
89.00
78.50

此程序改用在定义结构体变量 stu 时赋初值,这样程序可简化些。print 函数中的形参 p 被定义为指向 struct student 类型数据的指针变量。注意在调用 print 函数时,用结构体变量 stu 的起始地址 &stu 作实参。在调用函数时将该地址传送给形参 p(p是指针变量)。这样p 就指向 stu ,见图3.在 print 函数中输出 p 所指向的结构体变量的各个成员值,它们也就是 stu 的成员值。

main 函数中的对各成员赋值也可以改用函数输入,即用:

scanf("%d%s%f%f%f",&stu.num,stu.name,&stu.score[0],&stu.score           [1],&stu.score[2]);

输入时用这种形式输入:12345   LiLin   67.5   89   78.5

    注意输入项表列中 stu.name 前没有“&”符号,因为 stu.name 是字符数组名,本身代表地址,不应写成 &stu.name.

将例11.5改用输入:
#include "stdio.h"
#include "string.h"
#define FORMAT "%d\n%s\n%.2f\n%.2f\n%.2f\n"
struct student 
{
int num;
char name[20];
float score[3];
};
void main()
{
void print(struct student);
struct student stu;
scanf("%d%s%f%f%f",&stu.num,stu.name,&stu.score[0],&stu.score[1],&stu.score[2]);
print(stu); 
}
void print(struct student stu)
{
     printf(FORMAT,stu.num,stu.name,stu.score[0],stu.score[1],stu.score[2]);
     printf("\n");
}
结果是:
输入:12345   LiLin   67.5   89   78.5
12345
LiLin
67.50
89.00
78.50

将例11.6改用输入:
#include "stdio.h"
#define FORMAT "%d\n%s\n%.2f\n%.2f\n%.2f\n"
struct student 
{
int num;
char name[20];
float score[3];
}stu;
void main()
{

void print(struct student *);/*形参类型修改成指向结构体的指针变量*/
print(&stu);                             /*实参改为 stu 的起始地址*/

}
void print(struct student * p) /*形参类型修改了*/
{    
scanf("%d%s%f%f%f",&stu.num,stu.name,&stu.score[0],&stu.score[1],&stu.score[2]);
     printf(FORMAT,p->num,p->name,p->score[0],p->score[1],p->score[2]); /*用指    
                                                                        针变量调用各成员的值*/
     printf("\n");
}
结果是:
输入:12345   LiLin   67.5   89   78.5
12345
LiLin
67.50
89.00
78.50


        用指针作函数比较好,能提高运行效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值