原创 结构体指针变量的定义与引用★★★★

2011-6-14 21:43 2789 15 12 分类: MCU/ 嵌入式
结构体指针式指向结构体的指针。其定义方式如下:
        struct 结构体 * 结构体指针变量;;
   例如:struct student *sp;
   结构体指针对结构体成员的访问表达方式如下:
        结构体变量名->成员名
     或
        (*结构体指针变量名).成员名
===============================================================

http://www.neu.edu.cn/cxsj/online/C9/ch9_7-1.html 

9.7.1 结构体指针变量的定义
定义结构体变量的一般形式如下:
形式1:
struct结构体标识符
{
成员变量列表;…
};
struct 结构体标识符 *指针变量名;
形式2
struct结构体标识符
{
成员变量列表;…
} *指针变量名;
形式3:
struct
{
成员变量列表;…
}*指针变量名;
其中“指针变量名”为结构体指针变量的名称。形式1是先定义结构体,然后再定义此类型的结构体指针变量;形式2和形式3是在定义结构体的同时定义此类型的结构体指针变量。例如:定义struct Point类型的指针变量pPoints的形式如下:
struct Point
{
double x;
double y;
double z;
} *pPoints;

9.7.2 结构体指针变量的初始化
结构体指针变量在使用前必须进行初始化,其初始化的方式与基本数据类型指针变量的初始化相同,在定义的同时赋予其一结构体变量的地址。例如
struct Point oPoint={0,0,0};
struct Point pPoints=& oPoint; /*定义的同时初始化*/
在实际应用过程中,可以不对其进行初始化,但是在使用前必须通过赋值表达式赋予其有效的地址值。例如:
struct Point oPoint={0,0,0};
struct Point *pPoints2;
pPoints2=& oPoint; /*通过赋值表达式*/

9.7.3 结构体指针变量的引用
与基本类型指针变量相似,结构体指针变量主要作用是存储其结构体变量的地址或结构体数组的地址,通过间接方式操作对应的变量和数组。在C语言中规定,结构体指针变量可以参与的运算符如下:
++,--,+ ,* ,->,.,|,&,!
下面通过例题说明,如何引用结构体指针变量存储结构体变量地址,以及如何通过结构体指针变量间接的引用结构体变量以及其成员变量。
例9-3 应用结构体指针变量,打印结构体成员变量的信息。
#include <stdio.h>
struct Point
{
double x; /*x坐标*/
double y; /*y坐标*/
double z; /*z坐标*/
};
int main()
{
struct Point oPoint1={100,100,0};
struct Point oPoint2;
struct Point *pPoint; /*定义结构体指针变量*/
pPoint=& oPoint2;   /*结构体指针变量赋值*/
(*pPoint).x= oPoint1.x;
(*pPoint).y= oPoint1.y;
(*pPoint).z= oPoint1.z;
printf("oPoint2={%7.2f,%7.2f,%7.2f}",oPoint2.x, oPoint2.y, oPoint2.z);
return(0);
}
程序运行结果如下:
oPoint2={ 100.00,100.00,0.00}
其中表达式&oPoint2的作用是获得结构体变量oPoint2的地址。表达式pPoint=&oPoint2的作用是将oPoint2的地址存储在结构体指针变量pPoint中,因此pPoint存储了oPoint2的地址。*pPoint代表指针变量pPoint中的内容,因此*pPoint 和oPoint2等价。
通过结构体指针变量获得其结构体变量的成员变量的一般形式如下:
(*结构体指针变量). 成员变量
其中“结构体指针变量”为结构体指针变量,“成员变量”为结构体成员变量名称,“.”为取结构体成员变量的运算符。
另外C语言中引入了新的运算符“->”,通过结构体指针变量直接获得结构体变量的成员变量,一般形式如下:
结构体指针变量-> 成员变量
其中“结构体指针变量”为结构体指针变量,“成员变量”为结构体成员变量名称,“->”为运算符。
因此,例9-3中的部分代码
……
(*pPoint).x= oPoint1.x;
(*pPoint).y= oPoint1.y;
(*pPoint).z= oPoint1.z;
……
等价于
……
pPoint->x= oPoint1.x;
pPoint->y= oPoint1.y;
pPoint->z= oPoint1.z;
……
下面介绍如何应用结构体指针变量存储结构体数组的首地址,以及如何通过结构体指针变量获得结构体数组的元素及其成员变量。
例9-4 应用结构体指针变量改写例9-3,主要介绍修改部分Mutiline函数,其他部分略。
/*多边形绘制函数,形式参数为struct Point 类型指针变量pPoints */
void Mutiline(struct Point *pPoints)
{
int i;
struct Point *pOPoint; /*定义结构体指针变量*/
pOPoint=pPoints; /*存储结构体数组的首地址*/
moveto(pPoints->x,pPoints->y) ; /*将绘图点移动到第0个点*/
for( i=0; i<NPOINTS ; ++i )
{
lineto(pPoints->x, pPoints->y); /*从上一点向当前点绘制直线*/
pPoints++;
}
pPoints=pOPoint; /*指向结构体数组的首地址*/
lineto(pPoints->x,pPoints->y); /*封闭曲线*/
}
函数void Mutiline(struct Point *pPoints)的输入参数为struct Point指针变量pPoints。在主函数中调用形式为Mutiline(oPoints),将struct Point类型数组oPoints的首地址信息拷贝给形式参数struct Point *pPoint,此时pPoint指向结构体数组oPoints的第一个元素,如图所示。
主函数调用Mutiline的过程如下,首先将struct Point类型数组oPoints的首地址信息拷贝给形式参数struct Point *pPoint,等价于
pPoint= oPoints;
接下来,程序的控制权交给Mutiline函数,进入函数Mutiline。在程序进入函数Mutiline之后,pPoints 指向oPoints的首地址,跟踪程序表明此时变量pPoints的当前值为0X0F82。另外,由于数组第一个元素oPoints[0]的地址与数组的首地址相同。亦可以理解为此时pPoints指向了数组元素oPoints[0]的地址,因此*pPoints与oPoints[0]等价,表达式pPoints->x可以访问oPoints[0]的成员变量x,同样表达式pPoints->y可以访问oPoints[0]的成员变量y。执行pPoints++语句之后,pPoints的当前值为0X 0F9A。
ch9_7_clip_image002.jpg

