1 / 32

第十一章 结构体

第十一章 结构体. 11.1 概述 11.2 定义结构体变量的方法 11.3 结构体变量的引用 11.4 结构体变量的初始化 11.5 结构体数组 11.6 指向结构体数据的指针 11.7 用指针处理链表. 结构体类型定义形式 :. struct 结构体类型名 { 数据类型 成员名 1; 数据类型 成员名 2; : : 数据类型 成员名 n; } ;. 称成员表列. 11.1 概述. 在实际问题中我们常需要把不同类型的几个数据组合起来 , 构成

bowie
Download Presentation

第十一章 结构体

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第十一章 结构体 • 11.1 概述 • 11.2 定义结构体变量的方法 • 11.3 结构体变量的引用 • 11.4 结构体变量的初始化 • 11.5 结构体数组 • 11.6 指向结构体数据的指针 • 11.7 用指针处理链表

  2. 结构体类型定义形式: struct 结构体类型名 { 数据类型 成员名1; 数据类型 成员名2; : : 数据类型 成员名n; } ; 称成员表列 11.1 概述 在实际问题中我们常需要把不同类型的几个数据组合起来, 构成 一个整体。如一个公司职员的个人信息, 或学校中教师和学生的信息。 以学生信息为例, 它可能包括学生的学号、班级、姓名、性别、年龄、 成绩等。这时原有的那些数据类型就显的有点无能为力了,所以引入 一种新的数据类型---- 结构体。 结构体是由一些逻辑相关, 但数据类型不同的分量组成的一组数据。 用户定义 的标识符 关键字 注意: 用户需要先定义 结构体类型, 之后才能 定义结构体变量 注意不要忘了分号

  3. st1 st2 11.2 定义结构体变量的方法 name age s1 s2 一、 定义结构体变量 1. 先定义结构体类型, 再定义变量 struct student { char name[10] ; int age ; float s1 , s2 ; } ; struct student st1 , st2 ; name age s1 s2 结构体变量st1和st2各自都 需要20个字节的存储空间

  4. 3. 直接定义结构体变量 struct { char name[10] ; int age ; float s1 , s2 ; }st1 , st2 ; 2. 定义结构体类型同时定义变量 struct student { char name[10] ; int age ; float s1 , s2 ; }st1 , st2 ; 4. 说明: (1) 结构体变量具有结构体类型的一切特征 在内存中结构体变量占有一片连续的存储单元 存储单元的字节数可用sizeof 运算符算出 printf(“%d\n” , sizeof(struct student) ) ; printf(“%d\n” , sizeof(st1) ) ;

  5. (2) 结构体类型可以嵌套定义 例: struct date { int year ; int month ; int day ; } ; struct stud { char name[10] ; struct date birthday ; float s1 , s2 ; } ; 或 : struct stud { char name[10] ; struct date { int year ; int month ; int day ; }birthday ; float s1 , s2 ; } ;

  6. 11.3 结构体变量的引用 1. 引用结构体变量中的成员 格式:结构体变量名. 成员名 struct student st1 ; st1. name = “Mary” ; st1. age = 21 ; st1. s1 = 78 ; st1. s2 = 86 ; struct student { char name[10] ; int age ; float s1 , s2 ; } ; 注意: 一般是对结构体变量的各个成员分别进行赋值 st1 = { “Mary”, 21 , 78 , 86 } ; 这样的赋值是不允许的

  7. struct stud st2 ; int age , year ; st2. name = “John” ; st2. age = 20 ; st2. birthday. year = 1980 ; st2. birthday. month = 11 ; st2. birthday. day = 23 ; st2. s1 = 89 ; st2. s2 = 95 ; age = 24 ; year = 2000 ; struct date { int year ; int month ; int day ; } ; struct stud { char name[10] ; int age ; struct date birthday; float s1 , s2 ; } ; 可以定义与结构体变量 成员名相同名字的变量 它们之间不会发生混乱

  8. 注意要正确赋值的条件 是变量st1已经有了数据 2. 相同类型的结构体变量可以进行整体赋值 struct stud st1, st2, st3; st1. name = “John” ; st1. age = 20 ; st1. birthday.year = 1980 ; st1. birthday.month = 11 ; st1. birthday.day = 23 ; st1. s1 = 89 ; st1. s2 = 95 ; st2=st1; st3. name=“Mary”; st3. age=20; st3. birthday=st1. birthday; st3. s1 = 76; st3. s2 = 85; struct date { int year ; int month ; int day ; } ; struct stud { char name[10] ; int age ; struct date birthday; float s1 , s2 ; } ;

  9. 3. 结构体变量的输入 输出 C语言不允许结构体变量整体进行输入和输出, 只能对结构体变量的成员进行输入和输出 gets( st1. name ) ; scanf( “%d%d%d”, &st1. birthday. year , &st1. birthday. month , &st1. birthday. day ) ; scanf ( “%d%f%f”, &st1. age , &st1. s1 , &st1. s2 ) ; puts( s1. name ) ; printf( “%4d”, st1. age ); printf( “%d .%d .%d”, st1. birthday. year , st1. birthday. month , st1. birthday. day ) ; printf(“%5.2f %5.2f\n”, st1. s1 , s1t. s2 ) ;

  10. 11.4 结构体变量的初始化 struct student { char name[10] ; int age ; float score1 , score2 ; } ; struct student st1; st1={“ Mary”, 21, 78, 86} ; struct student { char name[10] ; int age ; float score1 , score2 ; } st1={“ Mary”, 21, 78, 86} ; 这是初始化, 正确 struct stud { char name[10] ; struct date birthday ; float score1 , score2 ; } ; struct stud st2={ “John” , 1980 , 11 , 23 , 89 , 95 } ; 这是赋值, 错误 C不允许这么做

  11. 11.5 结构体数组 一、 结构体数组的定义 1. 先定义结构体类型 再定义结构体数组 struct student { char name[10] ; int age ; float s1 , s2 ; } ; struct student st[6] ; 2. 定义结构体类型的同时定义数组 struct student { char name[10] ; int age ; float s1 , s2 ; } st[6] ; 3. 直接定义结构体数组 struct { char name[10] ; int age ; float s1 , s2 ; } st[6] ;

  12. st[0] st[1] st[2] 二、结构体数组的初始化 将每个数组元素的数据用花括号{ } 括起来 struct student { char name[10] ; int age ; float s1 , s2 ; } ; struct student st[3]={ {“Mary”, 21, 78, 86}, {“Alex”, 20, 90, 80} , {“Mike”,19, 75, 68} };

  13. 都是结构体变量的整体赋值 三、 结构体数组的引用 1. 引用某个数组元素的成员 例:puts( st[0]. name ) ; printf(“%d, %d”, st[1]. age , st[1]. s1 ) ; 2. 数组元素之间可以整体赋值 也可以将一个元素赋给一个相同类型的结构体变量 struct student x , st[3]={ {“Mary”,21,78,86}, {“Alex”, …} } ; st[2] = st[0] ; x = st[1] ; 3. 只能对数组元素的成员进行输入和输出 gets( st[2]. name ) ; scanf(“%d” , &st[2]. age) ; scanf(“%f%f ”, &st[2]. s1 , &st[2]. s2 ); puts( st[0]. name ); printf(“%4d%5.2f %5.2f\n”, st[0]. age , st[0]. s1 , st[0]. s2) ;

  14. 例: 有30名学生, 每个学生包括学号、姓名、成绩, 要求找出成绩最高者,并输出他的信息 #include <stdio.h> #define N 30 void main( ) { struct student { int n ; char name[10] ; int score ; }; struct studentst[N]; int i , m ; int max ; for ( i=0 ; i<N ; i++) scanf(“%d%s%d”, &st[i].n , st[i].name, &st[i].score) ; max=st[0].score; for( i=1 ; i<N ; i++ ) if ( st[i].score > max ) { max=st[i].score; m=i; } printf(“%4d”, st[m].n ) ; printf(“%10s ”, st[m].name ); printf(“%5d ”, st[m].score); }

  15. 例: 按成绩对学生信息进行从高到底的排序 void sort(struct stud a[ ] ) { int i , j ; struct stud temp; for ( i=0 ; i<N-1 ; i++) for ( j=i+1 ; j<N ; j++) if ( a[i].s<a[j].s ) { temp=a[i] ; a[i]=a[j] ; a[j]=temp ; } } #include <stdio.h> #define N 30 struct stud { int n ; char name[10] ; int s ; }; void input(struct stud a[ ]) { int i ; for ( i=0 ; i<N ; i++) scanf(“%d%s%d”, &a[i].n, a[i].name, &a[i].s) ; } void main( ) { struct studst[N]; input(st); sort(st); output(st); } void output(struct stud a[ ]) { int i ; for ( i=0 ; i<N ; i++) printf(“%4d%10s%4d”, a[i].n, a[i].name, a[i].s) ; }

  16. 11.6 指向结构体数据的指针 一、 指向结构体变量的指针 1. 定义 struct student { char name[20] ; int age ; float s1 , s2 ; } ; struct student stu , *p ; p = &stu ; 2. 成员的引用格式 (1)结构体变量名. 成员名 stu . name (2) (*指针变量名) . 成员名 (*p) . age (3) 指针变量名 -> 成员名 p -> s1 gets( stu. name ); (*p). age = 21 ; p -> s1 = 87 ; p -> s2 = 90 ;

  17. 二、 指向结构体数组的指针 1. 定义 struct student a[3] , *p ; 2. 使用 for ( p=a ; p<a+3 ; p++ ) { gets( p->name ) ; scanf( “%d%d %d ”,&p->age,&p->s1,&p->s2) ; } 三、 结构体变量作为函数参数 1. 函数的实参和形参都用结构体变量 , 参数之间为值传递 即:实参 结构体变量各成员的值依次传给形参结构体变量 注意 结构体类型是已经定义好的 2. 返回结构体类型值的函数 函数定义格式 : 结构体类型名 函数名 ( 形参表列) { 函数体 ; } 例 : struct student funct ( int x , float y ) { 函数体 ; }

  18. 例: 求学生成绩的总分和平均分 #include <stdio.h> #define N 5 struct stud { char name[10] ; int s[3] ; float sum , ave ; } ; struct stud count (struct stud x) /*结构体变量做形参,函数返回值为结构体类型*/ { int j ; x.sum = 0 ; for ( j = 0; j<3 ; j++ ) x.sum = x.sum + x.s[j] ; x.ave = x.sum / 3 ; return(x); } void main ( ) { struct stud a[N] ; int j ; for ( j=0; j<N; j++ ) { scanf(“%s%d ”, a[j].name, &a[j].s[0] ); scanf(“%d %d ”, &a[j].s[1] , &a[j].s[2] ); } for ( j=0; j<N; j++) a[j]=count ( a[j] ) ;/*结构体数组元素名作实参*/ for ( j=0; j<N; j++) { printf(“%10s%4d”, a[j].name, a[j].s[0] ); printf(“%4d%4d”, a[j].s[1], a[j].s[2] ); printf(“%8.2f %6.2f\n”, a[j].sum , a[j].ave ); } }

  19. 数据成员 指针成员 11.7 用指针处理链表 一.、基本概念 1. 动态存储分配: 根据需要临时分配内存单元用以存放数据, 当数据不用时可以随时释放内存单元 2. 链表: 是可以动态地进行存储分配的一种数据结构 它是由一组动态数据链接而成的序列 3. 结点: 链表中的每一个动态数据称为一个结点 4. 结点类型: 是一个包含指针项的结构体类型 一般由两部分组成: (1) 数据成员: 存放数据 (2) 指针成员: 存放下一个结点的地址 struct sd { int num; int score; struct sd *next ; } ;

  20. head 2010 1428 1570 1 2 3 2010 95 86 82 1428 1570 NULL 二、简单链表 头指针 表头结点 表尾结点 NULL为空地址, 表示链表到此结束

  21. head a c b p #include <stdio.h> struct sd { int num; int score; struct sd *next ; } ; void main( ) { struct sd a,b,c,*head,*p; head=&a; a.num=1; a.score=95; a.next=&b; b.num=2; b.score=86; b.next=&c; c.num=3; c.score=82; c.next=NULL; p=head; while(p!=NULL) { printf(“%3d%4d\n”,p->num,p->score); p=p->next; } } 2010 1428 1570 2010 2 86 1570 3 82 NULL 1 95 1428 NULL 1428 1570 2010 说明: 该程序虽然建立了一个链表, 但这个链表是静态的, 因为它 的结点个数是固定的, 不能按需要增加新的结点,也不能按需要删 除结点. 这样的链表并不实用, 我们需要的是“动态链表”

  22. 三、 处理动态链表所需的函数 ( 需用头文件<stdlib.h> ) 1. malloc 函数 原型 : void *malloc( unsigned int size ) 作用 : 在内存中开辟一个长度为 size 的连续存储空间 , 并将此存储 空间的起始地址带回 注意 : (1) 函数返回值是指针, 但该指针是指向void类型的 , 因此在 使用时希望这个指针指向其他类型需要用强制类型转换 (2) 如果内存缺少足够大的空间进行分配 , 则 malloc 函数 返回值为“空指针” (即NULL) 结构体类型占用的字节长度 例: struct sd *p; p = (struct sd * ) malloc ( sizeof(struct sd) ) ; 强制类型转换

  23. p 2. free函数 原型 : void free( void *ptr ) 作用 : 将指针变量ptr指向的存储空间释放 注意: (1) ptr的值不是任意的地址, 必须是程序中执行malloc或 calloc函数所返回的地址 (2) 模型中ptr是void型, 但调用free函数时, 参数可能是 其他类型, 计算机系统会自动进行转换 例: struct sd *p; p=(struct sd *) malloc (sizeof(struct sd)) ; free(p); 4200 4200

  24. 四、 链表应用举例 1. 建立链表(表尾添加法) #include <stdio.h> #include <stdlib.h> #define ST struct student ST { int num ; int score ; ST *next ; }; #define LEN sizeof(ST) int n ; 宏定义ST , 以后书写简单 求出结构体类型占用的字节数 全局量 , n 表示结点的个数

  25. 3264 head p1 p2 n 0 2010 1428 1570 1 95 2 86 3 82 0 0 NULL 2010 1 2 3 1428 1570 NULL 1570 3264 1428 1570 1428 创建一个由head指向的链表 ST * creat(void) { ST *head , *p1 , *p2 ; n=0 ; head=NULL ; printf(“\ninput num and score:”); scanf( “%d %d ”, &x, &y ) ;/*输入某个学生的学号和成绩*/ while ( x!=0 ) /*当学号不为0时循环执行*/ { n=n+1; p1 = (ST *) malloc (LEN) ; /*生成新结点p*/ p->num=x;p->score=y; if (n= =1) head=p1 ; /*新结点为链表中第一个结点*/ else p2->next=p1 ; /*新结点为链表中中间结点*/ p2 = p1 ; printf(“\ninput num and score:”); scanf( “%d %d ”, &x, &y ) ; } p2->next = NULL ; return( head ) ;/*返回新建链表的头指针*/ } 2010 2010

  26. head p 2010 1428 1570 2010 2 86 1570 3 82 NULL 1 95 1428 2. 输出链表 (将head指向的链表从头到尾输出一遍) void list ( ST *head ) { ST *p ; p = head ; /*从表头结点开始对链表进行访问*/ while ( p!=NULL ) /*当访问完表尾结点结束循环*/ { printf(“%3d %4d\n”, p->num, p->score ) ; p = p->next ; /*找下一个结点*/ } } 1428 1570 NULL 2010

  27. 2010 1428 1570 head 2010 2 86 1570 3 82 NULL 1 95 1428 num 2 p1 p2 n 3 2 1570 3. 链表的删除 (在head指向的链表中,删除数据域为num的结点) ST *del ( ST *head , int num ) { ST *p1 , *p2 ; p1 = head ; while ( ( num!=p1->num) && (p1->next!=NULL) ) { p2 = p1 ; p1 = p1->next ; }/*p1指向被删除结点p2指向 被删除结点的前面的结点*/ if ( num = = p1->num ) { if ( p1= =head ) head=p1->next ; /*被删除结点为表头结点*/ else p2->next=p1->next ; /*被删除结点是中间结点*/ free( p1 ) ; n=n-1 ; /*释放被删除结点,链表长度减1*/ printf( “deleted ! \n”) ; /*删除成功*/ } else printf( “can not delete!\n”) ; /*删除不成功*/ return( head ) ; /*返回被删除结点链表的头结点*/ } 1428 2010 2010

  28. 1428 1570 2010 head 2010 5 82 NULL 1 95 1428 3 86 1570 2680 p1 p0 p2 n 3 4 2680 4. 链表的插入 ST *insert ( ST *head ) { ST *p0 , *p1 , *p2 ; p1=head ; p0=( ST *) malloc ( LEN ) ; scanf (“%d%d”, &p0->num, &p0->score) ; if ( head= =NULL ) /*链表为空*/ { head = p0 ; p0->next = NULL ; } else { while ( ( p0->num > p1->num ) && ( p1->next!=NULL) ) { p2 = p1 ; p1 = p1->next ; }/*寻找结点插入位置*/ if ( p0->num<p1->num ) /*插入结点位置在链表中间*/ { if ( head= =p1) head = p0 ; else p2->next =p0 ; p0->next = p1 ; /*将结点插入到链表中*/ } else { p1->next = p0 ; p0->next = NULL; } /*插入结点位置在链表尾部*/ } n++ ;/*链表长度加1*/ return( head ) ;/*返回处理后链表的头指针*/ } 2010 1428 1570 1428 2010 4 75 1570 2680

  29. 1428 1570 2010 head 2010 5 82 NULL 2 95 1428 3 86 1570 2680 p0 p1 p2 n 3 插入的结点作为表头 4 2680 1 75 2680 2010 2010

  30. 1428 1570 2010 head 2010 5 82 NULL 2 95 1428 3 86 1570 2680 p0 p1 p2 n 3 插入的结点作为表尾 4 2680 8 75 1570 1428 2010 1428 2010 2680 NULL

  31. 5. main 函数 void main ( ) { ST *h ; int delnum ; h = creat( ) ; list ( h ) ; scanf(“%d”, &delnum ) ; h = del ( h , delnum ) ; list ( h ) ; h = insert ( h ) ; list ( h ) ; } /* 建立一个链表 */ /* 输出链表 */ /* 输入要删除的学号 */ /* 删除学号为delnum的结点 */ /* 在链表中插入一个结点 */

  32. 课后作业:P297 11.5 11.8 11.10

More Related