黑马程序员——4、C语言(结构体、枚举)

本文详细介绍了C语言中的结构体与枚举的概念、定义及应用。包括结构体的三种定义方式、存储空间分配、使用方法、类型作用域等,以及结构体数组、指向结构体的指针和结构体嵌套定义等内容。同时,还讲解了枚举类型的定义方式、注意事项及枚举变量的操作。

---------------------- Java培训、Android培训、iOS培训、.Net培训期待与您交流! ---------------------


一、结构体

  1. 结构体的定义

结构体与数组的区别

数组:只能由多个相同类型的数据构成

结构体:可以由多个不同类型的数据构成

struct是关键字,是结构体类型的标志。

(1)定义结构体的3种方式

/*定义结构体变量方式1:定义类型后定义变量
     struct Student{
     int age;
     double height;
     char *name;
     };
     struct Student stu = {20, 1.78, "jack"};
     */
    
    /*定义结构体变量方式2:定义类型同时定义变量
     struct Student{
     int age;
     double height;
     char *name;
     } stu = {20, 1.78, "jack"};
     */
    
    /*定义结构体变量方式3:定义类型同时定义变量,但省结构体名称,不能重用
     struct {
     int age;
     double height;
     char *name;
     } stu = {20, 1.78, "jack"};
     */

(2)定义结构体时的存储空间分配问题

结构体类型变量在分配存储空间的时候,由低地址到高地址顺序分配给各个内部成员。

仅仅定义类型的时候,不会分配存储空间:

struct Date{

       int year;

       int month;

       int day;

    };

定义变量的时候,才真正分配存储空间:

struct Date d1 = {2011,9,10};

(3)结构体的使用

1》一般对结构体变量的操作都是以成员为单位进行的,引用的一般形式:结构体变量名.成员变量名。

2》如果某个成员变量也是结构体变量,那么可以继续用成员运算符"."访问低一级的成员。

3》相同类型的结构体变量之间可以进行整体的赋值。

(4)结构体类型的作用域

1》定义在函数外面,全局有效(从定义类型的那行开始,一直到文件的结尾)

2》定义在函数内部,局部有效(从定义类型的那行开始,一直到代码块或函数结束)

(5)结构体的补齐算法

结构体所占存储空间,必须是最大成员字节数的倍数。

结构补齐原则:

1》数据成员对齐规则:结构的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储起始位置要从该成员大小的整数倍开始。

2》结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。

3》sizeof计算结构体大小:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

struct A  
{  
    short a; //大小为2, 因为b的大小是4,所以要补2  
    int b; //大小为4  
    char c; // 大小为1  
    // 所以2(a)+2(补齐)+4(b)+1(c)=9,注意:还没完,根据“原则3”,9不是内部最大成员(4)的整数倍,所以整个结构体要按4字节对齐,那么最终结果9+3(补齐)=12  
};  
  
struct B  
{  
    int a; // 大小为4,  
    char b; // 大小为1,因为c大小为2,所以b需要补1  
    short c; //大小为2  
    // 所以4(a)+1(b)+1(补齐)+2(c) = 8(也满足“原则3”)  
};  
  
struct C  
{  
    int a; // 大小为4,<span style="font-family: Arial, Helvetica, sans-serif;">因为b的大小是8,所以要补4 </span>
    double b; // 大小为8 
    float c; // 大小为8 
    // 所以 4(a)+4(补齐)+8(b)+8(c) = 24;  
};  
  
struct D  
{  
    char e[2]; //大小为2,因为f为4,所以补2
    int f; // 大小为4
    double g; // 大小为8  
    float h; // 大小为8  
    struct C i; // 因为前面总数为8的倍数(C的最大值为8)所以不用补位(总大小为24)  
    // 所以 2(e[2])+2(补齐)+4(f)+8(g)+8(h)+24(i) = 48,满足第三条  
};  
  
int main()  
{
    printf("sizeof(A)=", sizeof(A));  // 12
    printf("sizeof(B)=", sizeof(B));  // 8
    printf("sizeof(C)=", sizeof(C));  // 24
    printf("sizeof(D)=", sizeof(D));  // 48
    return 0;  
}

  2. 结构体数组

