【C Primer Plus第六版 学习笔记】第十四章 结构和其他数据形式

有基础,进阶用,个人查漏补缺

  1. 建立结构声明:描述该对象由什么组成,即结构布局

    格式:

    关键字 标记(可选){
    	结构
    };
    举例:
    struct book{
    	char title[2];
    	char author[4];
    	float value;
    };
    
  2. 定义结构变量

    结构布局告诉编译器如何表示数据,但是并未让编译器为数据分配空间。创建结构变量,则编译器会使用上述book模板为该变量分配空间。

    struct book library;
    

    在这里插入图片描述

    结构布局和结构变量合并声明

    struct book{
    	char title[2];
    	char author[4];
    	float value;
    }library;
    
    //也可以这样,但是就无法多次使用该结构进行其他同结构的变量声明了
    struct{
    	char title[2];
    	char author[4];
    	float value;
    }library;
    
  3. 初始化结构

    与初始化数组的语法类似

    struct book library = {
    	"ab",
    	"1234",
    	1.99
    };
    
  4. 访问结构成员

    library.title
    library.author
    library.value
    
  5. 结构的初始化器

    结构的初始化器使用点运算符和成员名标识特定元素

    //只初始化book结构和value成员
    struct book surprise = {.value = 10.99};
    
    //可以按照任意顺序使用指定初始化器
    struct book surprise = {.value = 10.99,
    												.author = "ab",
    												.title = "abds"};
    
    //此外
    struct book surprise = {.value = 10.99,
    												.author = "ab",
    												25};//赋给value的值是25,取代了10.99
    
  6. 嵌套结构

    #include <stdio.h>
    struct names {              //第一个结构
    	char first[20];
    	char last[20];
    };
    
    struct guy{                 //第二个结构
    	struct names handle;
    	char job[20];
    	float age;
    };
    
    int main(void)
    {
    	struct guy fellow = {
    		{"Ewen", "Villard"},
    		"coach",
    		25
    	};
    	
    	printf("Dear %s", fellow.handle.first);
    	return 0;
    }
    /*输出:
    Dear Ewen
    
  7. 指向结构的指针

    地址的就使用“→”,标识符的就使用“.”

    #include <stdio.h>
    struct names {              //第一个结构
    	char first[20]; //占用20字节内存
    	char last[20];  //占用20字节内存
    };
    
    struct guy{                 //第二个结构
    	struct names handle;
    	char job[20];     //占用20字节内存
    	char favfood[20]; //占用20字节内存
    	float age;        //占用4字节内存
    };
    
    int main(void)
    {
    	struct guy fellow[2] = {
    		{{"Ewen", "Villard"},
    		"coach",
    		"apple",
    		25
    		},
    		{{"Rob", "Swill"},
    		"editor",
    		"banana",
    		30
    		}
    	};
    	
    	struct guy * him;       //声明指向结构的指针
    /*或者有一个guy类型的结构barney,也可以him = &barney*/
    
    	printf("address #1: %p #2: %p\n", &fellow[0], &fellow[1]);
    	him = &fellow[0];      //告诉编译器该指针指向何处
    	printf("pointer #1: %p #2: %p\n", him, him+1);
    
    	//两种访问方式
    	printf("him->age is %.f; (*him).age is %.f\n", 
    					him->age, (*him).age);**//必须要是用圆括号,因为运算符.比*优先级高!!**
    	
    	him++;
    	printf("him->job is %.s; him->handle.last is %.s\n", 
    					him->job, him->handle.last);
    	return 0;
    }
    /*输出:
    address #1: 0x7fff5fbff820 #2: 0x7fff5fbff874  //相差54(十六进制,十进制为84),
    pointer #1: 0x7fff5fbff820 #2: 0x7fff5fbff874  //说明每个guy结构相差84字节内存
    him->age is 25; (*him).age is 25
    him->job is editor; him->handle.last is Swill
    
  8. 向函数传递结构的信息

    #include <stdio.h>
    #define FUNDLEN 50
    struct funds {
        char   bank[FUNDLEN];
        double bankfund;
        char   save[FUNDLEN];
        double savefund;
    };
    
    double sum1(double, double);       /* 1. 传递结构成员 */
    double sum2(const struct funds *); /* 2. 传递结构地址 */
    double sum3(struct funds moolah);  /* 3. 传递结构    */
    
    int main(void)
    {
        struct funds stan = {
            "Garlic-Melon Bank",
            4032.27,
            "Lucky's Savings and Loan",
            8543.94
        };
    	
    		/*均输出:Stan has a total of $12576.21.*/
    
        /* 1. 传递结构成员 */
        printf("Stan has a total of $%.2f.\n",
               sum1(stan.bankfund, stan.savefund) );
    		
    		/* 2. 传递结构地址 */
    		printf("Stan has a total of $%.2f.\n", sum2(&stan));
    
    		/* 3. 传递结构    */
    		printf("Stan has a total of $%.2f.\n", sum3(stan));
    
        return 0;
    }
    /* 1. 传递结构成员 */
    double sum1(double x, double y)
    {
        return(x + y);
    }
    /* 2. 传递结构地址 */
    double sum2(const struct funds * money)
    {
        return(money->bankfund + money->savefund);
    }
    /* 3. 传递结构    */
    double sum(struct funds moolah)
    {
        return(moolah.bankfund + moolah.savefund);
    }
    
  9. 结构和结构指针的选择

    1. 结构:
      1. 优点:①函数处理的是原始数据的副本,保护了原始数据;②代码风格更清楚
      2. 缺点:①老版本可能无法实现;②传递结构浪费时间和存储空间
    2. 指针结构:
      1. 优点:①任何C语言版本都可使用;②执行快,只需要传递一个地址
      2. 缺点:无法保护数据,但const解决了这个问题
    3. 通常,为了追求效率会使用指针结构作为函数参数,如果需要防止原始数据被意外修改,使用const限定符。处理小型结构最常用按值传递。
  10. 结构中的字符数组和字符指针

    struct names {
    	char first[20];
    	char last[20];
    };
    struct pnames {
    	char * first;
    	char * last;
    };
    
    /*以下三行代码没问题,但veep字符串均储存在结构内部,总共要分配40字节存储姓名,
    而treas的字符串储存在编译器储存常量的地方,结构本身只储存了两个地址,只占用16字节*/
    struct names veep = {"Taila", "Summers"};
    struct pnames treas = {"Brad", "Falling"};
    printf("%s and %s\n", veep.first, treas.first);
    
    /*就语法而言,没有问题*/
    /*对于会计师,其名字被储存在accountant结构变量的last成员中,该结构有一个储存字符串的数组*/
    /*对于律师,scanf()把字符串放到attorney.last表示的地址上,
    但这是未经初始化的变量,地址可以是任意值,程序可以把名放在任何地方,可能会导致程序崩溃*/
    struct names accountant;
    struct pnames attorney;
    scanf("%s", accountant.last);
    scanf("%s", attorney.last);
    
  11. 结构、指针、malloc()

    使用malloc()分配内存并使用指针储存该地址,会使得在结构中使用指针处理字符串比较合理。该方法优点是可以请求malloc()为字符串分配合适的存储空间。

  12. 复合字面量和结构(C99)

    C99的复合字面量特性可用于结构和数组

    #include <stdio.h>
    #define MAXTITL  41
    #define MAXAUTL  31
    
    struct book {          // 结构模板:标记是book
        char title[MAXTITL];
        char author[MAXAUTL];
        float value;
    };
    
    int main(void)
    {
        struct book readfirst;
        int score;
        
        printf("Enter test score: ");
        scanf("%d",&score);
        
        if(score >= 84)
            readfirst = (struct book) {"Crime and Punishment",
                "Fyodor Dostoyevsky",
                11.25};
        else
            readfirst = (struct book) {"Mr. Bouncy's Nice Hat",
                "Fred Winsome",
                5.99};
        printf("Your assigned reading:\n");
        printf("%s by %s: $%.2f\n",readfirst.title,
               readfirst.author, readfirst.value);
        
        return 0;
    }
    
  13. 伸缩型数组成员(C99)

    有两个特性:

    1. 该数组不会立刻存在
    2. 好像它确实存在并具有所需数目的元素一样

    声明伸缩型数组成员的规则:

    1. 伸缩型数组成员必须是结构的最后一个成员
    2. 结构中必须至少有一个成员
    3. 伸缩数组的声明类似普通数组,但其方括号中是空的
    struct flex {
    	int count;
    	double average;
    	double scores[];//伸缩型数组成员
    };
    /*声明一个struct flex类型变量时,不能用scores做任何事,因为没有给这个数组预留存储空间
    C99希望你声明一个指向struct flex类型的指针,然后用malloc()来分配足够的空间,
    以储存struct flex类型结构的常规内容和伸缩型数组成员所需的额外空间
    */
    struct flex * pf;
    pf = malloc(sizeof(struct flex) + 5 * sizeof(double));
    pf->count = 5;
    pf->scores[2] = 18.5;
    
  14. 匿名结构(C11)

    //嵌套结构
    struct names {
    	char first[20];
    	char last[20];
    };
    struct person {
    	int id;
    	struct names name;//嵌套结构成员
    };
    
    //在C11中,可以用嵌套的匿名成员结构定义person
    struct person {
    	int id;
    	struct {char first[20];	char last[20];};//匿名结构
    };
    
  15. 联合(union)

    1. 联合(union)是一种数据类型,能在同一个内存空间中储存不同的数据类型(非同时储存)。就是把没有规律、事先不知道顺序的数据类型放在一个结构中

      //该结构可以储存一个int类型,一个double类型和char类型的值
      union hold{
      	int a;
      	double b;
      	char c;
      };
      
      union hold A;
      A.a = 1;
      union hold A = B;//可以用另一个联合来初始化,也可以用指定初始化器
      
  16. 枚举类型(enum)

    可以使用枚举类型声明符号名称来表示整型变量。使用enum关键字,创建新“类型”并指定它可具有的值。实际上,enum常量是int类型,因此,只要能使用int类型的地方就可以使用枚举类型。枚举类型的目的是提高程序的可读性。

    //第一个声明创建spectrum作为标记名,允许把enum spectrum作为一个类型名使用
    enum spectrum {red, orange, yellow, green, blue, violet};
    //第二个声明color作为该类型的变量。
    enum spectrum color;
    //第一个声明中花括号内的标识符枚举了spectrum变量可能有的值,
    //因此color可能的值是red、orange、yellow、green、blue、violet,这些red等被称为枚举符
    color = blue;
    if(color == yellow)
    	···;
    for(color = red; color <= violet; color++)
    	···;
    

    虽然枚举符(如red等)是int类型,但是枚举符可以是任意整型变量。此处的spectrum的枚举范围是0~5,所以编译器可以用unsigned char来表示color变量。

    printf("red = %d, orange = %d\n", red, orange);
    /*输出:
    red = 0, orange = 1
    

    默认情况下,枚举列表中的常量都被赋予0、1、2等。

    在switch语句中,可以把枚举常量作为标签。

    赋值:

    enum levels {low = 100, medium = 500, high = 2000};
    enum feline {cat, lynx = 10, ouma, tiger};
    //cat的值为0(默认),lynx,ouma,tiger分别为**10,11,12**
    
  17. typedef

    利用typedef可以为某一类型自定义名称,由编译器解释,不是预处理器

    typedef unsigned char byte;//也可以用大写BYTE,遵循变量的命名规则即可
    byte x, y[10], *z;//该定义的作用域取决于typedef定义所在的位置
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值