第 14 章 结构和其他数据形式

一、结构(struct)

结构类似于 java 中的类,只不过它只有属性,没有方法

1.1 定义、声明、初始化结构,访问结构成员

#include <stdio.h>
#define	SIZE 20

//定义结构
struct book
{
	char name[SIZE];
	char author[SIZE];
	double price;
};

int main(void)
{
    //声明结构
	struct book book_b;
	struct book book_c;

	//声明结构同时初始化
	struct book book_a = {
		"C Primer Plus",
		"Stephen Prata",
		60
	};

	//使用初始化器初始化,这种方式会指定的成员初始化,其他成员使用默认值
	struct book book_d = {
		.author = "d"
	};		

	//使用访问结构成员的方式进行初始化,这种方式初始化会导致如果访问未被初始化的属性发生内存泄漏
	gets_s(book_c.name, SIZE);
	gets_s(book_c.author, SIZE);
	book_c.price = 50;

	//把一个结构初始化为另一个结构
	book_b = (struct book){
		"b",
		"B",
		60
	};

	printf("book_a: \n");
	printf("name: %s, author: %s, price: %.2f", book_a.name, book_a.author, 		book_a.price);
	printf("\n--------------------------------\n");

	printf("book_b: \n");
	printf("name: %s, author: %s, price: %.2f", book_b.name, book_b.author,           book_b.price);
	printf("\n--------------------------------\n");

	printf("book_c: \n");
	printf("name: %s, author: %s, price: %.2f", book_c.name, book_c.author, book_c.price);
	printf("\n--------------------------------\n");

	printf("book_d: \n");
	printf("name: %s, author: %s, price: %.2f", book_d.name, book_d.author, book_d.price);
	printf("\n--------------------------------\n");

	getchar();

}

/*运行结果
c
C
book_a:
name: C Primer Plus, author: Stephen Prata, price: 60.00
--------------------------------
book_b:
name: b, author: B, price: 60.00
--------------------------------
book_c:
name: c, author: C, price: 50.00
--------------------------------
book_d:
name: , author: d, price: 0.00
--------------------------------
*/

代码详解:

​ 结构有两层含义。一层含义是 ”结构布局“,结构布局告诉编译器如何表示数据,但是它并未让编译器为数据分配空间。另一层含义是结构变量,创建一个结构变量:

​ struct book book_a;

​ 编译器执行这行代码便创建了一个结构变量 book_a。编译器使用 book 模板为该变量分配空间:两个内含 SIZE个元素的 char 数组和一个 double 类型的变量。

1.5 结构数组

结构数组就是一个数组里面存储的是结构。

​ 例:

#include <stdio.h>
#define SIZE 20

struct book
{
        char name[SIZE];
        char author[SIZE];
        double price;
};

int main(void)
{
        int i;
    	//创建结构数组
        struct book books[SIZE] =
        {
                {"aa", "AA", 20.5},
                {"bb", "BB", 30},
                {"cc", "CC", 40}
        };

    	//输出数组
        printf("%15s %15s %15s\n", "name", "autor", "price");
        for(i = 0; i < 3;  i++)
                printf("%15s %15s %13.2f\n", books[i].name, books[i].author, 	 books[i].price);

        return 0;
}
/*运行结果
 name           autor           price
 aa              AA         20.50
 bb              BB         30.00
 cc              CC         40.00
 */

1.6 指向结构的指针

​ 本例演示了两种方法:

​ Ⅰ. 将指针指向一个已经声明的结构

​ Ⅱ. 使用 malloc 为指针分配空间

例1:

#include <stdio.h>
#define SIZE 20

struct book
{
        char name[SIZE];
        char author[SIZE];
        double price;
};


int main(void)
{
        struct book book_a ={
                "C Primer Plus",
                "Stephen Prata",
                60
        };
        //声明结构指针
        struct book * book_ptr_a;
        struct book * book_ptr_b;

        //指针指向 book_a
        book_ptr_a = &book_a;
		//输出
        printf("%15s %15s %15s\n", "name", "autor", "price");
        printf("%15s %15s %13.2f\n", book_ptr_a->name, book_ptr_a->author, book_ptr_a->price);
        return 0;
}
/*结果
name           autor           price
C Primer Plus   Stephen Prata         60.00
*/

