欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言笔记(十五)——结构体、联合体、枚举与typedef

程序员文章站 2022-03-09 15:21:19
...

一、结构体

#include <stdio.h>
struct student//student是结构体名字
{
    char name[100];
    int age;
    int sex;
}; //说明了结构体的数据成员类型.不能直接用student,需要在主函数中定义变量

int main()
{
    /**********定义结构体的方法1**************/
/*    struct student st;//定义了一个结构体变量,名字叫st,在栈里
    st.age = 20;
    st.sex = 1;
    strcpy(st.name, "BoBo");*/
        /**********定义结构体的方法2**************/
    struct student st = {"BoBo", 25, 0}; //定义了一个结构体变量,名字叫st
        /**********初始化结构体**************/
 //   struct student st = { 0 }; //定义了一个结构体变量,名字叫st,同时将所有成员值初始化为0

    printf("name = %s\n", st.name);
    printf("age = %d\n", st.age);
    if(st.sex == 0)
    {
        printf("sex = 男\n");
    }
    else
    {
        printf("sex = 女\n");
    }
    return 0;
}

1.1 定义结构体struct与成员初始化的几种方法

法1:
 struct student st;//定义了一个结构体变量,名字叫st,在栈里.注:定义时各变量顺序要跟声明顺序一致。st是结构体变量名称
    st.age = 20;
    st.sex = 1;
    strcpy(st.name, "BoBo");
法2:定义并初始化
 struct student st = {"BoBo", 25, 0}; //定义了一个结构体变量,名字叫st。注:定义时各变量顺序要跟声明顺序一致
法3:定义并初始化
struct student st = {.name = "BoBo", .age = 25, .sex = 0}; //“.成员变量名”的形式可以不用按声明顺序赋值。

初始化为0的方法

法4:

 struct student st = { 0 }; 

法5:

memset(&st, 0, sizeof(st));

1.2 结构体的访问

.操作符

结构体变量名字.成员变量名字

eg: 

    printf("name = %s\n", st.name);

1.3 结构体的内存对其方式

    编译器在编译一个结构的时候采用内存对齐模式。

比如结构声明有一个int,一个char,则有8个字节。

C语言笔记(十五)——结构体、联合体、枚举与typedef

C语言笔记(十五)——结构体、联合体、枚举与typedef

1.4 指定结构体元素的位字段

    定义一个结构体的时候可以指定具体元素的位长。1字节 = 8bit

struct text

{

    char a : 2; //定义一个成员类型为char,但这个成员只使用2个bit。指定元素为2位长,不是2个字节长

};

struct A

{

    int x : 4;

    char a : 2;

    char b : 1;

}

则A的长度为8个字节。因为int型有4个字节,char a,b只能在下一行,尽管它俩只用了3bit,但根据内存对齐方式,结构A共占了8字节
注:指定位长不能超过该变量类型的位数范围。比如int a : 32 最大只能使用32位,不能多用。
1.5 结构数组
给结构数组赋值

struct man{

    char name[20];
    char score;
};

int main()
{

    struct man m[10] = { {"tom", 12}, {"marry", 10}, {"jack", 9} }; //在栈中定义数组,有10个成员,m【0】-m【9】

   // struct student *p = malloc(sizeof(struct student) * 3);//在堆中定义了3个成员的数组

    int i;
    for(i = 0; i < 3; i++)
        {
            printf("名字 = %s, 分数 = %d\n", m[i].name, m[i].score);
        }
return 0;
}

*堆、栈中分别定义数组访问数组成员

在栈中

定义数组:

     struct man m[10] = { {"tom", 12}, {"marry", 10}, {"jack", 9} }; //在栈中定义数组,有10个成员,m【0】-m【9】

访问数组:

    m[2].age = 5; //将j结构体变量m中第三个成员的age项赋值5.

在堆中

定义数组:

    struct student *p = malloc(sizeof(struct student) * 3);//在堆中定义了3个成员的数组

访问数组:

   p[0].age = 100;//将结构体变量p的第一个成员的age项赋值为100

或者

    p -> age = 100; //此方法只适用于指针

结构赋值:将数组中某一元素跟另一元素交换位置。比如将下面的程序放到上面结构体定义的下面,可以将结构体中 {"tom", 12}, {"marry", 10}这两元素换位显示。

struct student tmp = m[0];

m[0] = m[1];

m[1] = tmp;

结构体数组排序:采用冒泡算法将数组成员按年龄从小到大排序,年龄一样的,按成绩由小到大排

struct man{
    char name[20];
    char age;
    char score;
}; //结构体说明
void swap(struct man *p, struct man *a) //函数定义
{
    struct man tmp = *p;
    *p = *a;
    *a = tmp;
}
int main()
{
    struct man m[10] = { {"tom", 36, 12}, {"marry", 15, 10}, {"jack", 100, 9}, {"jj", 20, 12} };
    int i, j;
    for(j = 0; j < 4; j++)
    {
        for(i = 1; i < 4 - j; i++)
            {
                if(m[i].age > m[i - 1].age)
                {
                    swap(&m[i], &m[i - 1]);
                }
                else
                    if((m[i].age == m[i - 1].age) && (m[i].score > m[i - 1].score))
                    {
                        swap(&m[i], &m[i - 1]);
                    }
            }
    }
    for(i = 0; i < 4; i++)
    {
        printf("名字 = %s, 年龄 = %d, 分数 = %d\n", m[i].name, m[i].age, m[i].score);
    }
return 0;
}

