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

一、结构体

#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个字节。



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;
}

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;
}


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的参数是指针形式的,其内存关系如下:


所以要采用指针的形式

#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 结构,还是指向结构的指针

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

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

    

猜你喜欢

转载自blog.csdn.net/qq_37764129/article/details/80824960