C enum(枚举)

枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。

枚举语法定义格式为:

enum 枚举名 {枚举元素1,枚举元素2,……};

接下来我们举个例子,比如:一星期有 7 天,如果不用枚举,我们需要使用 #define 来为每个整数定义一个别名:

#define MON  1
#define TUE  2
#define WED  3
#define THU  4
#define FRI  5
#define SAT  6
#define SUN  7

 这个看起来代码量就比较多,接下来我们看看使用枚举的方式:

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

这样看起来是不是更简洁了。

注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。

枚举变量的定义

前面我们只是声明了枚举类型,接下来我们看看如何定义枚举变量。

我们可以通过以下三种方式来定义枚举变量

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

1 enum DAY
2 {
3       MON=1, TUE, WED, THU, FRI, SAT, SUN
4 };
5 enum DAY day;

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

1 enum DAY
2 {
3       MON=1, TUE, WED, THU, FRI, SAT, SUN
4 } day;

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

1 enum
2 {
3       MON=1, TUE, WED, THU, FRI, SAT, SUN
4 } day;

【示例】

1 #include<stdio.h>
 2  
 3 enum DAY
 4 {
 5       MON=1, TUE, WED, THU, FRI, SAT, SUN
 6 };
 7  
 8 int main()
 9 {
10     enum DAY day;
11     day = WED;
12     printf("%d",day);
13     return 0;
14 }

执行结果:

3

在C 语言中,枚举类型是被当做 int 或者 unsigned int 类型来处理的,所以按照 C 语言规范是没有办法遍历枚举类型的。

不过在一些特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。

以下实例使用 for 来遍历枚举的元素:

1 #include<stdio.h>
 2  
 3 enum DAY
 4 {
 5       MON=1, TUE, WED, THU, FRI, SAT, SUN
 6 } day;
 7 int main()
 8 {
 9     // 遍历枚举元素
10     for (day = MON; day <= SUN; day++) {
11         printf("枚举元素:%d \n", day);
12     }
13 }

执行结果:

1 枚举元素:1 
2 枚举元素:2 
3 枚举元素:3 
4 枚举元素:4 
5 枚举元素:5 
6 枚举元素:6 
7 枚举元素:7

以下枚举类型不连续,这种枚举无法遍历。

1 enum
2 {
3     ENUM_0,
4     ENUM_10 = 10,
5     ENUM_11
6 };

将整数转换为枚举

以下实例将整数转换为枚举:

1 #include <stdio.h>
 2 #include <stdlib.h>
 3  
 4 int main()
 5 {
 6  
 7     enum day
 8     {
 9         saturday,
10         sunday,
11         monday,
12         tuesday,
13         wednesday,
14         thursday,
15         friday
16     } workday;
17  
18     int a = 1;
19     enum day weekend;
20     weekend = ( enum day ) a;  //类型转换
21     //weekend = a; //错误
22     printf("weekend:%d",weekend);
23     return 0;
24 }

执行结果:

weekend:1

C 字符串

在 C 语言中,字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

下面的声明和初始化创建了一个 "Hello" 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "Hello" 的字符数多一个。

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

依据数组初始化规则,您可以把上面的语句写成以下语句:

char greeting[] = "Hello";

其实,您不需要把 null 字符放在字符串常量的末尾。C 编译器会在初始化数组时,自动把 '\0' 放在字符串的末尾。让我们尝试输出上面的字符串:

1 #include <stdio.h>
 2 
 3 int main ()
 4 {
 5    char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
 6 
 7    printf("Greeting message: %s\n", greeting );
 8 
 9    return 0;
10 }

执行结果:

Greeting message: Hello

C 中有大量操作字符串的函数:

序号

函数 & 目的

1

strcpy(s1, s2);

复制字符串 s2 到字符串 s1。

2

strcat(s1, s2);

连接字符串 s2 到字符串 s1 的末尾。

3

strlen(s1);

返回字符串 s1 的长度。

4

strcmp(s1, s2);

如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。

5

strchr(s1, ch);

返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。

6

strstr(s1, s2);

返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

 【示例】