0X0F9A-0X0F82=0X0018=24=sizeof(struct Point),24个字节正好为struct Point的大小。
此时pPoints指向数组元素oPoints[1]的地址, 因此*pPoints与oPoints[1]的等价。依次类推,通过pPoints的加法运算可以访问结构体数组oPoints中的所有元素。
因此要正确理解结构体指针变量的算术运算,pPoints++或pPoints= pPoints+1的作用不是简单的地址值加1,而是当前的地址值加上结构体类型的大小。
结构体指针变量+1= 结构体指针变量+sizeof(struct 结构体)
例9-5 输入10个同学的姓名、数学成绩、英语成绩和物理成绩,确定总分最高的同学,并打印其姓名及其三门课程的成绩。
#include "stdio.h"
struct Student /*定义结构体struct Student*/
{
char Name[20]; /*姓名*/
float Math; /*数学*/
float English; /*英语*/
float Physical; /*物理*/
};
void main()
{
/*定义struct Student类型结构体数组存储所有同学的相关信息*/
struct Student oStudents[10]={{"",0,0,0}};
/*定义struct Student类型指针存储总分最高的同学的地址信息*/
struct Student *pMaxStu;
struct Student *pStudent;
float fMaxScore,fTotal;
float fMath,fEnglish,fPhysical;
char szName[20];
printf("\nPlease input 10 students and there score\n");/*提示信息*/
printf("----------------------------------------\n");
printf("Name Math English Physical \n");
printf("----------------------------------------\n");
fMaxScore=0;
pMaxStu=oStudents;
for(pStudent=oStudents;pStudent<oStudents+10;pStudent++)
{
/*读入当前同学的相关信息*/
scanf("%s %f %f %f",szName,&fMath,&fEnglish,&fPhysical);
strcpy(pStudent->Name,szName);
pStudent->Math=fMath;
pStudent->English=fEnglish;
pStudent->Physical=fPhysical;
fTotal=pStudent->Math+pStudent->English+pStudent->Physical;
/*获得当前最高分的同学*/
if(fMaxScore<fTotal)
{
pMaxStu=pStudent;
}
}
printf("----------------------------------------\n");
printf("%s,%f,%f,%f",
pMaxStu->Name,pMaxStu->Math,pMaxStu->English,pMaxStu->Physical);
}
首先定义长度为10的struct Student类型结构体数组用于存储所有同学的相关信息,定义struct Student类型指针pMaxStu存储最高总分同学的地址信息。定义struct Student类型指针oStudents指向结构体数组oStudents 。
循环语句
for(pStudent=oStudents;pStudent<oStudents+10;pStudent++)
中pStudent=oStudents的作用是令pStudent指向数组的第一个元素;循环条件是pStudent<oStudents+10,即循环10次。其中语句
pStudent->Math=fMath;
pStudent->English=fEnglish;
pStudent->Physical=fPhysical;
的作用是保存当前同学的相关信息。

======================================================================

