结构_结构体 - CSDN
精华内容
参与话题
  • C语言中的结构体(struct)

    万次阅读 多人点赞 2016-02-15 20:23:39
    C语言中,结构体类型属于一种构造类型(其他的构造类型还有:数组类型,联合类型)。本文主要介绍关于结构体以下几部分。 1、概念为什么要有结构体?因为在实际问题中,一组数据往往有很多种不同的数据类型。...

    C语言中,结构体类型属于一种构造类型(其他的构造类型还有:数组类型,联合类型)。本文主要介绍关于结构体以下几部分。
    这里写图片描述

    1、概念

    为什么要有结构体?

    因为在实际问题中,一组数据往往有很多种不同的数据类型。例如,登记学生的信息,可能需要用到 char型的姓名,int型或 char型的学号,int型的年龄,char型的性别,float型的成绩。又例如,对于记录一本书,需要 char型的书名,char型的作者名,float型的价格。在这些情况下,使用简单的基本数据类型甚至是数组都是很困难的。而结构体(类似Pascal中的“记录”),则可以有效的解决这个问题。
    结构体本质上还是一种数据类型,但它可以包括若干个“成员”,每个成员的类型可以相同也可以不同,也可以是基本数据类型或者又是一个构造类型。
    结构体的优点:结构体不仅可以记录不同类型的数据,而且使得数据结构是“高内聚,低耦合”的,更利于程序的阅读理解和移植,而且结构体的存储方式可以提高CPU对内存的访问速度。

    结构声明(structure declaration)

    结构声明(也见有称做定义一个结构体)是描述结构如何组合的主要方法。
    一般形式是:
    struct 结构名{
    成员列表
    };
    struct关键词表示接下来是一个结构。
    如声明一个学生的结构:

    struct Student{         //声明结构体
        char name[20];      //姓名
        int num;            //学号
        float score;        //成绩
    };

    上面的声明描述了一个包含三个不同类型的成员的结构,但它还没创建一个实际的数据对象,类似C++中的模板。每个成员变量都用自己的声明来描述,以分号结束。花括号之后的分号表示结构声明结束。结构声明可以放在函数外(此时为全局结构体,类似全局变量,在它之后声明的所有函数都可以使用),也可以放在函数内(此时为局部结构体,类似局部变量,只能放在该函数内使用,如果与全局结构体同名,则会暂时屏蔽全局结构体)。

    要定义结构变量,则一般形式是:
    struct 结构体名 结构体变量名;
    如:

    struct Student stu1;    //定义结构体变量

    这里写图片描述
    1)、结构体变量的定义可以放在结构体的声明之后:

    struct Student{         //声明结构体
        char name[20];      //姓名
        int num;            //学号
        float score;        //成绩
    };
    struct Student stu1;    //定义结构体变量

    2)、结构体变量的定义也可以与结构体的声明同时,这样就简化了代码:

    struct Student{        
        char name[20];       
        int num;             
        float score;         
    }stu1;                  //在定义之后跟变量名

    3)、还可以使用匿名结构体来定义结构体变量:

    struct {                //没有结构名
        char name[20];       
        int num;            
        float score;         
    }stu1;  
    

    但要注意的是这样的方式虽然简单,但不能再次定义新的结构体变量了。

    访问结构成员

    虽然结构类似一个数组,只是数组元素的数据类型是相同的,而结构中元素的数据类型是可以不同的。但结构不能像数组那样使用下标去访问其中的各个元素,而应该用结构成员运算符点(.)。即访问成员的一般形式是:
    结构变量名 . 成员名
    如 stu1 . name 表示学生stu1的姓名。

    但如果结构体中的成员又是一个结构体,如:

    struct Birthday{                //声明结构体 Birthday
        int year;
        int month;
        int day;
    };
    struct Student{                 //声明结构体 Student
        char name[20];              
        int num;                    
        float score;                 
        struct Birthday birthday;   //生日
    }stu1;

    则用 stu1.birthday.year 访问出生的年份。

    结构体变量的初始化

    1)、结构体变量的初始化可以放在定义之后:

    可以对结构体的成员逐个赋值:

    struct Student stu1, stu2;      //定义结构体变量
    strcpy(stu1.name, "Jack");
    stu1.num = 18;
    stu1.score = 90.5;

    注意:不能直接给数组名赋值,因为数组名是一个常量。如:

    stu1.name = "Jack"; //…main.c:26:15: Array type 'char [20]' is not assignable

    或者可以对结构体进行整体赋值:

    stu2 = (struct Student){"Tom", 15, 88.0};

    注意:此时要进行强制类型转换,因为数组赋值也是使用{},不转换的话系统无法区分!如:

    int arr[5] = {1, 2, 3, 4, 5};       //数组的初始化
    stu2 = {"Tom", 15, 88.0};           //…main.c:31:12: Expected expression

    2)、结构体变量的初始化也可以与定义同时:

    struct Student{                 //声明结构体 Student
        char name[20];               
        int num;                    
        float score;                 
    }stu = {"Mike", 15, 91};        //注意初始化值的类型和顺序要与结构体声明时成员的类型和顺序一致

    此时不需要强制类型转换
    也可以部分初始化:

    struct Student stu4 = {.name = "Lisa"};

    也可以按照任意的顺序使用指定初始化项目:

        struct Student st = { .name = "Smith",
                              .score = 90.5,
                              .num = 18 };

    3)、可以用一个已经存在的结构体去初始化一个新的相同类型的结构体变量,是整体的拷贝(每一个成员都一一赋值给新的结构体变量),而不是地址赋值。如:

    stu3 = stu1;
    printf("stu1 addr: %p\nstu3 addr: %p\n", &stu1, &stu3);
    printf("stu1.num: %d\nstu3.num: %d\n", stu1.num, stu3.num);
    printf("stu1.num addr: %p\nstu3.num addr: %p\n", &stu1.num, &stu3.num);
    //输出结果:
    stu1 addr: 0x10000104c
    stu3 addr: 0x100001084
    stu1.num: 18
    stu3.num: 18
    stu1.num addr: 0x100001060
    stu3.num addr: 0x100001098

    2、结构体变量的存储原理

    1)结构体数据成员对齐的意义

    内存是以字节为单位编号的,某些硬件平台对特定类型的数据的内存要求从特定的地址开始,如果数据的存放不符合其平台的要求,就会影响到访问效率。所以在内存中各类型的数据按照一定的规则在内存中存放,就是对齐问题。而结构体所占用的内存空间就是每个成员对齐后存放时所占用的字节数之和。
    计算机系统对基本数据类型的数据在内存中存放的限制是:这些数据的起始地址的值要求是某个数K的倍数,这就是内存对齐,而这个数 K 就是该数据类型的对齐模数(alignment modulus)。这样做的目的是为了简化处理器与内存之间传输系统的设计,并且能提升读取数据的速度。
    结构体对齐不仅包括其各成员的内存对齐(即相对结构体的起始位置),还包括结构体的总长度。

    2)结构体大小的计算方法和步骤
    i. 将结构体内所有数据成员的长度值相加,记为 sum_a ;
    ii. 将各数据成员为了内存对齐,按各自对齐模数而填充的字节数累加到sum_a上,记为sum_b。
    对齐模数是 #pragma pack 指定的数值与该数据成员自身长度相比较得到的数值较小者。该数据相对起始位置应该是对齐模数的整数倍。
    iii. 将和 sum_b 向结构体模数对齐。
    该模数则是 #pragma pack 指定的数值与结构体内最大的基本数据类型成员长度相比较得到的数值较小者。结构体的长度应该是该模数的整数倍。

    数据类型自身对齐:
    这里写图片描述
    所谓“对齐在N上”,是指“存放的起始位置是%N = 0”.

    3)在没有#pragma pack宏的情况下:
    例子1:

    这里写图片描述

    内存分配状态为:

    这里写图片描述

    对于结构体的第一个成员 a,起始位置为0x…38 (也为 4 的倍数),所占内存为 0x…38 ~ 0x…3b,共占4个字节;
    对于结构体的第二个成员 b,自身长度为1,对齐模数也为1,所以内存分配可以紧接着a的结尾位置 0x…3b,所以起始位置为 0x…3c,共占1个字节;
    对于结构体的第三个成员 c,自身长度为2,对齐模数也为2,所以起始位置距离a 的起始位置应该是2的倍数,所以 0x…3d处只距离5,不符合要求,所以空着,继续往下找,而在 0x…3e处满足要求,所以可以作为c的起始位置,共占2个字节;
    此时3个成员及其中间空着的位置所占内存单元总和为8,而结构体内最大的基本数据成员是 a,其长度为4,所以结构体模数为 4,而8是4的倍数,满足要求,故不再加内存。

    例子2:
    与例子1相比,三个类型的声明顺序变了:

    这里写图片描述

    内存分配状态为:
    这里写图片描述

    要注意的是,对 a而言,对齐模数为 4,所以当 b的起始位置在0x7f…830之后,0x7f…831、0x7f…832、0x7f…833的位置距离起始位置0x7f…830分别是1,2,3,都不是 4 的倍数,所以那三个位置都空着,直到0x7f…834才满足要求,所以作为 a 的起始位置。当最后 一个成员 c 占的内存末尾在0x7f…839时,所有数据成员及其之间的空位所占内存单元总和为10,而结构体模数为4,10不是4的倍数,所以要扩大到12才满足要求,此时又多了2个空位置,就是0x7f…83a和0x7f…83b。

    例子3:
    当结构体中有数组时:

    这里写图片描述

    内存分配状态为:
    这里写图片描述

    亦即相同类型数据的数组之间多分配的空间会被相邻数组的元素所占用。

    4)在存在#pragma pack宏的情况下:
    方法类似,只是模数可能会按上面说的规则而有所变化。

    这里写图片描述

    内存分配状态为:
    这里写图片描述

    注意,当没有#pragma pack(2)时,成员a要确定自身的q起始位置,是以自身的长度4为对齐模数,但有了#pragma pack(2),则将括号里的2与a的长度4比较,2为较小者,所以以2为a的对齐模数,即地址从0x7f…839往下找到0x7f…83a时,已经距离结构体的起始位置0x7f…838为2,是2的倍数,满足要求(虽然不是4的倍数),可以作为a的起始位置。而最后,所有数据成员及其之间的空位所占内存单元总和为8,因为2和4(结构体中最大的数据成员长度)的较小者为2,而8是2的倍数,所以刚好满足要求,不用在分配空位置,所以结构体总长度即为8。

    3、结构体数组

    结构类型作为一种数据类型,也可以像基本数据类型那样,作为数组的元素的类型。元素属于结构类型的数组成为结构型数组。如开头提出的问题,生活中经常用到结构数组来表示具有相同数据结构的一个群体,如一个班的学生的信息,一个书店或图书馆的书籍信息等。

    1)结构数组定义
    一般格式:
    struct 结构名 {
    成员列表
    } 数组名[数组长度];
    如:

    struct Student{                 //声明结构体 Student
        char name[20];
        int num;
        float score;
    }stu[5];                        //定义一个结构结构数组stu,共有5个元素

    2)结构数组的初始化

    定义结构数组的同时进行初始化

    struct Student stu[2] = {{"Mike", 27, 91},{"Tom", 15, 88.0}};  

    先定义,后初始化
    整体赋值:

    stu[2] = (struct Student){"Jack", 12, 85.0};

    或者将结构体变量的成员逐个赋值:

    strcpy(stu[3].name, "Smith");
    stu[3].num = 18;
    stu[3].score = 90.5;

    输出结构体:

    //结构体数组的长度:
    int length = sizeof(stu) / sizeof(struct Student);
    //逐个输出结构数组的元素
    for (int i = 0; i < length; i++) {
        printf("姓名:%s  学号:%d  成绩:%f \n", stu[i].name, stu[i].num, stu[i].score);
    }

    //输出结果:
    这里写图片描述

    在这个例子中,要注意的是:
    这里写图片描述

    4、结构与指针

    当一个指针变量用来指向了一个结构变量,这个指针就成了结构指针变量。
    结构指针变量中的值是所指向的结构变量的首地址。可以通过指针来访问结构变量。

    1)定义结构指针变量的一般形式:
    struct 结构名 * 结构指针变量名
    如:

    struct Student *pstu;       //定义了一个指针变量,它只能指向Student结构体类型的结构体变量

    结构指针变量的定义也可以与结构体的定义同时。而且它必须先赋值后使用。
    数组名表示的是数组的首地址,可以直接赋值给数组指针。但结构变量名只是表示整个结构体变量,不表示结构体变量的首地址,所以不能直接赋值给结构指针变量,而应该使用 & 运算符把结构变量的的地址赋值给结构指针变量。即:

    这里写图片描述

    注意:结构名、结构变量名、结构体指针的区别。

    2)通过结构指针间接访问成员值

    访问的一般形式:
    (*结构指针变量). 成员名 或 结构指针变量 -> 成员名
    如:

    (*pstu).name    
    pstu->name

    注意(pstu)的小括号不能省略,因为成员符“.”优先级为1,取地址符“”优先级为2,去掉括号就相当于*(pstu.name)了。

    5、结构体的嵌套

    1)结构体中的成员可以又是一个结构体,构成结构体的嵌套:

    struct Birthday{                //声明结构体 Birthday
        int year;
        int month;
        int day;
    };
    struct Student{                 //声明结构体 Student
        char name[20];              
        int num;                    
        float score;                 
        struct Birthday birthday;   //生日
    }; 
    

    这里写图片描述
    2)结构体不可以嵌套跟自己类型相同的结构体,但可以嵌套定义自己的指针。如:

    struct Student{                 //声明结构体 Student
        char name[20];
        int num;
        float score;
        struct Student *friend;     //嵌套定义自己的指针
    }

    3)甚至可以多层嵌套:

    struct Time{                    //声明结构体 Time
        int hh;                     //时
        int mm;                     //分
        int ss;                     //秒
    };
    struct Birthday{                //声明结构体 Birthday
        int year;
        int month;
        int day;
        struct Time dateTime        //嵌套结构
    };
    struct Student{                 //声明结构体 Student
        char name[20];
        int num;
        float score;
        struct Birthday birthday;   //嵌套结构
    }
    //定义并初始化
    struct Student stud = {"Jack", 32, 85, {1990, 12, 3, {12, 43, 23}}};
    //访问嵌套结构的成员并输出
    printf("%s 的出生时刻:%d时 \n", stud.name, stud.birthday.dateTime.hh);
    //输出结果:Jack 的出生时刻:12时 

    注意如何初始化和对嵌套结构的成员进行访问。

    6、结构与函数

    结构体的成员可以作为函数的参数,属于值传递(成员是数组的除外)。如:

    struct Student{                 //声明结构体 Student
        char name[20];
        int num;
        float score;
    };
    void printNum(int num){         //定义一个函数,输出学号
        printf("num = %d \n", num);
    }
        struct Student student0 = {"Mike", 27, 91};
        printNum(student0.num);     //调用printNum 函数,以结构成员作函数的参数
    //运行结果:num = 27 

    注意,函数printNum并不知道也不关心实际参数是不是结构成员,它只要求实参是int类型的就可以了。

    结构变量名也可以作为函数的参数传递,如:

    void PrintStu(struct Student student){      //定义 PrintStu 函数,以结构变量作函数的形参
        student.num = 100;                      //修改学号
        printf("PrintStu 修改后:姓名: %s, 学号: %d, 内存地址: %p \n", student.name, student.num, &student);
    }
        struct Student student0 = {"Mike", 27, 91};
        PrintStu(student0);                     //调用 PrintStu 函数,以结构变量名作函数的参数
        printf("           原来:姓名: %s, 学号: %d,  内存地址: %p \n", student0.name, student0.num, &student0);
    

    //输出结果:
    这里写图片描述

    形参和实参的地址不一样,是在函数中创建了一个局部结构体,然后实参对形参进行全部成员的逐个传送,在函数中对局部结构体变量进行修改并不影响原结构体变量。这样传送的时间空间开销都比较大,特别是当成员有数组的时候,程序效率较低。所以可以考虑使用指针:

    void PrintStu2(struct Student *student){      //定义 PrintStu2 函数,以结构指针作函数的形参
        student->num = 100;                       //修改学号
        printf("PrintStu2 修改后:姓名: %s, 学号: %d, 内存地址: %p \n", student->name, student->num, student);
    }
        struct Student student0 = {"Mike", 27, 91};
        PrintStu2(&student0);                     //调用 PrintStu 函数,以结构变量的地址作函数的参数
        printf("           原来:姓名: %s, 学号: %d,  内存地址: %p \n", student0.name, student0.num, &student0);

    //输出结果:
    这里写图片描述

    形参和实参的地址是一样的,所以是地址传递,在 PrintStu2 函数中,student 与&student0 指向同一块内存单元,用指针student修改结构变量会影响原结构变量。

    展开全文
  • 操作系统结构

    万次阅读 2018-07-13 12:58:45
    操作系统的内部的六种不同的结构设计:单体系统、层次系统、微内核、客户机-服务器系统、虚拟机和exokernels。 一、单体系统 二、层次式系统 三、微内核 四、客户机-服务器模式 五、虚拟机 六、外核...

    操作系统的内部的六种不同的结构设计:单体系统、层次系统、微内核、客户机-服务器系统、虚拟机和exokernels。

    一、单体系统

    在多数常见的组织形式的处理方式中,全部操作系统在内核态中以单一程序的方式运行。整个操作系统以过程集合的方式编写,链接成一个大型可执行二进制程序。
    在单体系统中,也可能有一些结构存在。可以将参数放置在良好定义的位置,通过这种方式,向操作系统请求所能提供的服务(系统调用),然后执行一个陷阱指令,这个指令将机器从用户态切换到内核态并把控制传递给操作系统,然后操作系统取出参数并且确定应该执行哪个系统调用,随后在一个表格中检索,在该表格的k槽中存放着指向执行系统调用k过程的指针。
    对于这类操作系统的基本结构:
    1. 需要一个主程序,用来处理服务过程请求。
    2. 需要一套服务过程,用来执行系统调用。
    3. 需要一套实用过程,用来辅助服务过程。
    在该模型中,每一个系统调用都通过一个服务过程为其工作并运行之。要有一组实用程序来完成一些服务过程所需要用到的功能。
    简单的单体系统结构图示:
    简单的单体系统结构

    二、层次式系统

    单体系统进一步通用化,就变成一个层次式结构的操作系统,它的上层软件都是在下一层软件的基础之上构建的。THE系统是按此模型构造的第一个操作系统。
    THE系统共分为六层。
    0. 处理器分配和多道程序设计
    处理器分配分配在第0层中进行,当中断发生或定时器到期时,由该层进行进程切换。在第0层之上,系统由一些连续的进程所组成,编写这些进程时不用再考虑在单处理器上多进程运行的细节。也就是说,在第0层中提供了基本的CPU多道程序功能。
    1. 存储器和磁鼓管理
    内存管理在第1层中进行,它分配进程的主存空间,当内存用完时则在一个512k字的磁鼓上保留进程的一部分(页面),在第1层上,进程不用考虑它是在磁鼓上还是在内存中进行。第1层软件保证一旦需要访问某一个页面时,该页面必定已在内存中。
    2. 操作员-进程通信
    第2层处理进程与操作员控制台(即用户)之间的通信。在这层的上不,可以认为每个进程都有自己的操作员控制台。
    3. 输入/输出管理
    第3层管理I/O设备和相关的信息流缓冲区。在第3层上,每个进程都与有良好特性的抽象I/O设备打交道,而不必考虑外部设备的物理细节。
    4. 用户程序
    第4层是用户程序层,用户程序不必考虑进程、内存、控制台或I/O设备管理细节。
    5. 操作员
    系统操作员进程位于第5层中。

    MULTICS系统

    该系统由许多的同心环构造而成,而不是采用层次化构造。内层环比外层环有更高的级别。当外环的过程欲调用内环的过程时,它必须执行一条等价于系统调用的TRAP指令。在执行该TRAP指令前,要进行严格的桉树合法性检查。

    三、微内核

    在微内核设计背后的思想是为了实现高可靠性,将操作系统划分成小的、良好定义的模块,只有其中一个模块–微内核–运行在内核态上,其余的模块,由于功能相对弱些,则作为普通用户进程运行。特别地由于把每个设备驱动和文件系统分别作为普通用户,这些模块中的错误虽然会使这些模块崩溃,但是不会使得整系统死机。
    微内核在实时、工业、航空以及军事应用中特别流行。
    MINIX3系统结构图示:
    微内核实例

    再生服务器

    检查其他服务器和驱动器的功能是否正确,一旦检查出一个错误,它自动取代之,无需任何用户的干预。这种方式使得系统具有自修复能力,并且获得了较高的可靠性。
    系统对每个进程的权限有着许多限制。一个与小内核相关联的思想是在内核中的机制与策略分离的原则。一个比较简单的调度算法是,对于每个进程赋予一个优先级,并让内核执行在具有最高优先级进程中可以运行的某个进程。这里机制(在内核中)就是寻找最高优先级的进程并运行之。而策略(赋予进程以优先级)可以由用户态中的进程完成。在这个方式中,机制和策略是分离的,从而使系统内核变得更小。

    四、客户机-服务器模式

    一个微内核思想的略微变体是将进程划分为:
    1. 服务器:每个服务器提供某种服务。
    2. 客户端:使用这些服务。
    这个模式就是所谓的客户机-服务器模式。通常在系统最底层是微内核,这个模式的本质是存在客户端进程和服务器进程。
    在客户端和服务器之间的通信是消息传递。普遍方式是客户端和服务器在不同的计算机上,通过局域网或广域网连接,由于客户端通过发送消息与服务端通信,客户端并不需要知道这些消息是在它们的本地机器上处理,还是通过网络被送到远程机器上处理。
    客户端-服务器模型实例:
    客户端-服务器

    五、虚拟机

    1. VM/370

    最初命名为CP/CMS,后来改名为VM/370,它的目的是为了将多道程序和获取更方便的裸机彻底隔离。它的核心称为虚拟机监控程序,它在裸机上运行并且具备了多道程序功能。该系统向上层提供了若干个虚拟机。它不同于其他操作系统:这些虚拟机不是那种具有文件等优良特征的扩展计算机。它们仅仅是裸机硬件的精确复制品,包含了内核态/用户态、I/O功能、中断及其他真是硬件所具备的全部内容。

    2. 虚拟机的再次发现

    虚拟化的优点:
    1. 一台物理机就可以运行许多虚拟机,每个虚拟机看起来都是一台完全的机器。这样可以节省费用。
    2. 可以同时运行两个或多个操作系统。

    3. Java虚拟机

    它是一种体系结构。Java编译器为JVM生成代码,这些代码以后可以由一个软件JVM解释器质性。这种处理方式的优点在于,JVM代码可以通过Internet传送到任何有JVM解释器的机器上,并在该机器执行。使用JVM的优点就是如果解释器正确地完成,并不意味着结束,还要对所输入的KVM进行安全性检测,然后在一直保护环境下执行,这样,这些程序就不能偷窃数据或进行其他任何有害的操作。

    六、外核

    与虚拟机克隆真实机器不同,另一种策略是对机器进行分区。给每个用户整个资源的一个子集。
    在底层中,一种称为外核的程序在内核态中运行。它的任务是为虚拟机分配资源,并检查试图使用这些资源的企图,以确保没有机器会使用他人资源。每个用户层的虚拟机可以运行自己的操作系统,但限制在只能使用已经申请并且获得分配的那部分资源。
    外核机制的优点是减少了映像层。在其他的设计中,每个虚拟机都认为它有的磁盘,其盘块号从0到最大编号,这样虚拟机监控程序必须维护一张表格用以重映像磁盘地址,有了外核这个重映像处理就不需要了,外核只需要记录已经分配各个虚拟机的有关资源即可。这个方法还有一个优点,它将多道程序(在外核内)与用户操作系统代码(在用户控件内)加以分离,而且相应负载并不重,这是因为外核所做的一切,只是保持多个虚拟机彼此不发生冲突。

    展开全文
  • B/S结构简介

    万次阅读 2007-07-26 20:56:00
    B/S结构,即Browser/Server(浏览器/服务器)结构,是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户界面完全通过WWW浏览器实现,一部分事务逻辑在前端实现,但是主要事务逻辑在...

        B/S结构,即Browser/Server(浏览器/服务器)结构,是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户界面完全通过WWW浏览器实现,一部分事务逻辑在前端实现,但是主要事务逻辑在服务器端实现,形成所谓3-tier结构。B/S结构,主要是利用了不断成熟的WWW浏览器技术,结合浏览器的多种Script语言(VBScript、JavaScript…)和ActiveX技术,用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。随着Windows 98/Windows 2000将浏览器技术植入操作系统内部,这种结构更成为当今应用软件的首选体系结构。 

      B/S结构,即Browser/Server(浏览器/服务器)结构,就是只安装维护一个服务器(Server),而客户端采用浏览器(Browse)运行软件。它是随着Internet技术的兴起,对C/S结构的一种变化和改进。主要利用了不断成熟的WWW浏览器技术,结合多种Script语言(VBScript、JavaScript…)和ActiveX技术,是一种全新的软件系统构造技术。

    B/S三层体系结构采用三层客户/g艮务器结构,在数据管理层(Server)和用户界面层(Client)增加了一层结构,称为中间件(Middleware),使整个体系结构成为三层。三层结构是伴随着中间件技术的成熟而兴起的,核心概念是利用中间件将应用分为表示层、业务逻辑层和数据存储层三个不同的处理层次,如图2所示。三个层次的划分是从逻辑上分的,具体的物理分法可以有多种组合。中间件作为构造三层结构应用系统的基础平台,提供了以下主要功能:负责客户机与服务器、服务器与服务器间的连接和通信;实现应用与数据库的高效连接;提供一个三层结构应用的开发、运行、部署和管理的平台。这种三层结构在层与层之间相互独立,任何一层的改变不会影响其它层的功能。

    在B/S体系结构系统中,用户通过浏览器向分布在网络上的许多服务器发出请求,服务器对浏览器的请求进行处理,将用户所需信息返回到浏览器。而其余如数据请求、加工、结果返回以及动态网页生成、对数据库的访问和应用程序的执行等工作全部由Web Server完成。随着Windows将浏览器技术植入操作系统内部,这种结构已成为当今应用软件的首选体系结构。显然B/S结构应用程序相对于传统的C/S结构应用程序是一个非常大的进步。

    B/S结构的主要特点是分布性强、维护方便、开发简单且共享性强、总体拥有成本低。但数据安全性问题、对服务器要求过高、数据传输速度慢、软件的个性化特点明显降低,这些缺点是有目共睹的,难以实现传统模式下的特殊功能要求。例如通过浏览器进行大量的数据输入或进行报表的应答、专用性打印输出都比较困难和不便。此外,实现复杂的应用构造有较大的困难。虽然可以用ActiveX、Java等技术开发较为复杂的应用,但是相对于发展已非常成熟C/S的一系列应用工具来说,这些技术的开发复杂,并没有完全成熟的技术工具供使用。

     

    近年来,随着网络技术不断发展,尤其是基于Web的信息发布和检索技术、Java计算技术以及网络分布式对象技术的飞速发展,导致了很多应用系统的体系结构从C/S结构向更加灵活的B/S多级分布结构演变,使得软件系统的网络体系结构跨入一个新阶段。认识这些结构的特征,并根据实际情况进行系统的选型,对于成功开发一个MIS系统是非常关键的。

     C/S结构与B/S结构

    1.1 C/S结构

    C/S结构,即Client/Server(客户机/服务器)结构。此结构把数据库内容放在远程的服务器上,而在客户机上安装相应软件。C/S软件一般采用两层结构,其分布结构如图1所示。它由两部分构成:前端是客户机,即用户界面(Client)结合了表示与业务逻辑,接受用户的请求,并向数据库服务提出请求,通常是一个PC机;后端是服务器,即数据管理(Server)将数据提交给客户端,客户端将数据进行计算并将结果呈现给用户。还要提供完善的安全保护及对数据的完整性处理等操作,并允许多个客户同时访问同一个数据库。在这种结构中,服务器的硬件必须具有足够的处理能力,这样才能满足各客户的要求。

    C/S结构在技术上很成熟,它的主要特点是交互性强、具有安全的存取模式、网络通信量低、响应速度快、利于处理大量数据。但是该结构的程序是针对性开发,变更不够灵活,维护和管理的难度较大。通常只局限于小型局域网,不利于扩展。并且,由于该结构的每台客户机都需要安装相应的客户端程序,分布功能弱且兼容性差,不能实现快速部署安装和配置,因此缺少通用性,具有较大的局限性。要求具有一定专业水准的技术人员去完成。

    1.2 B/S结构

    B/S结构,即Browser/Server(浏览器/服务器)结构,就是只安装维护一个服务器(Server),而客户端采用浏览器(Browse)运行软件。它是随着Internet技术的兴起,对C/S结构的一种变化和改进。主要利用了不断成熟的WWW浏览器技术,结合多种Script语言(VBScript、javascript…)和ActiveX技术,是一种全新的软件系统构造技术。图片点击可在新窗口打开查看

    B/S三层体系结构采用三层客户/g艮务器结构,在数据管理层(Server)和用户界面层(Client)增加了一层结构,称为中间件(Middleware),使整个体系结构成为三层。三层结构是伴随着中间件技术的成熟而兴起的,核心概念是利用中间件将应用分为表示层、业务逻辑层和数据存储层三个不同的处理层次,如图2所示。三个层次的划分是从逻辑上分的,具体的物理分法可以有多种组合。中间件作为构造三层结构应用系统的基础平台,提供了以下主要功能:负责客户机与服务器、服务器与服务器间的连接和通信;实现应用与数据库的高效连接;提供一个三层结构应用的开发、运行、部署和管理的平台。这种三层结构在层与层之间相互独立,任何一层的改变不会影响其它层的功能。

    在B/S体系结构系统中,用户通过浏览器向分布在网络上的许多服务器发出请求,服务器对浏览器的请求进行处理,将用户所需信息返回到浏览器。而其余如数据请求、加工、结果返回以及动态网页生成、对数据库的访问和应用程序的执行等工作全部由Web Server完成。随着Windows将浏览器技术植入操作系统内部,这种结构已成为当今应用软件的首选体系结构。显然B/S结构应用程序相对于传统的C/S结构应用程序是一个非常大的进步。

    B/S结构的主要特点是分布性强、维护方便、开发简单且共享性强、总体拥有成本低。但数据安全性问题、对服务器要求过高、数据传输速度慢、软件的个性化特点明显降低,这些缺点是有目共睹的,难以实现传统模式下的特殊功能要求。例如通过浏览器进行大量的数据输入或进行报表的应答、专用性打印输出都比较困难和不便。此外,实现复杂的应用构造有较大的困难。虽然可以用ActiveX、Java等技术开发较为复杂的应用,但是相对于发展已非常成熟C/S的一系列应用工具来说,这些技术的开发复杂,并没有完全成熟的技术工具供使用。

    2 C/S结构与B/S结构的分析比较

    2.1 硬件环境不同

    C/S建立在局域网的基础上,通过专门服务器提供连接和数据交换服务。所处理的用户不仅固定,并且处于相同区域,要求拥有相同的操作系统。B/S建立在广域网的基础上,信息自己管理,有比C/S更强的适应范围,一般只要有操作系统和浏览器就行。与操作系统平台关系最小。面向不可知的用户群。

    2.2 结构不同

    C/S软件一般采用两层结构,而B/S采用三层结构:

    这两种结构的不同点是两层结构中客户端参与运算,而三层结构中客户端并不参与运算,只是简单地接收用户的请求,显示最后的结果。由于三层结构中的客户端并不需要参与计算,所以对客户端的计算机电脑配置要求较低。虽然BlS采用了逻辑上的三层结构,但在物理上的网络结构仍然是原来的以太网或环形网。这样,第一层与第二层结构之间的通信、第二层与第三层结构之间的通信都需占用同一条网络线路,网络通信量大。而C/S只有两层结构,网络通信量只包括Client与Server之间的通信量,网络通信量低。所以,C/S处理大量信息的能力是B/S无法比拟的。

    2.3 处理模式不同

    B/S的处理模式与C/S相比,大大简化了客户端,只要装上操作系统、网络协议软件以及浏览器即可,这时的客户机成为瘦客户机,而服务器则集中了所有的应用逻辑。

    2.4 构件重用不同

    在构件的重用性方面,C/S程序从整体进行考虑,具有较低的重用性。 而BlS对应的是多重结构,要求构件具有相对独立的功能,具有较好的重用性。

    2.5 系统维护不同

    系统维护是在软件生存周期中开销最大的一部分。C/S程序由于其本身的整体性,必须整体考察并处理出现的问题。而B/S结构,客户端不必安装及维护。B/S结构在构件组成方面只变更个别构件,开发、维护等工作都集中在服务器端。当需要升级时,只需更新服务器端的软件,而不必更换客户端软件,实现系统的无缝升级。这样就减轻了系统维护与升级的成本和工作量,使用户的总体拥有成本(TCO)大大降低。

    2.6 对安全的要求不同

    由于C/S采用配对的点对点的结构模式,并采用适用于局域网、安全性比较好的网络协议(例如NT的NetBEUI协议),安全性可得到较好的保证。C/S一般面向相对固定的用户群,程序更加注重流程,它可以对权限进行多层次校验,提供了更安全的存取模式,对信息安全的控制能力很强。一般高度机密的信息系统采用C/S结构适宜。而B/S采用点对多点、多点对多点这种开放的结构模式,并采用TCP/IP这一类运用于Intemet的开放性协议,其安全性只能靠数据服务器上管理密码的数据库来保证。所以B/S对安全以及访问速度比C/S有更高的要求。而Intemet技术中这些关键的安全问题远未解决。

    2.7 速度不同

    由于C/S在逻辑结构上比B/S少一层,对于相同的任务,C/S完成的速度总比B/S快。使得C/S更利于处理大量数据。

    2.8 交互性与信息流不同

    交互性强是C/S固有的一个优点。在C/S中,客户端有一套完整的应用程序,在出错提示、在线帮助等方面都有强大的功能,并且可以在子程序间自由切换。B/S虽然由javascript、VBScript提供了一定的交互能力,但与C/S的一整套客户应用相比是太有限了。C/S的信息流单一,而B/S可处理如B-B、B-C、B-G等信息并具有流向的变化。

    3 基于B/S结构与C/S结构结合的体系结构

    综上所述,可见B/S与C/S这两种技术是各有利弊的。

    C/S技术是20年前的主流开发技术,它主要局限于内部局域网的需要。因而缺乏作为应用平台的一些特性,难以扩展到互联网这样的环境上去,而且要求开发者自己去处理事务管理、消息队列、数据的复制和同步、通信安全等系统级的问题。这对应用开发者提出了较高的要求,而且迫使应用开发者投入很多精力来解决应用程序以外的问题。这使得应用程序的维护、移植和互操作变得复杂,成了C/S的一大缺陷。

    但是,与B/S结构相比,C/S技术发展历史更为“悠久”。从技术成熟度及软件设计、开发人员的掌握水平来看,C/S技术更成熟、更可靠。在某些情况下,采用100%的B/S方式将造成系统响应速度慢、服务器开销大、通信带宽要求高、安全性差、总投资增加等问题。而且,对于一些复杂的应用,B/S方式目前尚没有合适方式进行开发。
    图片点击可在新窗口打开查看
       
    客观地分析C/S、B/S的优劣,建立C/S、B/S结构相结合的网络构架已成为必然趋势。在实际开发和规划系统的时候要有的放矢,才能够搭建成合适的信息系统。

    下面以学校学生管理系统为实例说明这种设计方法。该系统采用B/S+C/S体系结构,结合了ASP技术,并将组件技术COM+和ActiveX技术分别应用在服务器端和客户端。该系统的实现主要分为三个部分:ASP页面、COM+组件和数据库,是一个三层结构。表示层由ASP页面组成,用以实现WEB页面显示和调用COM+组件,业务逻辑和数据访问由一组用VC实现的COM+组件构成。为了便于维护、升级和实现分布式应用,在实现过程中,又将业务逻辑层和数据访问层分离开,ASP页面不直接调用数据访问层,而是通过业务逻辑层调用数据库。一些需要用WEB处理的、满足大多数访问者请求的功能界面采用B/S结构,例如任课教师可以通过浏览器查询所教班级学生各种相关信息;学校管理人员通过浏览器对学校的学生、教师等信息进行管理与维护以及查询统计;领导层可通过浏览器进行数据的查询和决策。这样客户端比较灵活。而后台只需少数人使用的功能则采用C/S结构,例如数据库管理维护界面。如此处理,可充分发挥各种模式的优越性——避免了B/S结构在安全性、保密性和响应速度等方面的缺点以及C/S结构在维护和灵活性等方面的缺点。COM+的实现可分为三个步骤:COM+组件的设计、COM+应用程序的生成和编程。COM+组件位于WEB应用程序中,客户端发出请求到WEB SERVER。WEB SERVER将请求传给WEB应用程序。WEB应用程序将数据请求传送给数据库服务器,数据库服务器将数据返回WEB应用程序。然后再由WEB SERVER将数据传送给客户端。对于一些较难实现的功能通过在页面中嵌入ActiveX控件来实现。

    采用这种结构优点在于:

    (1)充分发挥了B/S与C/S体系结构的优势,弥补了二者不足。充分考虑用户利益,保证浏览查询者方便操作的同时也使得系统更新简单,维护简单灵活,易于操作。

    (2)信息发布采用B/S结构,保持了瘦客户端的优点。装入客户机的软件可以采用统一的WWW浏览器。而且由于WWW浏览器和网络综合服务器都是基于工业标准,可以在所有的平台上工作。

    (3)数据库端采用C/S结构,通过ODBC/JDBC连接。这一部分只涉及到系统维护、数据更新等,不存在完全采用C/S结构带来的客户端维护工作量大等缺点。并且在客户端可以构造非常复杂的应用,界面友好灵活,易于操作,能解决许多B/S存在的固有缺点。

    (4)对于原有的基于C/S体系结构的应用,只需开发用于发布的WWW界面,就可非常容易地升级到这种体系结构,并保留原来的某些子系统。这样就充分地利用现有系统的资源。

    (5)通过在浏览器中嵌入ActiveX控件可以实现在浏览器中不能实现或实现起来比较困难的功能。例如通过浏览器进行报表的应答。

    (6)将服务器端划分为WEB服务器和WEB应用程序两部分。WEB应用程序采用组件技术实现三层体系结构中的逻辑部分,达到封装的目的。

    B/S结构与C/S结构各具优缺点,怎样结合B/S与C/S开发系统是开发MIS系统普遍关注的问题。在应用过程中,应结合实际情况,并根据实际情况进行系统的选型与构建,从而开发出高效、安全的应用系统。

    为什么说B/S结构优于C/S结构

    C/S结构,即Client/Server(客户机/服务器)结构,是大家熟知的软件系统体系结构,通过将任务合理分配到Client端和Server端,降低了系统的通讯开销,可以充分利用两端硬件环境的优势。
      B/S结构,即Browser/Server(浏览器/服务器)结构,是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户界面完全通过WWW浏览器实现,一部分事务逻辑在前端实现,但是主要事务逻辑在服务器端实现,形成所谓3-tier结构。B/S结构利用不断成熟和普及的浏览器技术实现原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。这种结构更成为当今应用软件的首选体系结构,microsoft.net也是在这样一种背景下被提出来的架构,但微软的方案只是一种构想,要成为现实还需要几年,而JAVA技术已经是很成熟的应用了。
      目前大多数应用软件系统都是Client/Server形式的两层结构,现在的软件应用系统正在向分布式的Web应用发展;内部的和外部的用户都可以访问新的和现有的应用系统,Web和Client/Server 应用都可以进行同样的业务处理;不同的应用模块共享逻辑组件;通过现有应用系统中的逻辑可以扩展出新的应用系统。这也就是目前应用系统的发展方向。
      管理软件的主流技术与管理思想一样,也经历了三个发展时期:界面技术从DOS字符界面,到Windows图形界面(或图形用户界面GUI),直至今天的Browser浏览器界面。最新浏览器界面,不仅直观和易于使用,更主要的是基于浏览器平台的任何应用软件其界面风格一致,用户对操作培训的要求大为下降,软件可操作性增强;平台体系结构也从单机单用户发展到文件/服务器(F/S)体系,再到客户机/服务器(C/S)体系和浏览器/服务器(B/S)体系。
      传统的C/S体系结构虽然采用的是开放模式,但这只是系统开发一级的开放性,在特定的应用中无论是Client端还是Server端都还需要特定的软件,没能提供用户真正期望的开放环境;B/S结构则不同,它的前端是以TCP/IP协议为基础的,企业内的WWW服务器可以接受安装有Web浏览程序的Internet终端的访问,作为最终用户,只要通过Web浏览器,各种处理任务都可以调用系统资源来完成,这样大大简化了客户端,减轻了系统维护与升级的成本和工作量,降低了用户的总体拥有成本(TCO)。
      越来越厚的使用说明书和越来越花时间的培训,并不能称为"良好的售后服务",真正好的产品在功能越来越复杂的同时应该使产品的使用越来越简单,使用浏览器作为软件界面不但容易统一各种应用系统,也非常便于使用。在工作节奏越来越紧张的今天调集大批的职员进行培训是很困难的,时间和人力都难以集中,浏览器这种易于使用几乎不需要培训的方式是最好的选择。
    维护和升级方式的革命-瘦客户机
      软件系统的改进和升级越来越频繁,B/S架构的产品明显体现的更方便的特性。无论用户的规模有多大,有多少分支机构都不会增加任何维护升级的工作量,所有的操作只需要针对服务器进行,如果是异地只需要把服务器连接上网即可立即进行维护和升级,这对人力、时间、费用的节省是相当惊人的。
      一个稍微大一点单位来说,系统管理人员如果需要在几百甚至几千部电脑之间来回奔跑,效率和工作量是可想而知的,但B/S架构的软件只需要管理服务器就行了,所有的客户端只是浏览器,根本不需要做任何的维护。所以客户机越来越"瘦"而服务器越来越"胖"是将来软件的主流发展方向,这使得升级和维护越来越容易而使用越来越简单。
    成本降低,选择更多
      很明显windows在桌面电脑上几乎一统天下,浏览器成为了标准配置,但在服务器操作系统,windows并没有这种绝对的统治地位,而现在的趋势是应用软件都变成B/S架构的,只安装在服务器上,所以服务器操作系统的选择是很多的,不管选用那种操作系统都可以让大部分人使用windows作为桌面操作系统的情况不受影响,这就使的很多免费的操作系统如现在最流行的Linux得以快速发展,除了操作系统是免费的以外,连数据库也是免费的,这样的选择非常流行。
      比如说很多人每天上新浪网,只要安装了浏览器就可以了,并不需要了解新浪的服务器用的是什么操作系统,而事实上大部分网站确实没有使用windows操作系统,但用户的电脑本身安装的大部分是windows操作系统。
    中国政府处于安全和国家战略的考虑希望有自己的操作系统,而在桌面领域任何一种操作系统都难以和windows抗衡, 
      Linux的出现使这种想法变成了现实,由于Linux是免费产品,源代码也是公开的,中国出现很多开发Linux的力量,国家大力推动Linux,政府机关处于安全的考虑会越来越多使用Linux,从国内软件市场的销售来看Linux也是基本上每个月都是排名第一的产品。
      传统的C/S结构的软件需要针对不同的操作系统系统开发不同版本的软件,由于产品的更新换代十分快,这么高的代价和低效率已经越来越不适应了。在JAVA这样的跨平台语言出现之后B/S架构更是飞快地普及起来了。
    面向电子商务时代的技术
      将来所有的应用系统几乎都在互联网上运行,企业发展电子商务也是不可避免的,而B/S架构的软件则代表了将来的技术,只要连上互联网或内部广域网就可以与全球的客户相连,与各地的分支机构相连。
    移动办公
    ☆ 在办公室内移动的时候可以使用任何一台电脑办公,而传统的OA是每台电脑对应指定的用户,别的用户不能使用该电脑,而且还需要安装调试软件,相当不方便。
     回家或离开办公室或出差到其他地方只要有可以上网的电脑也可以使用办公系统。
    ☆ 分公司可以通过互联网、专线、电话网等连接使用资源共享,协同办公。
    系统整合
      无论是办公自动化管理系统,人力资源管理系统,客户关系管理系统,ERP等等,发展的趋势是不断融合,采用统一的B/S结构开发的产品无论是现在还是将来都是最好的选择。
    目前B/S模式下最好的选择---JAVA技术
      现在出现的Microsoft.NET也是模仿JAVA的思路,Microsoft.NET的蓝图与Java十分相似,目前还只是一个框架,还需要几年才能成熟,而JAVA已经是应用十分普及的技术了。

     

    展开全文
  • C语言中的结构体,联合,链表和枚举,位域(下) 一、联合的定义  定义一个联合类型的一般形式为:  union 联合名  {  成员表  ...成员表中含有若干成员,成员的一般形式为: 类型说明符 成员名 成员名的命名应...

    C语言中的结构体,联合,链表和枚举,位域(下) 一、联合的定义 
    定义一个联合类型的一般形式为: 
    union 联合名 

    成员表 
    }; 
    成员表中含有若干成员,成员的一般形式为: 类型说明符 成员名 成员名的命名应符合标识符的规定。 
    例如:

    union perdata { int class; char office[10]; }; 定义了一个名为perdata的联合类型,它含有两个成员,一个为整型,成员名为class;另一个为字符数组,数组名为office。联合定义之后,即可进行联合变量说明,被说明为perdata类型的变量,可以存放整型量class或存放字符数组office。
    二、联合变量的说明 
    联合变量的说明和结构变量的说明方式相同, 也有三种形式。即先定义,再说明;定义同时说明和直接说明。以perdata类型为例,说明如下:

    union perdata { int class; char officae[10]; }; union perdata a,b;  或者可同时说明为: union perdata { int class; char office[10]; }a,b;或直接说明为: union { int class; char office[10]; }a,b 经说明后的a,b变量均为perdata类型。 它们的内存分配示意图如图7—8所示。a,b变量的长度应等于 perdata 的成员中最长的长度, 即等于 
    office数组的长度,共10个字节。从图中可见,a,b变量如赋予整型值时,只使用了2个字节,而赋予字符数组时,可用10个字节。 
    联合变量的赋值和使用 
    对联合变量的赋值,使用都只能是对变量的成员进行。 联合变量的成员表示为: 联合变量名.成员名 例如,a被说明为perdata类型的变量之后,可使用 a.class a.office 不允许只用联合变量名作赋值或其它操作。 也不允许对联合变量作初始化赋值,赋值只能在程序中进行。还要再强调说明的是,一个联合变量, 每次只能赋予一个成员值。换句话说,一个联合变量的值就是联合变员的某一个成员值。 
    [例7.15]设有一个教师与学生通用的表格,教师数据有姓名,年龄,职业,教研室四项。学生有姓名,年龄,职业,班级四项。 
    编程输入人员数据, 再以表格输出。

    main() { struct { char name[10]; int age; char job; union { int class; char office[10]; } depa; }body[2]; int n,i; for(i=0;i<2;i++) { printf("input name,age,job and department\n"); scanf("%s %d %c",body[i].name,&body[i].age,&body[i].job); if(body[i].job=='s') scanf("%d",&body[i].depa.class); else scanf("%s",body[i].depa.office); } printf("name\tage job class/office\n"); for(i=0;i<2;i++) { if(body[i].job=='s') printf("%s\t= < %d\n",body[i].name,body[i].age ,body[i].job,body[i].depa.class); else printf("%s\t= < %s\n",body[i].name,body[i].age, body[i].job,body[i].depa.office); } } 本例程序用一个结构数组body来存放人员数据, 该结构共有四个成员。其中成员项depa是一个联合类型, 这个联合又由两个成员组成,一个为整型量class,一个为字符数组office。在程序的第一个for语句中,输入人员的各项数据,先输入结构的前三个成员name,age和job,然后判别job成员项,如为"s"则对联合depa·class输入(对学生赋班级编号)否则对depa·office输入(对教师赋教研组名)。 
    在用scanf语句输入时要注意,凡为数组类型的成员,无论是结构成员还是联合成员,在该项前不能再加"&"运算符。如程序第18行中 
    body[i].name是一个数组类型,第22行中的body[i].depa.office也是数组类型,因此在这两项之间不能加"&"运算符。程序中的第二个for语句用于输出各成员项的值: 
    本章小结
    1. 结构和联合是两种构造类型数据,是用户定义新数据类型的重要手段。结构和联合有很多的相似之处,它们都由成员组成。成员可以具有不同的数据类型。成员的表示方法相同。都可用三种方式作变量说明。 
    2. 在结构中,各成员都占有自己的内存空间,它们是同时存在的。一个结构变量的总长度等于所有成员长度之和。在联合中,所有成员不能同时占用它的内存空间,它们不能同时存在。联合变量的长度等于最长的成员的长度。 
    3. “.”是成员运算符,可用它表示成员项,成员还可用“->”运算符来表示。 
    4. 结构变量可以作为函数参数,函数也可返回指向结构的指针变量。而联合变量不能作为函数参数,函数也不能返回指向联合的指针变量。但可以使用指向联合变量的指针,也可使用联合数组。 
    5. 结构定义允许嵌套,结构中也可用联合作为成员,形成结构和联合的嵌套。 
    6. 链表是一种重要的数据结构,它便于实现动态的存储分配。本章介绍是单向链表,还可组成双向链表,循环链表等。

    typedef是类型定义的意思。typedef struct 是为了使用这个结构体方便。 
    具体区别在于: 
    若struct node {}这样来定义结构体的话。在申请node 的变量时,需要这样写,struct node n; 
    若用typedef,可以这样写,typedef struct node{}NODE; 。在申请变量时就可以这样写,NODE n; 
    区别就在于使用时,是否可以省去struct这个关键字。

    分三块来讲述: 
    1 首先: 
    在C中定义一个结构体类型要用typedef: 
    typedef struct Student 

    int a; 
    }Stu; 
    于是在声明变量的时候就可:Stu stu1; 
    如果没有typedef就必须用struct Student stu1;来声明 
    这里的Stu实际上就是struct Student的别名。 
    另外这里也可以不写Student(于是也不能struct Student stu1;了) 
    typedef struct 

    int a; 
    }Stu; 
    但在c++里很简单,直接 
    struct Student 

    int a; 
    }; 
    于是就定义了结构体类型Student,声明变量时直接Student stu2; 
    =========================================== 
    2其次: 
    在c++中如果用typedef的话,又会造成区别: 
    struct Student 

    int a; 
    }stu1;//stu1是一个变量 
    typedef struct Student2 

    int a; 
    }stu2;//stu2是一个结构体类型 
    使用时可以直接访问stu1.a 
    但是stu2则必须先 stu2 s2; 
    然后 s2.a=10; 
    =========================================== 
    3 掌握上面两条就可以了,不过最后我们探讨个没多大关系的问题 
    如果在c程序中我们写: 
    typedef struct 

    int num; 
    int age; 
    }aaa,bbb,ccc; 
    这算什么呢? 
    我个人观察编译器(VC6)的理解,这相当于 
    typedef struct 

    int num; 
    int age; 
    }aaa; 
    typedef aaa bbb; 
    typedef aaa ccc; 
    也就是说aaa,bbb,ccc三者都是结构体类型。声明变量时用任何一个都可以,在c++中也是如此。但是你要注意的是这个在c++中如果写掉了typedef关键字,那么aaa,bbb,ccc将是截然不同的三个对象。

    第四篇:C/C++中typedef struct和struct的用法

    struct _x1 { ...}x1; 和 typedef struct _x2{ ...} x2; 有什么不同?

    其实, 前者是定义了类_x1和_x1的对象实例x1, 后者是定义了类_x2和_x2的类别名x2 ,

    所以它们在使用过程中是有取别的.请看实例1.

    [知识点]

    结构也是一种数据类型, 可以使用结构变量, 因此, 象其它 类型的变量一样, 在使用结构变量时要先对其定义。

    定义结构变量的一般格式为:

    struct 结构名

    {

    类型 变量名;

    类型 变量名;

    ...

    } 结构变量;

    结构名是结构的标识符不是变量名。

    另一种常用格式为:

    typedef struct 结构名

    {

    类型 变量名;

    类型 变量名;

    ...

    } 结构别名;

    另外注意: 在C中,struct不能包含函数。在C++中,对struct进行了扩展,可以包含函数。

    ======================================================================

    实例1: struct.cpp

    #include using namespace std; typedef struct _point{ int x; int y; }point; //定义类,给类一个别名 struct _hello{ int x,y; } hello; //同时定义类和对象 int main() { point pt1; pt1.x = 2; pt1.y = 5; cout<< "ptpt1.x=" << pt1.x << "pt.y=" < //hello pt2; //pt2.x = 8; //pt2.y =10; //cout<<"pt2pt2.x="<< pt2.x <<"pt2.y="< //上面的hello pt2;这一行编译将不能通过. 为什么? //因为hello是被定义了的对象实例了. //正确做法如下: 用hello.x和hello.y hello.x = 8; hello.y = 10; cout<< "hellohello.x=" << hello.x << "hello.y=" < return 0; } 第五篇:问答

    Q: 用struct和typedef struct 定义一个结构体有什么区别?为什么会有两种方式呢?

    struct Student 

    int a; 
    } stu; 
    typedef struct Student2 

    int a; 
    }stu2;

    A:

    事实上,这个东西是从C语言中遗留过来的,typedef可以定义新的复合类型或给现有类型起一个别名,在C语言中,如果你使用 
    struct xxx 

    }; 的方法,使用时就必须用 struct xxx var 来声明变量,而使用 
    typedef struct 

    }的方法 就可以写为 xxx var; 
    不过在C++中已经没有这回事了,无论你用哪一种写法都可以使用第二种方式声明变量,这个应该算是C语言的糟粕。

    用法小结

    第一、四个用途

    用途一:

    定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如: 
    char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针, 
    // 和一个字符变量; 
    以下则可行: 
    typedef char* PCHAR; // 一般用大写 
    PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针 
    虽然: 
    char *pa, *pb; 
    也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。

    用途二:

    用在旧的C的代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如: 
    struct tagPOINT1 

    int x; 
    int y; 
    }; 
    struct tagPOINT1 p1;

    而在C++中,则可以直接写:结构名 对象名,即: 
    tagPOINT1 p1;

    估计某人觉得经常多写一个struct太麻烦了,于是就发明了: 
    typedef struct tagPOINT 

    int x; 
    int y; 
    }POINT;

    POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候

    或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。

    枚举
    在实际问题中, 有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月, 一个班每周有六门课程等等。如果把这些量说明为整型, 字符型或其它类型显然是不妥当的。 为此,C语言提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值, 被说明为该“枚举”类型的变量取值不能超过定义的范围。应该说明的是, 枚举类型是一种基本数据类型,而不是一种构造类型, 因为它不能再分解为任何基本类型。 
    枚举类型的定义和枚举变量的说明 
    一、枚举的定义枚举类型定义的一般形式为: 
    enum 枚举名 
    { 枚举值表 }; 
    在枚举值表中应罗列出所有可用值。这些值也称为枚举元素。 
    例如: enum weekday 
    { sun,mou,tue,wed,thu,fri,sat }; 
    该枚举名为weekday,枚举值共有7个,即一周中的七天。 凡被说明为weekday类型变量的取值只能是七天中的某一天。 
    二、枚举变量的说明 如同结构和联合一样,枚举变量也可用不同的方式说明, 即先定义后说明,同时定义说明或直接说明。设有变量a,b,c被说明为上述的weekday,可采用下述任一种方式: 
    enum weekday 

    ...... 
    }; 
    enum weekday a,b,c;或者为: enum weekday 

    ...... 
    }a,b,c;或者为: enum 

    ...... 
    }a,b,c;

    枚举类型变量的赋值和使用 
    枚举类型在使用中有以下规定: 
    1. 枚举值是常量,不是变量。不能在程序中用赋值语句再对它赋值。例如对枚举weekday的元素再作以下赋值: sun=5;mon=2;sun=mon; 都是错误的。 
    2. 枚举元素本身由系统定义了一个表示序号的数值,从0 开始顺序定义为0,1,2…。如在weekday中,sun值为0,mon值为1, …,sat值为6。

    main(){ enum weekday { sun,mon,tue,wed,thu,fri,sat } a,b,c; a=sun; b=mon; c=tue; printf("%d,%d,%d",a,b,c); } 3. 只能把枚举值赋予枚举变量,不能把元素的数值直接赋予枚举变量。如: a=sum;b=mon; 是正确的。而: a=0;b=1; 是错误的。如一定要把数值赋予枚举变量,则必须用强制类型转换,如: a=(enum weekday)2;其意义是将顺序号为2的枚举元素赋予枚举变量a,相当于: a=tue; 还应该说明的是枚举元素不是字符常量也不是字符串常量, 使用时不要加单、双引号。

    main(){ enum body { a,b,c,d } month[31],j; int i; j=a; for(i=1;i<=30;i++){ month[i]=j; j++; if (j>d) j=a; } for(i=1;i<=30;i++){ switch(month[i]) { case a:printf(" - %c\t",i,'a'); break; case b:printf(" - %c\t",i,'b'); break; case c:printf(" - %c\t",i,'c'); break; case d:printf(" - %c\t",i,'d'); break; default:break; } } printf("\n"); }位域 
    有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为: 
    struct 位域结构名 
    { 位域列表 }; 
    其中位域列表的形式为: 类型说明符 位域名:位域长度 
    例如:

    struct bs { int a:8; int b:2; int c:6; }; 位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:

    struct bs { int a:8; int b:2; int c:6; }data; 说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明: 
    1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

    struct bs { unsigned a:4 unsigned :0  unsigned b:4  unsigned c:4 } 在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。 
    2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。 
    3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:

    struct k { int a:1 int :2  int b:3 int c:2 }; 从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。

    二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 位域变量名·位域名 位域允许用各种格式输出。

    main(){ struct bs { unsigned a:1; unsigned b:3; unsigned c:4; } bit,*pbit; bit.a=1; bit.b=7; bit.c=15; printf("%d,%d,%d\n",bit.a,bit.b,bit.c); pbit=&bit; pbit->a=0; pbit->b&=3; pbit->c|=1; printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c); } 上例程序中定义了位域结构bs,三个位域为a,b,c。说明了bs类型的变量bit和指向bs类型的指针变量pbit。这表示位域也是可以使用指针的。 
    程序的9、10、11三行分别给三个位域赋值。( 应注意赋值不能超过该位域的允许范围)程序第12行以整型量格式输出三个域的内容。第13行把位域变量bit的地址送给指针变量pbit。第14行用指针方式给位域a重新赋值,赋为0。第15行使用了复合的位运算符"&=", 该行相当于: pbit->b=pbit->b&3位域b中原有值为7,与3作按位与运算的结果为3(111&011=011,十进制值为3)。同样,程序第16行中使用了复合位运算"|=", 相当于: pbit->c=pbit->c|1其结果为15。程序第17行用指针方式输出了这三个域的值。 
    类型定义符typedef 
    C语言不仅提供了丰富的数据类型,而且还允许由用户自己定义类型说明符,也就是说允许由用户为数据类型取“别名”。 类型定义符typedef即可用来完成此功能。例如,有整型量a,b,其说明如下: int aa,b; 其中int是整型变量的类型说明符。int的完整写法为integer, 
    为了增加程序的可读性,可把整型说明符用typedef定义为: typedef int INTEGER 这以后就可用INTEGER来代替int作整型变量的类型说明了。 例如: INTEGER a,b;它等效于: int a,b; 用typedef定义数组、指针、结构等类型将带来很大的方便,不仅使程序书写简单而且使意义更为明确,因而增强了可读性。例如: 
    typedef char NAME[20]; 表示NAME是字符数组类型,数组长度为20。 
    然后可用NAME 说明变量,如: NAME a1,a2,s1,s2;完全等效于: char a1[20],a2[20],s1[20],s2[20] 
    又如: 
    typedef struct stu{ char name[20]; 
    int age; 
    char sex; 
    } STU; 
    定义STU表示stu的结构类型,然后可用STU来说明结构变量: STU body1,body2; 
    typedef定义的一般形式为: typedef 原类型名 新类型名 其中原类型名中含有定义部分,新类型名一般用大写表示, 以 
    便于区别。在有时也可用宏定义来代替typedef的功能,但是宏定义是由预处理完成的,而typedef则是在编译时完成的,后者更为灵活方便。 
    本章小结
    1. 枚举是一种基本数据类型。枚举变量的取值是有限的,枚举元素是常量,不是变量。 
    2. 枚举变量通常由赋值语句赋值,而不由动态输入赋值。枚举元素虽可由系统或用户定义一个顺序值,但枚举元素和整数并不相同,它们属于不同的类型。因此,也不能用printf语句来输出元素值(可输出顺序值)。 
    3. 位运算是C语言的一种特殊运算功能, 它是以二进制位为单位进行运算的。位运算符只有逻辑运算和移位运算两类。位运算符可以与赋值符一起组成复合赋值符。如&=,|=,^=,>>=,<<=等。 
    4. 利用位运算可以完成汇编语言的某些功能,如置位,位清零,移位等。还可进行数据的压缩存储和并行运算。 
    5. 位域在本质上也是结构类型,不过它的成员按二进制位分配内存。其定义、说明及使用的方式都与结构相同。 
    6. 位域提供了一种手段,使得可在高级语言中实现数据的压缩,节省了存储空间,同时也提高了程序的效率。 
    7. 类型定义typedef 向用户提供了一种自定义类型说明符的手段,照顾了用户编程使用词汇的习惯,又增加了程序的可读性

    展开全文
  • 结构体、联合体以及枚举类型是我们在学习C/C++中经常遇到的一些数据结构,接下来我们就来认识和区别一下他们。 结构体:(struct) 用途:把不同的数据组合成一个整体——自定义数据类型 C语言:在C语言中,...
  • 1.1.3 结构 1.1.3.0 结构的定义 结构是含有多个不同类型数据的数据结构。 struct { int a; char b }part1; 1.1.3.1 结构变量的初始化 1、 struct { int a; char b; }part1{1,'q'}; 2、指定初始化(c99) ...
  • 结构&联合&枚举

    2020-03-04 19:30:52
    结构 结构就是一种把数据项组合在一起的数据结构,在c语言中,进行组合的通常方法就是把需要组合的东西放在花括号里:{内容...}关键字struct放在左花括号前面,以便编译器能够从程序块中认出它: struct { ... }; ...
  • 结构体、联合、枚举

    2018-03-25 23:15:19
    结构的基础知识:结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 结构体也可以放数组 结构体地址:结构体第一个成员地址 结构体成员地址同数组也是递增的 struct tag(名称一般不...
  • 数据结构:八大数据结构分类

    万次阅读 多人点赞 2018-09-05 18:23:28
    数据结构分类 数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成 。 常用的数据结构有:数组,栈,链表,队列,树,图,堆,散列表等,如图所示: 每一种数据结构都...
  • 结构化数据、半结构化数据和非结构化数据

    万次阅读 多人点赞 2020-08-20 19:04:49
    结构化数据、半结构化数据和非结构化数据结构化数据结构化的数据是指可以使用关系型数据库表示和存储,表现为二维形式的数据。一般特点是:数据以行为单位,一行数据表示一个实体的信息,每一行数据的属性是相同的。...
  • 结构化数据和非结构化数据、半结构化数据的区别

    万次阅读 多人点赞 2019-06-15 22:27:41
    计算机信息化系统中的数据分为结构化数据和非结构化数据、半结构化数据。 结构化数据 结构化数据,是指由二维表结构来逻辑表达和实现的数据,严格地遵循数据格式与长度规范,主要通过关系型数据库进行存储和管理...
  • 关于结构化、半结构化、非结构化数据的理解

    万次阅读 多人点赞 2018-08-06 11:36:03
    记得在课上,老师说,结构化数据就是我们关系数据库里的表,剩下的都是半结构化和非结构化数据,好比XML文档就是半结构化数据,WORD文档就是非结构化数据,大数据就是半结构化和非结构化数据。心中一直有一个疑问?...
  • 数据结构和算法视频教程

    万人学习 2019-06-25 10:51:39
    数据结构、算法视频培训课程,该教程主要是介绍在游戏开发中经常使用的数据结构,例如数组,链表,栈,队列,二叉树,递归等重要知识点讲解以及将它们里灵活的运用到算法里面。
  • 数据结构与算法(java版)

    万次阅读 多人点赞 2018-04-22 17:18:08
    数据结构与算法(java版)标签: java 数据结构 算法2017年12月28日 21:50:08102人阅读 评论(0) ...(1)数据结构与算法概念解析 (2)数据结构之数组 (3)数据结构之栈 (4)数据结构之队列 (5)数据结...
  • oracle 查看表结构

    万次阅读 2019-04-16 15:09:31
    oracle 查看表结构 1.命令窗口:desc 表名 2.sql窗口:select * from user_tab_columns where table_name=‘大写表名’;
  • 线性结构和非线性结构

    万次阅读 多人点赞 2015-09-08 17:13:31
    线性结构是一个有序数据元素的集合。 其中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。 常用的线性结构有:线性表,栈,队列,双队列,数组,串。   ...
  • 以下数据结构中,()是非线性数据结构A:树(二叉树) B:字符串 C:队列 D:栈 E:线性表 F:二维数组 G:多维数组数据的逻辑结构分为线性结构和非线性结构。 常用的线性结构有:线性表,栈,队列,双队列,...
  • 程序设计的三种基本结构

    万次阅读 2017-02-24 11:48:08
    任何简单或者复杂的算法都可以由顺序结构、选择结构和循环结构这三种基本结构组合而成。所以这三种结构被称为程序设计的三种基本结构,也是程序化程序设计必须采用的结构。 顺序结构 图1 顺序结构 顺序结构...
  • 数据结构之逻辑结构与物理结构(存储结构

    万次阅读 多人点赞 2018-06-27 21:23:29
    1.逻辑结构:逻辑结构分为四种类型:集合结构,线性结构,树形结构,图形结构。1.1 所谓集合结构:表面意思,没有什么深刻意义,就是数据元素同属一个集合,单个数据元素之间没有任何关系。如下图所示。 1.2 线性...
  • 数据结构课程是计算机类专业的专业基础课程,在IT人才培养中,起着重要的作用。课程按照大学计算机类专业课程大纲的要求,安排教学内容,满足需要系统学习数据结构的人。系列课程包含11个部分,本课为第1部分,介绍...
1 2 3 4 5 ... 20
收藏数 5,270,764
精华内容 2,108,305
关键字:

结构