1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 int main ()
 5 {
 6    char str1[12] = "Hello";
 7    char str2[12] = "World";
 8    char str3[12];
 9    int  len ;
10  
11    /* 复制 str1 到 str3 */
12    strcpy(str3, str1);
13    printf("strcpy( str3, str1) :  %s\n", str3 );
14  
15    /* 连接 str1 和 str2 */
16    strcat( str1, str2);
17    printf("strcat( str1, str2):   %s\n", str1 );
18  
19    /* 连接后,str1 的总长度 */
20    len = strlen(str1);
21    printf("strlen(str1) :  %d\n", len );
22  
23    return 0;
24 }

执行结果:

strcpy( str3, str1) :  Hello
strcat( str1, str2):   HelloWorld
strlen(str1) :  10

C 结构体

C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。

结构用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性:

  • Title
  • Author
  • Subject
  • Book ID

定义结构

为了定义结构,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

1 struct tag { 
2     member-list
3     member-list 
4     member-list  
5     ...
6 } variable-list ;

tag 是结构体标签。

member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。

variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。下面是声明 Book 结构的方式:

1 truct Books
2 {
3    char  title[50];
4    char  author[50];
5    char  subject[100];
6    int   book_id;
7 } book;

结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。

1 //此结构体的声明包含了其他的结构体
 2 struct COMPLEX
 3 {
 4     char string[100];
 5     struct SIMPLE a;
 6 };
 7  
 8 //此结构体的声明包含了指向自己类型的指针
 9 struct NODE
10 {
11     char string[100];
12     struct NODE *next_node;
13 };

如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明,如下所示:

1 struct B;    //对结构体B进行不完整声明
2  
3 //结构体A中包含指向结构体B的指针
4 struct A
5 {
6     struct B *partner;
7     //other members;
8 };

//结构体B中包含指向结构体A的指针,在A声明完后,B也随之进行声明 struct B { struct A *partner; //other members; };

访问结构成员

为了访问结构的成员,我们使用成员访问运算符(.)。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号。您可以使用 struct 关键字来定义结构类型的变量。下面的实例演示了结构的用法:

1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 struct Books
 5 {
 6    char  title[50];
 7    char  author[50];
 8    char  subject[100];
 9    int   book_id;
10 };
11  
12 int main( )
13 {
14    struct Books Book1;        /* 声明 Book1,类型为 Books */
15    struct Books Book2;        /* 声明 Book2,类型为 Books */
16  
17    /* Book1 详述 */
18    strcpy( Book1.title, "C Programming");
19    strcpy( Book1.author, "Nuha Ali"); 
20    strcpy( Book1.subject, "C Programming Tutorial");
21    Book1.book_id = 6495407;
22  
23    /* Book2 详述 */
24    strcpy( Book2.title, "Telecom Billing");
25    strcpy( Book2.author, "Zara Ali");
26    strcpy( Book2.subject, "Telecom Billing Tutorial");
27    Book2.book_id = 6495700;
28  
29    /* 输出 Book1 信息 */
30    printf( "Book 1 title : %s\n", Book1.title);
31    printf( "Book 1 author : %s\n", Book1.author);
32    printf( "Book 1 subject : %s\n", Book1.subject);
33    printf( "Book 1 book_id : %d\n", Book1.book_id);
34  
35    /* 输出 Book2 信息 */
36    printf( "Book 2 title : %s\n", Book2.title);
37    printf( "Book 2 author : %s\n", Book2.author);
38    printf( "Book 2 subject : %s\n", Book2.subject);
39    printf( "Book 2 book_id : %d\n", Book2.book_id);
40  
41    return 0;
42 }

指向结构的指针

您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,如下所示:

struct Books *struct_pointer;

现在,您可以在上述定义的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构名称的前面,如下所示:

struct_pointer = &Book1;

为了使用指向该结构的指针访问结构的成员,您必须使用 -> 运算符,如下所示:

struct_pointer->title;

 【示例】

