黑马程序员——C语言学习之结构体和枚举

时间:2021-12-19 00:22:56

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

结构体

一、什么是结构体

对于数组中,每个元素都是相同的,如果我们想使每个元素不同的话,我们可以考虑使用结构体。
结构体可以由多种不同类型的数据类型组成的新的数据类型

 

二、结构体的定义

1.定义形式

结构体的定义以struct为,结构体内部的元素,也就是组成成分,我们一般称为"成员"。

其基本结构为:

struct 结构体名{
类型名1 成员名1;
类型名2 成员名2;
……
类型名n 成员名n;   
};

 

2.举例

定义一个学生,有姓名、年龄、身高三条属性

struct Student {

char *name; // 姓名

int age; // 年龄

float height; // 身高

};

 

三、结构体变量的定义

结构体的定义有三种形式,下面一一给出

1.先定义结构体类型,再定义变量

struct Student {

char *name;

int age;

};


struct Student stu;

 

2.定义结构体类型的同时定义变量

struct Student {

char *name;

int age;

} stu;


 

3.直接定义结构体类型变量,省略类型名

struct {

char *name;

int age;

} stu;

 

四、结构体的注意点

1.关于递归

不允许对结构体本身递归定义,下面做法是错误的:

struct Student {

int age;

struct Student stu;

};

 

2.关于包含

结构体内可以包含别的结构体

struct Date {

int year;

int month;

int day;

};


struct Student {

char *name;

struct Date birthday;

};

 

3. 关于存储空间

定义结构体类型,只是说明了该类型的组成情况,并没有给它分配存储空间,就像系统不为int类型本身分配空间一样。只有当定义属于结构体类型的变量时,系统才会分配存储空间给该变量

struct Student {

char *name;

int age;

};

struct Student stu;

 

第1~4行并没有分配存储空间,当执行到第9行时,系统才会分配存储空间给stu变量。

 

4. 关于内存大小

结构体变量占用的内存空间是其成员所占内存之和,而且各成员在内存中按定义的顺序依次排列

struct Student {

char *name; // 姓名

int age; // 年龄

float height; // 身高

};

 

在64位编译器环境下,一个Student变量共占用内存:8 + 4 + 4 = 16字节。

 

五、结构体的初始化

1. 声明变量的同时初始化

    struct Student {

int age;

char *name;

};

struct Student stu = {22, "hello"};

 

2. 先声明变量,再逐一初始化

    struct Student stu;

stu.age = 22;

stu.name = "hello";

 

3. 定义结构体的同时进行变量定义和初始化

    struct Student {

int age;

char *name;

} stu = {22, "hello"};

 

4. 非顺序初始化

struct Student stu = {.name = "hello", .age = 22};

 

5. 注意

1> 如果没有初始化结构体,所有变量会自动的有默认值

2> 只能在定义变量的同时进行初始化赋值,初始化赋值和变量的定义不能分开,下面的做法是错误的:

struct Student stu;

stu = {"MJ", 27};

 

六、结构体的使用

1. 结构体变量是基本数据类型

    int age = stu.age;

char *name = stu.name;

 

2. 结构体的成员

一般对结构体变量的操作是以成员为单位进行的

引用的一般形式为:

结构体变量名.成员名
struct Student {    char *name;    int age;}; struct Student stu; // 访问stu的age成员stu.age = 27;

 

"."称为成员运算符,它在所有运算符中优先级最高

 

3. 结构体变量是结构体

如果某个成员也是结构体变量,可以连续使用成员运算符"."访问最低一级成员

    struct Date {

int year;

int month;

int day;

};



struct Student {

int age;

char *name;

struct Date birthday;

};



struct Student stu = {22, "hello", {1999, 10, 10}};

int year = stu.birthday.year;

int month = stu.birthday.month;

int day = stu.birthday.day;

 

4. 相同类型的结构体变量之间可以进行整体赋值

struct Student {

char *name;

int age;

};



struct Student stu1 = {"MJ", 27};



// 将stu1直接赋值给stu2

struct Student stu2 = stu1;



printf("age is %d", stu2.age);


 

七、结构体数组

1. 定义

跟结构体变量一样,结构体数组也有3种定义方式

1> 方式一:

   // 方式一

struct Student {

int age;

char *name;

} stus[3];


 

2> 方式二:

  // 方式二

struct Student {

int age;

char *name;

};

struct Student stu[3];


 

3> 方式三:

    // 方式三

struct {

int age;

char *name;

} stus[3];

 

2.初始化

struct {

char *name;

int age;

} stu[2] = { {"MJ", 27}, {"JJ", 30} };

 

也可以用数组下标访问每一个结构体元素,可以参照数组的笔记。

 

八、结构体指针

1. 格式