结构体指针的定义和引用
指针变量非常灵活方便,可以指向任一类型的变量,若定义指针变量指向结构体类型变
量,则可以通过指针来引用结构体类型变量。
7.3.1 指向结构体类型变量的使用
首先让我们定义结构体:
struct stu
{
char name[20];
long number;
float score[4];
} ;
再定义指向结构体类型变量的指针变量:
struct stu *p1, *p2 ;
定义指针变量p 1、p 2,分别指向结构体类型变量。引用形式为:指针变量→成员;
[例7-2] 对指向结构体类型变量的正确使用。输入一个结构体类型变量的成员,并输出。
#include <stdlib.h> /*使用m a l l o c ( ) 需要* /
struct data / *定义结构体* /
{
int day,month,year;
} ;
struct stu /*定义结构体* /
{
char name[20];
long num;
struct data birthday; /嵌*套的结构体类型成员*/
} ;
main() /*定义m a i n ( ) 函数* /
{
struct stu *student; 定/*义结构体类型指针*/
student=malloc(sizeof(struct stu)); 为/指* 针变量分配安全的地址*/
printf("Input name,number,year,month,day:\n");
scanf("%s",student->name); 输/*入学生姓名、学号、出生年月日*/
scanf("%ld",&student->num);
scanf("%d%d%d",&student->birthday.year,&student->birthday.month,
&student->birthday.day);
printf("\nOutputname,number,year,month,day\n");
/*打印输出各成员项的值*/
printf("%20s%10ld%10d//%d//%d\n",student->name,student->num,
student->birthday.year,student->birthday.month,
student->birthday.day);
}
程序中使用结构体类型指针引用结构体变量的成员,需要通过C提供的函数malloc()来为
指针分配安全的地址。函数sizeof()返回值是计算给定数据类型所占内存的字节数。指针所指
各成员形式为:
student->name
student->num
student->birthday.year
student->birthday.month
student->birthday.day
 
7.3.2 指向结构体类型数组的指针的使用
定义一个结构体类型数组,其数组名是数组的首地址,这一点前面的课程介绍得很清楚。
定义结构体类型的指针,既可以指向数组的元素,也可以指向数组,在使用时要加以区分。
[例7-3] 在例7 - 2中定义了结构体类型,根据此类型再定义结构体数组及指向结构体类型的指针。
struct data
{
intday,month,year;
};
struct stu/*定义结构体*/
{
char name[20];
long num;
struct data birthday;/嵌*套的结构体类型成员*/
};
struct stustudent[4],*p;定/*义结构体数组及指向结构体类型的指针*/
作p=student,此时指针p就指向了结构体数组student。
p是指向一维结构体数组的指针,对数组元素的引用可采用三种方法。
1)地址法
student+i和p+i均表示数组第i个元素的地址,数组元素各成员的引用形式为:
(student+i)->name、(student+i)->num和(p+i)->name、(p+i)->num等。student+i和p+i
与&student意义相同。
2)指针法
若p指向数组的某一个元素,则p++就指向其后续元素。
3)指针的数组表示法
若p=student,我们说指针p指向数组student,p表示数组的第i个元素,其效果与
student等同。对数组成员的引用描述为:p.name、p.num等。
[例7-4]指向结构体数组的指针变量的使用。
structdata/*定义结构体类型*/
{
intday,month,year;
};
structstu/*定义结构体类型*/
{
char name[20];
long num;
struct data birthday;
};
main()
{inti;
structstu*p,student[4]={{"liying",1,1978,5,23},{"wangping",2,1979,3,14},
{"libo",3,1980,5,6},{"xuyan",4,1980,4,21}};
/*定义结构体数组并初始化*/
p=student;/*将数组的首地址赋值给指针p,p指向了一维数组student*/
printf("\n1----Outputname,number,year,month,day\n");
for(i=0;i<4;i++)/*采用指针法输出数组元素的各成员*/
printf("%20s%10ld%10d//%d//%d\n",(p+i)->name,(p+i)->num,
(p+i)->birthday.year,(p+i)->birthday.month,
(p+i)->birthday.day);
}

==========================================================

结构指针变量使用时的注意事项

在使用结构指针变量的时候,往往容易犯一个“低级”错误。即定义一个结构指针变量后就直接对结构指针变量所指向的结构成员进行操作,从而产生一些莫名其妙的错误。我们必须要给结构指针变量赋予一个有效的结构变量地址,才能正常操作结构指针变量。比如:

struct UART{

             int a;

             uchar b;

}

main()

{

      struct UART  *p;

      p->a = 0xXXX;

      p->b = 0xXX;

     printf("%i,%c",p->b,p->a);

}

这个程序输出的值将是不可预知的,因为“在程序中只是定义了一个结构指针变量,并没有给该结构指针变量赋一个有效值,因此该结构变量所指向的地址将不确定,从而不能得到预期结果”

应该改为:

struct UART{

             int a;

             uchar b;

}

main()

{

      struct UART  *p;

     struct UART dd;

      p = &dd;               //这句一定要有,否则将出现不可预知的问题

      p->a = 0xXXX;

      p->b = 0xXX;

     printf("%i,%c",p->b,p->a);

}

====================================================================

 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
15
关闭 站长推荐上一条 /3 下一条