例2:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 20

struct book
{
        char name[SIZE];
        char author[SIZE];
        double price;
};

int main(void)
{
        struct book* book_ptr_b;
        double* p = (double *) malloc(5 * sizeof(double));
        //使用 malloc 分配空间
        book_ptr_b = (struct book*) malloc(sizeof(struct book));
        //设置属性
        scanf("%s%s", book_ptr_b->name, book_ptr_b->author);
        book_ptr_b->price = 50;
              
        printf("%15s %15s %15s\n", "name", "autor", "price");
        printf("%15s %15s %13.2f\n", book_ptr_b->name, book_ptr_b->author, book_ptr_b->price);
    	//malloc 分配的空间不会自动释放,养成好的编程习惯,要使用 free 释放空间
    	free(p);

        return 0;
}
/*运行结果
bb cc
name           autor           price
bb              cc         50.00
*/

例3:伸缩性数组成员,就是结构中的数组在定义时并未初始化

#include <stdio.h>
#include <stdlib.h>

struct class
{
        int grade;
        int stdunts[];  //stdunts的长度未指定
};

int main(void)
{
    	//声明并初始化一个 students 的长度未5 的结构 class
        struct class * c = (struct class *) malloc(sizeof(struct class) + 5 * sizeof(int));
    	
    	free(c);

        return 0;
}

1.7 向函数传递结构的信息

​ 可以传递三种信息:

Ⅰ. 传递结构成员

Ⅱ. 传递结构指针(按地址传递)

Ⅲ. 传递一个结构(按值传递)

1.8 使用 malloc() 为结构中的指针成员分配内存

例:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 20

struct book
{
        char * name;	//name 是一个指针,它存储字符串的地址
        char * author;
        double price;
};

int main(void)
{
        //声明一个 book 结构
        struct book mybook;

        //分配 name 指向的内存  
        mybook.name = (char *) malloc(SIZE);
        //分配 author 指向的内存        
        mybook.author= (char *) malloc(SIZE);

        //为 name 指向的内存设置一个值
        scanf("%s %s", mybook.name, mybook.author);

        //输出值
        printf("%s, %s\n", mybook.name, mybook.author);
        return 0;
}
/*运行结果
aaa AAA(输入)
aaa, AAA (输出)
*/

1.10 把结构保存到文件中

/*fwrite 把结构保存到文件中,注:保存到文件中的是二进制格式*/
#include <stdio.h>
#define SIZE 20

//定义结构体
struct book
{
        char name[SIZE];
        char author[SIZE];
        double price;
};

int main(void)
{
        FILE *bookfile;
        int i;
        //定义一个结构数组
        struct book books[3] = {
                {"aa", "AA", 20},
                {"bb", "BB", 30},
                {"cc", "CC", 40}
        };

        bookfile = fopen("books", "wb");
        fwrite(books, sizeof(struct book), 3, bookfile);        //把数组中内容写到 bookfile 文件中

        fclose(bookfile);

        return 0;
}
/*使用 fread() 从文件中读取结构*/
#include <stdio.h>
#define SIZE 20

//定义一个结构体
struct book
{
        char name[SIZE];
        char author[SIZE];
        double price;
};

int main(void)
{
        int i;
        FILE *bookfile;         //文件指针
        struct book books[3];   //结构数组

        bookfile = fopen("books", "rb");        //打开books
        fread(books, sizeof(struct book), 3, bookfile); //把文件中的内容读到结构数组中 

        //输出
        printf("books: \n");
        for(i = 0; i < 3; i++)
                printf("name: %s, author: %s, price: %.2f\n", books[i].name, books[i].author, books[i].price);

        return 0;
}
/*结果:
books: 
name: aa, author: AA, price: 20.00
name: bb, author: BB, price: 30.00
name: cc, author: CC, price: 40.00
*/

二、联合(union)

联合是一种数据类型,它能在同一个内存空间中存储不同的数据类型(不是同时存储)。

2.1 使用联合

例:

#include <stdio.h>

//定义一个联合
union data {
        int a;
        double b;
};