1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 struct Books
 5 {
 6    char  title[50];
 7    char  author[50];
 8    char  subject[100];
 9    int   book_id;
10 };
11  
12 /* 函数声明 */
13 void printBook( struct Books *book );
14 int main( )
15 {
16    struct Books Book1;        /* 声明 Book1,类型为 Books */
17    struct Books Book2;        /* 声明 Book2,类型为 Books */
18  
19    /* Book1 详述 */
20    strcpy( Book1.title, "C Programming");
21    strcpy( Book1.author, "Nuha Ali"); 
22    strcpy( Book1.subject, "C Programming Tutorial");
23    Book1.book_id = 6495407;
24  
25    /* Book2 详述 */
26    strcpy( Book2.title, "Telecom Billing");
27    strcpy( Book2.author, "Zara Ali");
28    strcpy( Book2.subject, "Telecom Billing Tutorial");
29    Book2.book_id = 6495700;
30  
31    /* 通过传 Book1 的地址来输出 Book1 信息 */
32    printBook( &Book1 );
33  
34    /* 通过传 Book2 的地址来输出 Book2 信息 */
35    printBook( &Book2 );
36  
37    return 0;
38 }
39 void printBook( struct Books *book )
40 {
41    printf( "Book title : %s\n", book->title);
42    printf( "Book author : %s\n", book->author);
43    printf( "Book subject : %s\n", book->subject);
44    printf( "Book book_id : %d\n", book->book_id);
45 }

C 共用体

共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。

定义共用体

为了定义共用体,您必须使用 union 语句,方式与定义结构类似。union 语句定义了一个新的数据类型,带有多个成员。union 语句的格式如下:

1 union [union tag]
2 {
3    member definition;
4    member definition;
5    ...
6    member definition;
7 } [one or more union variables];

union tag 是可选的,每个 member definition 是标准的变量定义,比如 int i; 或者 float f; 或者其他有效的变量定义。在共用体定义的末尾,最后一个分号之前,您可以指定一个或多个共用体变量,这是可选的。下面定义一个名为 Data 的共用体类型,有三个成员 i、f 和 str:

1 union Data
2 {
3    int i;
4    float f;
5    char  str[20];
6 } data;

现在,Data 类型的变量可以存储一个整数、一个浮点数,或者一个字符串。这意味着一个变量(相同的内存位置)可以存储多个多种类型的数据。您可以根据需要在一个共用体内使用任何内置的或者用户自定义的数据类型。

共用体占用的内存应足够存储共用体中最大的成员。例如,在上面的实例中,Data 将占用 20 个字节的内存空间,因为在各个成员中,字符串所占用的空间是最大的。下面的实例将显示上面的共用体占用的总内存大小:

1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 union Data
 5 {
 6    int i;
 7    float f;
 8    char  str[20];
 9 };
10  
11 int main( )
12 {
13    union Data data;        
14  
15    printf( "Memory size occupied by data : %d\n", sizeof(data));
16  
17    return 0;
18 }

执行结果:

Memory size occupied by data : 20

访问共用体成员

为了访问共用体的成员,我们使用成员访问运算符(.)。成员访问运算符是共用体变量名称和我们要访问的共用体成员之间的一个句号。您可以使用 union 关键字来定义共用体类型的变量。下面的实例演示了共用体的用法:

1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 union Data
 5 {
 6    int i;
 7    float f;
 8    char  str[20];
 9 };
10  
11 int main( )
12 {
13    union Data data;        
14  
15    data.i = 10;
16    data.f = 220.5;
17    strcpy( data.str, "C Programming");
18  
19    printf( "data.i : %d\n", data.i);
20    printf( "data.f : %f\n", data.f);
21    printf( "data.str : %s\n", data.str);
22  
23    return 0;
24 }

执行结果:

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

在这里,我们可以看到共用体的 if 成员的值有损坏,因为最后赋给变量的值占用了内存位置,这也是 str 成员能够完好输出的原因。现在让我们再来看一个相同的实例,这次我们在同一时间只使用一个变量,这也演示了使用共用体的主要目的: 

1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 union Data
 5 {
 6    int i;
 7    float f;
 8    char  str[20];
 9 };
10  
11 int main( )
12 {
13    union Data data;        
14  
15    data.i = 10;
16    printf( "data.i : %d\n", data.i);
17    
18    data.f = 220.5;
19    printf( "data.f : %f\n", data.f);
20    
21    strcpy( data.str, "C Programming");
22    printf( "data.str : %s\n", data.str);
23  
24    return 0;
25 }

执行结果:

data.i : 10
data.f : 220.500000
data.str : C Programming