结构与联合_C语言快速入门与计算机二级备考

结构

声明结构体类型

  • 结构体:本质是用户自己建立的,由不同类型数据组成的,组合类型的数据结构

  • 一般形式为:structt 结构名 {成员列表(类型名 成员名;)}; 例如:

    struct Student{
    	int num; 
    	char name[20];
    	char sex;
    	int age; 
    	float score;
    	char pho[30];
    };//这里有分号!
    
  • 结构体中的成员可以属于另一个结构体类型,嵌套使用,例如:

    struct date{int y; int m; int d;};
    struct Student{……struct date birthday;}//在Student内使用date的结构体类型
    
  • 和本地变量一样,在函数内部声明的结构类型只能在函数内部使用,而在外部声明的结构类型可以被多个函数使用

定义结构体变量

  • 定义结构体变量struct 结构类型名 结构体变量名;

    struct point{
    	int x;
    	int y;
    }//定义了point,包含x和y
    struct point p1,p2;//定义了point类型的p1,p2
    
    //声明结构时能够同时完成声明与定义结构变量,用于只需要几个结构体变量的情况,如下
    struct {
    	int x;
    	int y;
    } p1,p2; //p1与p2都是一种无名结构,里面包含了x和y
    struct point{
    	int x;
    	int y;
    }p1,p2; //p1与p2都是point,里面有x和y
    
  • 为变量赋值结构体变量名.类型名=变量;

    例如:

    struct Student a;//定义学生a结构体变量
    a.name="lihua";
    a.age=18;
    a.birthday.mouth=10;
    
    struct Student a={“lihua”,18,10……};//必须按顺序,编译器自动对号入座
    
    struct Student a={.age=18, .birthday.mouth=10……};
    //可以只给部分值,类似于数组的初始化,没给的值将会被赋0
    
    struct Student b;
    a=b;//同结构体变量可以直接赋值
    
  • .是一个取成员的运算符,类似数组的[]

    数组用[]和下标访问其中成员,如a[0]=10;

    结构用.和名字访问其中成员,如a.x=10;

结构体变量的运算

  • 对于整个结构,可以直接用结构变量的名字,赋值、取地址、传递参数等
  • p1=(struct point){5,10}; //强制类型转换,将5和10两个值转换为struct point类型的变量
    //相当于p1.x=5;p1.y=10;
    p1=p2;//相当于p1.x=p2.x;p1.y=p2.y
    
    //数组就无法做这两种运算
    

函数与结构

  • 结构能传入函数/被函数返回

    从函数的((20241111170228-47u8xd5 "参数传递"))中得知,C在调用函数时,只能传递值给函数,变量与参数并不会有联系,结构类型同理(注意区分结构与数组的不同,结构并非指针)

    在作为函数参数时,被传入函数的并非外面的结构,而只是外面结构的克隆体,在不同函数内对其进行的操作将无法对原本的结构形成修改

    //设计一个输入结构的函数来说明
    struct a {
    	int x;
    	int y;
    };
    void input(struct a p){
    	scanf("%d", &p.x);
    	scanf("%d", &p.y);
    	//`.`取成员的优先级比`&`取地址高,所以`&a.x`表示取a.x的地址
    	printf("%d,%d\n", p.x, p.y);
    }
    int main(){
    	struct a test = { 0,0 };
    	input(test);
    	printf("%d,%d", test.x, test.y);
    	return 0;
    }
    //input函数中的p与main函数中的test没有关系,因为函数只能传递值而非量
    //因此,程序实际做的事是:将一个结构传入函数,在这个函数内对其修改,而没有返回回去
    //因此,两次输出并不会相同,表明这个函数无法对结构变量test修改
    
    //解决方法:利用结构变量可以直接赋值的特性,在函数中创立一个临时的结构变量,再将其返回
    struct a input()
    {
    	struct a p;
    	scanf("%d", &p.x);
    	scanf("%d", &p.y);
    	printf("%d,%d\n", p.x, p.y);
    	return p;//创建了一个临时的结构变量p作为替身,对其修改后返回
    }
    int main()
    {
    	struct a test = { 0,0 };
    	test=input();//将修改后返回的p赋给test
    	printf("%d,%d", test.x, test.y);
    	return 0;
    }
    
  • 指向结构的指针

    与上面的例子相比,使用指针要比创建整个结构的替身这种做法更方便,更省空间

    ->运算符表示指针所指的结构变量中的成员,例如:

    struct date {
    	int month;
    	int day;
    	int year;
    }myday;
    struct date *p=&myday;//结构与数组不同,它不是指针,所以要用上&取地址
    //p这个指针指向myday这个结构变量
    (*p).month=12;
    //.运算符取出p所指的myday中的month
    //()强制类型转换将12变成date类型中的month
    
    p->month=12;//这样与上述代码效果相同
    //->运算符优先级高于对取出元素的运算
    

    由此可以对上文的结构输入程序进行修改:

    void main(){
    	struct a test={0,0};
    	input(&test);//将要修改的结构test的地址传入
    	printf("%d,%d", test.x, test.y);
    }//由于通过指针直接操作外面的test,所以不需要将p返回
    void input(struct a *p){
    	scanf("%d",&(p->x));
    	scanf("%d",&(p->y));
    }
    