int main(void)
{
        //声明联合
        union data a = {88};            //初始化联合成员
        union data b = {.b = 55.5};     //使用初始化器初始化元素 b
        union data c;

        //查看数据
        printf("union a: \n");
        printf("a = %d, b = %.2f\n", a.a, a.b);

        printf("union b: \n");
        printf("a = %d, b = %.2f\n", b.a, b.b);

        printf("union c: \n");
        c.a = 1;
        printf("before set b, a = %d, b = %.2f \n", c.a, c.b);
        c.b = 2;
        printf("after set b, a = %d, b = %.2f \n", c.a, c.b);

        //查看联合大小
    	printf("--------------------------------\n");
        printf("size of union: %zd\n", sizeof(union data));

        return 0;
}
/*运行结果
union a: 
a = 88, b = 0.00
union b: 
a = 0, b = 55.50
union c: 
before set b, a = 1, b = 0.00 
after set b, a = 0, b = 2.00 
--------------------------------
size of union: 8
*/

分析结果:

​ 实验结果符合定义,联合只能存储一个变量,其他变量是默认值。联合所占的空间大小是最大的一个数据类型所占的空间。

三、枚举(enum)

可以用枚举类型(enmuerated type)声明符号名称来表示整型常量。枚举类型的目的是提高程序的可读性。

​ 例:

#include <stdio.h>

enum spectrum { red, orange, yellow, green, blue, violet};
int main(void)
{
        enum spectrum color;
		
    	//查看枚举的值
        printf("red = %d, orange = %d, yellow = %d, green = %d, blue = %d, violet = %d\n", red, orange, yellow, green, blue, violet);

        color = 1;      //使用整形常量给 color 赋值
        switch(color)
        {
                case 0: printf("I'm red\n");
                        break;
                case orange: printf("I'm orange\n");    //使用枚举来接受整形常量
                             break;

                default: printf("I'm others");
                         break;
        }

        return 0;
}
/*运行结果
red = 0, orange = 1, yellow = 2, green = 3, blue = 4, violet = 5
I'm orange
*/

四、函数指针

普通变量有地址,函数也有地址。指向函数的指针中存储着函数代码起始的地址,函数指针主要的用法就是把函数作为另一个函数的参数。

​ 声明函数指针如同声明函数一样,也要指定名称,参数,返回值类型。

​ 例:void (*pf) (char *)

例1:

/*练习声明、使用函数指针*/
#include <stdio.h>

void (*pf) (char *); //声明一个函数指针
void show(char *);      //声明一个函数,用函数指针指向它

int main(void)
{
        pf = show;

        //ANSI 认为这两种方法等价
        pf("I'm 'pf'");
        (*pf)("I'm '*pf'");

        return 0;
}

void show(char * str)
{
        printf("%s\n", str);

        return;
}
/*运行结果
I'm 'pf'
I'm '*pf'
*/

例2:

#include <stdio.h>

void (*pf) (char *); //声明一个函数指针
void show(char *);      //声明一个函数,用函数指针指向它
void usePf (void (*pf)(char *), char *, int choice);    //声明一个函数,它的参数是一个函数参数为 char* 的函数指针、一个 char* 、一个 int 值

int main(void)
{
        pf = show;
        int choice;
        char str[20];

        //写一个死循环接受用户选择,当输入的不是数字则停止
        printf("enter your choice: ");
        while(scanf("%d", &choice) == 1)
        {
                printf("enter a string: ");
                scanf("%s", str);

                usePf(pf, str, choice);         //调用 usePf
                printf("enter your choice: ");
        }


        return 0;
}

void show(char * str)
{
        printf("%s\n", str);

        return;
}

void usePf(void (*pf)(char *), char * str, int choice)
{
        switch(choice)
        {
                case 1: printf("No.1, ");
                        break;

                case 2: printf("No.2, ");
                        break;

                case 3: printf("No.3, ");
                        break;
        }

        pf(str);        //使用函数指针来调用 show 函数
}
/*运行结果
enter your choice: 1
enter a string: hello
No.1, hello
enter your choice: 2
enter a string: chi
No.2, chi
enter your choice: 3
enter a string: hh
No.3, hh
*/

参考书籍

C Primer Plus (第六版)中文版

发布了42 篇原创文章 · 获赞 3 · 访问量 2083

猜你喜欢

转载自blog.csdn.net/stable_zl/article/details/104147986
今日推荐