既然结构体是一种数据类型,那么结构体就可以成为数组的元素类型。

struct Rank{
        int no;     
        char *name; 
        int score; 
    };
    struct Rank r[3] = {
        {1, "jack", 3000},
        {2, "jim", 1000},
        {3, "rose", 500}
    };

  3. 指向结构体的指针

每个结构体都有自己的存储空间和地址,我们可以使用一个指针变量来指向某一个结构体变量。

结构体指针变量的定义形式:struct 结构体名 *指针变量名

访问结构体成员的3种方式:

》结构体变量名.成员名

》(*指针变量名).成员名

》指针变量名->成员名

struct Student{
        int no;
        char *name;
    };
    struct Student stu1 = {51041, "joke"};
    
    //指针变量p将来指向struct Student类型数据
    struct Student *p;
    p = &stu1;
    
    p->no = 1400518;
    
    printf("no=%d, name=%s\n", stu1.no, stu1.name);
    printf("no=%d, name=%s\n", (*p).no, (*p).name);
    printf("no=%d, name=%s\n", p->no, p->name);

  4. 结构体和函数

如果结构体作为函数的参数,则只是将实参结构体所有成员的值对应地赋值给了形参结构体的所有成员。因此,形参的改变不会影响到实参。

struct Student{
    int age;
    int no;
};

//不会影响实参
void test(struct Student s)
{
    s.age = 30;
    s.no = 2;
}

//会影响实参
void test2(struct Student *p)
{
    p->age = 15;
    p->no = 3;
}

//重新赋值了指针p,所以对实参没有影响了
void test3(struct Student *p)
{
    struct Student stu2 = {10, 4};
    p = &stu2;
    p->age = 14;
    p->no = 5;
}

int main()
{
    struct Student stu = {28, 1};
    
    //test(stu);
    //test2(&stu);
    test3(&stu);
    
    
    printf("age=%d, no=%d\n", stu.age, stu.no);
    
    return 0;
}

  5. 结构体的嵌套定义

结构体可以作为数据类型定义另一个结构体的成员变量。

struct Date {
        int year;
        int month;
        int day;
    };
    
    struct Student{
        int no;
        struct Date birthday;
        struct Date ruxueDate;
    };

注意:结构体不可以自己包含自己。



二、枚举

枚举是C语言的一种基本数据类型,并不是构造类型。当变量有几个固定的可能取值时,我们就可以把这个变量定义为枚举类型。

  1. 枚举类型的定义

格式:enum 枚举名 {枚举元素1, 枚举元素2, ...};

枚举定义的3中方式:

1》先定义枚举类型,再定义枚举变量

2》定义枚举类型的同时定义枚举变量

3》省略枚举名称,直接定义枚举变量

// 先定义枚举类型,再定义枚举变量
    enum Sex {
        SexMan,
        SexWoman
    };
    enum Sex s = SexMan;
    
    // 定义枚举类型的同时定义枚举变量
    enum Sex {
        SexMan,
        SexWoman
    } s;
    s = SexMan;
    
    // 省略枚举名称,直接定义枚举变量
    enum {
        SexMan,
        SexWoman
    } s;
    s = SexMan;

  2. 枚举的注意事项

1》C语言编译器将会把枚举元素当做整形常量来处理。

enum Sex {
        SexMan, //值为0
        SexWoman //值为1
    };

2》枚举元素的值取决于定义时各个枚举元素的顺序,默认第一个枚举元素的值为0,第二个为1,依次累加。

3》可以在定义枚举类型的时候指定某个枚举元素的值

enum Sex {
        SexMan=5, //值为5
        SexWoman //值为6
    };

  3. 枚举变量的操作

(1)赋值

可以将枚举变量赋值为枚举常量或整型值(整形值必须要有意义)

    enum Sex {
        SexMan,
        SexWoman
    } s;
    s = SexMan;
    s = 1; // s = SexWoman;

(2)遍历枚举元素

    enum Sex {
        SexMan,
        SexWoman
    } s;
    s = SexMan;
    s = 1; // s = SexWoman;
    for (int i = SexMan; i <=SexWoman; i++)
    {
<span style="white-space:pre">	</span>printf("枚举元素:%d \n", i);
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值