1.6 嵌套结构

    一个结构的成员还可以是另一个结构类型

struct A
{
    int a;
    char b;
};
struct B
{
    struct A a;
    char c;
};
int main()
{
    printf("%d\n", sizeof(struct B));
    return 0;
}
C语言笔记(十五)——结构体、联合体、枚举与typedef

C语言笔记(十五)——结构体、联合体、枚举与typedef

1.7 结构体的赋值

struct name a = b;

结构赋值:将数组中某一元素跟另一元素交换位置。比如将下面的程序放到上面1.5例子中结构体定义的下面,可以将结构体中 {"tom", 12}, {"marry", 10}这两元素换位显示。

struct A a1, a2;

a1.a = 10;

a2.b = 20;

a2 = a1;//结构体赋值,其实就是结构体之间内存的拷贝

1.8 指向结构体的指针

   “->”操作符:表示指针访问一个结构体的成员

struct A
{
  int a;
  int b;
};
int main()
{
    struct A a;
    struct A *p = &a;
    p ->a = 2;
    p ->b = 6;
    printf("a = %d, b = %d\n", a.a, a.b);
}

1.9 指向结构体数组的指针

struct A
{
    int a;
    int b;
};
int main()
{
    struct A array[10] = { 0 };//栈里创建数组
    struct A *p = &array; //定义一个指针指向结构体地址
    p -> a = 1; //数组的第0个元素分别设置为1和2.指针访问一个结构体的成员
    p -> b = 2;
    p++;//设置数组的下一个元素
    p -> a = 3;
    p -> b = 4;
    int i;
    for(i = 0; i < 10; i++)
    {
        printf("a = %d, b = %d\n", array[i].a, array[i].b);
    }
    return 0;
}

C语言笔记(十五)——结构体、联合体、枚举与typedef

1.10 结构中的数组成员和指针成员

    一个结构中可以有数组成员,也可以有指针成员。若是指针成员,结构体成员在初始化和赋值时就需要提前为指针成员分配内存

结构中的数组成员例子:

struct child
{
    char name[30];
    int age;
};
struct child_a
{
    char *name;
    int age;
};
int main()
{
    struct child st;
    st.age = 30;
    strcpy(st.name, "liudehua");
   
    printf("%d, %s\n", st.age, st.name);
    free(st.name);
    return 0;
}
结构中的指针成员例子:
struct child
{
    char name[30];
    int age;
};
struct child_a
{
    char *name;
    int age;
};
int main()
{
    struct child_a st = {NULL, 0};//因为child_a中name是指针,所以结构体定义这要对结构成员初始化
    st.age = 30;
    //因为*name的地址为NULL,所以下面要给name重新分配内存
    st.name = malloc(100);
    strcpy(st.name, "liudehua");

    printf("%d, %s\n", st.age, st.name);
    free(st.name);
    return 0;
}

1.11 结构作为函数的参数

    将结构作为函数参数,将结构指针作为函数参数

#include <stdio.h>
struct student
{
    char name[10];
    int age;
};
//不建议用结构体作为函数的参数使用
void print_student(const struct student s) //为防止内容被修改,所以加const
{
    printf("name = %s, age = %d\n", s.name, s.age);
}
void set_student(struct student s, const char *name, int age)//指针作为参数,只需要传递一个地址,所以代码效率高。因此当一个结构作为函数的参数时,尽量使用指针,而不是使用结构变量
{
    strcpy(s.name, name);
    s.age = age;
}

int main(void)
{
    struct student st = {"tom", 20};
    set_student(st, "mike", 100); //加上set_student以及这一句后,运行的结果仍然是name = tom, age = 20.
    print_student(st);
    return 0;
}

set_student(st, "mike", 100);//这个函数的作用是将它的值复制到s.name中输出,但它忽略了set_student的参数是指针形式的,其内存关系如下:

C语言笔记(十五)——结构体、联合体、枚举与typedef

所以要采用指针的形式

#include <stdio.h>
struct student
{
    char name[1000];//栈中数量很大时,函数入栈时要消耗很多资源,采用指针的话,由于只需要传一个地址,所以效率会很高
    int age;
};
void print_student(const struct student *s) //为防止值在传递过程过程被修改,所以要加const
{
    printf("name = %s, age = %d\n", s->name, s->age);
}
void set_student(struct student *s, const char *name, int age)
{
    strcpy(s->name, name);
    s->age = age;
}
int main(void)
{
    struct student st = {"tom", 20};
    set_student(&st, "mike", 100);
    print_student(&st);
    return 0;
}

1.12 结构,还是指向结构的指针

    在定义一个和结构有关的函数时,是使用结构还是结构的指针?

    指针作为参数,只需要传递一个地址,所以代码效率高。因此当一个结构作为函数的参数时,尽量使用指针,而不是使用结构变量,这样代码效率很高。