struct 结构体名 *指针名;

 

2. 访问结构体的方式

1> 之前访问结构体的方式是:

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


2> 现在增加两种:

(*指针名).成员变量名
指针名->成员变量名

 

3. 例子

#include <stdio.h>



int main(int argc, const char * argv[]) {

// 定义一个结构体类型

struct Student {

char *name;

int age;

};



// 定义一个结构体变量

struct Student stu = {"MJ", 27};



// 定义一个指向结构体的指针变量

struct Student *p;



// 指向结构体变量stu

p = &stu;



/*

这时候可以用3种方式访问结构体的成员

*/

// 方式1:结构体变量名.成员名

printf("name=%s, age = %d \n", stu.name, stu.age);



// 方式2:(*指针变量名).成员名

printf("name=%s, age = %d \n", (*p).name, (*p).age);



// 方式3:指针变量名->成员名

printf("name=%s, age = %d \n", p->name, p->age);



return 0;

}

 

九、结构体与函数

1. 结构体作为函数参数

结构体实参会把成员变量值对应的赋值给函数结构体参数对应的变量值,改变函数结构体参数不会影响到实参。

#include <stdio.h>



// 定义一个结构体

struct Student {

int age;

};



void test(struct Student stu) {

printf("修改前的形参:%d \n", stu.age);

// 修改实参中的age

stu.age = 10;



printf("修改后的形参:%d \n", stu.age);

}



int main(int argc, const char * argv[]) {



struct Student stu = {30};

printf("修改前的实参:%d \n", stu.age);



// 调用test函数

test(stu);





printf("修改后的实参:%d \n", stu.age);

return 0;

}

 

输出结果为:

修改前的实参:30

修改前的形参:30

修改后的形参:10

修改后的实参:30

 

形参是改变了,但是实参一直没有变过

 

2. 结构体指针作为函数参数

struct Student {

int age;

char *name;

};



void test(struct Student * s)

{

// 对结构体s的操作会影响到stu

s->age = 10;

s->name = "world";

}



int main()

{

struct Student stu = {23, "hello"};

test(&stu);

printf("%d, %s\n", stu.age, stu.name);



return 0;

}

 

输出:

10, world


 

枚举

一、枚举综述

枚举是C语言中的一种基本数据类型,并不是构造类型,它可以用于声明一组常数。当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型。

枚举的本质其实是int类型,而且枚举是有序的,第一个枚举类型成员是int类型的0,后面是1、2、3…以此类推,枚举定义的成员变量也可以不从0开始,但是MJ老师说过没有必要修改。

 

二、枚举类型的定义

1. 定义格式

enum 枚举名 {
元素1, 元素2, ...
}

 

以后一般与typedef联合使用,方便程序员,此是后话。

 

2.举例

enum Season {

spring,

summer,

autumn,

winter

};

 

三、枚举变量的定义

上面只是介绍了枚举类型本身,下面用枚举类型定义变量。

不定义变量没法编程不是?!

跟结构体一样,有3种方式定义枚举变量

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

enum Season {

spring,

summer,

autumn,

winter

};



enum Season s;

 

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

enum Season {

spring,

summer,

autumn,

winter

}s;

 

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

enum {

spring,

summer,

autumn,

winter

}s;

 

四、枚举使用的注意

1> C语言编译器会将枚举元素(spring、summer等)作为整型常量处理,称为枚举常量。

2> 枚举元素的值取决于定义时各枚举元素排列的先后顺序。默认情况下,第一个枚举元素的值为0,第二个为1,依次顺序加1。

enum Season {

spring,

summer,

autumn,

winter

};

 

也就是说spring的值为0,summer的值为1,autumn的值为2,winter的值为3

 

3> 也可以在定义枚举类型时改变枚举元素的值

enum Season {

spring,

summer = 3,

autumn,

winter

};

 

没有指定值的枚举元素,其值为前一元素加1。也就说spring的值为0,summer的值为3,autumn的值为4,winter的值为5

还是那句话,MJ老师说这玩意真没必要改,也没几个蛋疼的程序员改这东西。

个人觉得,如果程序员是处女座的话,呵呵呵呵呵。。。。。

 

五、枚举变量的基本操作

1.赋值

可以给枚举变量赋枚举常量或者整型值,其实他们都是一回事。

enum Season {

spring,

summer,

autumn,

winter

} s;



s = spring; // 等价于 s = 0;



s = 3; // 等价于 s = winter;

 

2.遍历枚举元素

enum Season {

spring,

summer,

autumn,

winter

} s;



// 遍历枚举元素

for (s = spring; s <= winter; s++) {

printf("枚举元素:%d \n", s);

}

 

输出结果:

枚举元素:0

枚举元素:1

枚举元素:2

枚举元素:3