结构的变体

  • 结构数组

    为了方便定义多个结构体变量,使用结构数组

    结构数组可以同结构变量一样被赋值,被传递给一个函数

    有了结构数组,多个结构输入程序可以简化流程,不必一个一个结构成员输入

    struct date dates[100];//这就定义了一个结构数组
    //这表示一个数组dates,含有100元素
    //每个元素都是结构体变量struct date,都包含所有的结构体成员
    
  • 结构中的结构

    在声明结构体变量时提到了结构体中嵌套使用结构体

    对于含嵌套的结构体,使用指针例:

    struct point{
    	int x;
    	int y;
    };//声明一个结构point
    struct rectangle{
    	struct point pt1;
    	struct point pt2;
    };//声明了一个嵌套了point结构的结构rectangle
    //包含关系为:{rectangle类型 [point类型 pt1(int x,y)][point类型 pt2(int x,y)]}
    struct rectangle r;
    r.pt1.x//对于rectangle类型的r,可以用这种方式取被嵌套的成员
    
    struct rectangle r,*rp;
    rp=&r;//声明了两个结构体变量,一个是r,另一个是指向r的指针
    r.pt1.x
    rp->pt1.x
    (r.pt1).x
    (rp->pt1).x//这四种形式等价
    rp->pt1->x//这种写法是错误的,因为pt1是指针
    

联合

声明联合

  • union 联合名 {成员列表(类型名 成员名;)};

    类似于结构struct,也由不同的成员构成,例如:

    union AnElt{
    	int i;
    	char c;
    } elt1,elt2; //同创建结构类型一样,此处创建了两个名为elt1与elt2的联合类型AnElt
    

联合的特点

  • 与结构的区别在于结构的各个成员是相互独立的,但联合中的各个成员共用一个内存空间,同一时间内只有一个成员是有效的

    但是在使用时不能直接引用,要同结构体一样引用其中的成员

  • 联合的大小是一个联合最大的成员

  • 对于这些特点的解释:一个联合占据一定的内存空间,其中成员共同使用这些空间,当另一个成员使用时将会盖住原来成员的数据,而这些成员都无法超出联合的大小

联合的应用

  • 初始化时,对联合的第一个成员初始化

  • 利用union输出一个变量在内存中保存的各个字节

    typedef union{
    	int i;
    	char ch[sizeof(int)];
    }CHI;//创建一个联合并命名为CHI,其中包括一个整数i与一个长度为整数类型大小的字符数组
    int main()
    {
    	CHI test;
    	test.i=1234;//以1234为例,其16进制为00 00 04 D2
    	for(int i=0;i<sizeof(int);i++)
    	{
    	printf("%02hhX",test.ch[i]);
    	}
    return 0;
    }
    //注意:我们常用的x86计算机属于小端储存(数据的高字节保存在内存的高地址中)
    //例如:0x12345678在内存中分布为0x78|0x56|0x34|0x12(设从左到右内存地址升高)
    //于是1234实际保存的方式为D2 04 00 00,这较小的一位会保存在前面(低位在前)
    

自定义数据类型

  • 例如:在使用结构体变量时,每次都要写struct 变量名以表示其类型,又或者使用无符号数据类型时类型名会很长,书写很不方便

  • 通过typedef可以声明一个已有数据类型的新名字

  • 这种做法可以改善程序的可读性,或者简化了复杂的变量名例如:

    typedef int length;//使length成为int类型的别名,可替代int出现在变量定义或参数声明中
    typedef struct ADate{
    	……
    }Date;//定义了一个结构体变量类型struct ADate,简化其名为Date
    
    length = 1000;//重载了已有的类型名,新名字的含义更清晰
    Date d ={……};//简化了原本复杂的变量名struct ADate d
    

posted on 2024-11-15 13:57  无术师  阅读(52)  评论(0)    收藏  举报