结构体(struct)

从某种意义上说,会不会使用struct,如何使用struct是区别一个开发人员是否具备丰富开发经验的试金石。

处理由不同类型成员构成的构造类型,要采用结构体的方式。

定义:关键字struct.

无名结构体,一般用于定义类型相同时,定义变量;并且不会带来多余的命名。

  1. struct{
  2. char name[40];
  3. int age;
  4. int num;
  5. float score;
  6. }s1,s2,s3,s4;
  7. int main() {
  8. struct{
  9. char name[40];
  10. int age;
  11. int num;
  12. float score;
  13. }s1;
  14. ....
  15. return 0;
  16. }

有名结构体

一处定义各处使用

  1. struct stu{
  2. char name[40];
  3. int age;
  4. int num;
  5. float score;
  6. }
  7. int main() {
  8. struct stu s1;
  9. struct stu s2;
  10. struct stu s3;
  11. return 0;
  12. }

typedef

对现有类型取别名,不能创造新的类型(typerename)。

使用方法:

1.先用原类型定义变量

2.在定义前加上typedef

3.将原来的名字改成自己需要的类型名

  1. typedef char int8;
  2. typedef short int16;
  3. typedef int int32;
  4. typedef long long int64;
  5. int main() {
  6. int8 i8;
  7. int16 i16;
  8. int32 i32;
  9. int64 i64;
  10. return 0;
  11. }

别名结构体

typedef是一个常用于对结构体取别名的关键字,更好的用于结构体中

  1. typedef struct{
  2. char name[40];
  3. int age;
  4. int num;
  5. float score;
  6. }Stu;
  7. int main() {
  8. Stu s1;
  9. Stu s2;
  10. Stu s3;
  11. }

typedef与#define区别

typedef:构成c语言语句参与编译。

#define构成的语句在预处理阶段处理完毕

  1. #fefine DINT int
  2. int main() {
  3. DINT a,b,c;//所有声明时要替换。
  4. }
  1. int main() {
  2. char *p,q;
  3. printf("sizeof(p) = %d sizeof(q) = %d\n",sizeof(p),sizeof(q));//4,1
  4. typedef char * pChar;
  5. pChar a,b;
  6. printf("sizeof(a) = %d sizeof(b) = %d\n",sizeof(a),sizeof(b));//4,4
  7. #define DpChar char *
  8. DpChar m,n;//<=>char * m,n;
  9. printf("sizeof(m) = %d sizeof(n) = %d\n",sizeof(m),sizeof(n));//4,1
  10. return 0;
  11. }

struct的初始化

凡是基本类型,既可以在定义的时候初始化,也可以先定义再赋值。

凡是构造类型,要么在定义的时候初始化,不可以先定义再以实例化的方式赋值。

初始化是一种特殊的语法,跟赋值不等价。

成员赋值,不能已初始化的方式赋值(如数组,字符串等)

  1. struct stu{
  2. char name[100];
  3. int num;
  4. char sex;
  5. float score;
  6. }
  7. int main() {
  8. struct stu s = {"assassin",10001,'f',99};
  9. //也可以这样赋值
  10. /*
  11. struct stu s;
  12. s.name = "assassin";//错误的,赋值不能这样写,和初始化有区别
  13. strcpy(s.name,"assassin");
  14. s.num = 1001;
  15. ...
  16. */
  17. return 0;
  18. }
  1. struct stu{
  2. char name[100];
  3. int num;
  4. char sex;
  5. float score;
  6. }
  7. int main() {
  8. struct stu s;
  9. scanf("%s%d %c%f\n",s.name,&s.num,&s.sex,&s.score);//其中s.name,name是个数组,数组时个特殊的指针,所以前面不用取址符。&的优先级低于"."的优先级。
  10. return 0;
  11. }

struct的访问

一类是访问栈上的,一类是访问堆上的。(点乘员运算符,指向成员运算符)

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. struct stu{
  4. char name[100];
  5. int num;
  6. char sex;
  7. float score;
  8. };
  9. int main() {
  10. struct stu s = {"assassin",10001,'f',99};
  11. struct stu *pa = &s;
  12. //点乘运算访问
  13. printf("name = %s\n",(*pa).name);
  14. printf("num = %d\n",(*pa).num);
  15. printf("sex = %c\n",(*pa).sex);
  16. printf("score = %f\n",(*pa).score);
  17. printf("======================\n");
  18. printf("name = %s\n",s.name);
  19. printf("num = %d\n",s.num);
  20. printf("sex = %c\n",s.sex);
  21. printf("score = %f\n",s.score);
  22. //足以说明*pa <=> s
  23. //"."点乘优先级高于"*"解引用运算符
  24. printf("======================\n");
  25. //指向成员访问
  26. printf("name = %s\n",pa->name);
  27. printf("num = %d\n",pa->num);
  28. printf("sex = %c\n",pa->sex);
  29. printf("score = %f\n",pa->score);
  30. return 0;
  31. }
  32. /*
  33. name = assassin
  34. num = 10001
  35. sex = f
  36. score = 99.000000
  37. ======================
  38. name = assassin
  39. num = 10001
  40. sex = f
  41. score = 99.000000
  42. ======================
  43. name = assassin
  44. num = 10001
  45. sex = f
  46. score = 99.000000
  47. */

堆上的访问

  1. typedef struct stu{
  2. char name[100];
  3. int num;
  4. char sex;
  5. float score;
  6. }Stu;
  7. int main() {
  8. Stu *pa = (Stu*)malloc(sizeof(Stu));
  9. strcpy(pa->name,"assassin");//赋值
  10. pa->num = 10001;
  11. pa->sex = 'f';
  12. pa->score = 99;
  13. printf("name = %s\n",pa->name);
  14. printf("num = %s\n",pa->num);
  15. printf("sex = %s\n",pa->sex);
  16. printf("score = %s\n",pa->score);
  17. free(pa);
  18. return 0;
  19. }
  20. /*
  21. name = assassin
  22. num = 10001
  23. sex = f
  24. score = 99.000000
  25. */

struct赋值

相同结构体类型的变量间,可以赋值。不同类型不可以。词语发基础奠定了可以用与传参和返值。

  1. typedef struct stu{
  2. char name[100];
  3. int num;
  4. char sex;
  5. float score;
  6. }Stu;
  7. int main() {
  8. Stu s;
  9. Stu s2 = {"assassin",1003,'f',99};
  10. s = s2;
  11. printf("%s %d %c %f\n",s.num,s.num,s.sex,s.score);//是可以赋值的
  12. return 0;
  13. }

结构体支持赋值,访问和数组一样

  1. typedef struct _stu{
  2. char name[10];
  3. }Stu;
  4. typedef struct _array{
  5. int arr[10];
  6. }Array;
  7. int main() {
  8. int arr[10] = {1,2,23,4,5,6,78,};
  9. int arr2[10];
  10. arr2 = arr;//error
  11. Stu stu1 = {"assassin"};
  12. Stu stu2;
  13. stu2 = stu1;//正确
  14. Array arr3 = {1,2,23,4,5,6,7,8};
  15. Array arr4;
  16. arr4 = arr3;//和上面有区别
  17. for(int i = 0;i<10;i++) {
  18. printf("%d\n",arr4.arr[i]);
  19. }
  20. }

传参和返回值的本质就是依次赋值

  1. typedef struct _complex{
  2. float real;
  3. float image;
  4. }MyComplex;
  5. //实现一个函数,实现两个负数相加
  6. MyComplex addComplex(MyComplex x,MyComplex y) {
  7. MyComplex t;
  8. t.real = x.real + y.real;
  9. t.image = x.image + y.image;
  10. return t;
  11. }
  12. int main() {
  13. MyComplex c1 = {1,2};
  14. MyComplex c2 = {3,4};
  15. MyComplex retc = addComplex(c1,c2);
  16. printf("(%.2f,%.2f)\n",retc.real,retc.image);
  17. return 0;
  18. }
  19. //(4.00,6.00)

C语言对于数组的处理就是指针,对于结构体也推荐传指针。(即使有很大的数据,只传4个字节,而且效率提高了很大)

  1. typedef struct _complex{
  2. float real;
  3. float image;
  4. }MyComplex;
  5. //实现一个函数,实现两个负数相加
  6. MyComplex addComplex(MyComplex *px,MyComplex *py) {
  7. MyComplex t;
  8. t.real = px->real + py->real;
  9. t.image = px->image + py->image;
  10. return t;
  11. }
  12. int main() {
  13. MyComplex c1 = {1,2};
  14. MyComplex c2 = {3,4};
  15. MyComplex retc = addComplex(&c1,&c2);
  16. printf("(%.2f,%.2f)\n",retc.real,retc.image);
  17. return 0;
  18. }
  19. //效率大大提高

结构体数组

结构体数组的本质:是一维数组,只不过是一维数组中的每一个个成员又是结构体。

  1. typedef struct _stu{
  2. int num;
  3. char name[100];
  4. char sex;
  5. float score;
  6. }Stu;
  7. int main() {
  8. Stu s[] = {{1001,"assassin",'f',99},{1002,"Wunworld",'f',89},{1003,"seafwg"},{1004,"intelwisd"}};
  9. for(int i = 0;i < sizeof(s)/sizeof(*s);i++) {
  10. printf("num = %d\n",s[i].num);
  11. printf("name = %s\n",s[i].nam);
  12. printf("sex = %c\n",s[i].sex);
  13. printf("score = %f\n",s[i].score);
  14. }
  15. }

实例投票:现有三位侯选人员,侯选人包含名字和选票数两项,现在 10 人对其投票,每个人限投票一次,投票完毕,打印投票结果,如有名字打错,算作弃权处理。

  1. typedef struct _candidate{
  2. char name[30];
  3. int voteCount;
  4. }Candidate;
  5. void disCandidate(Candidate *c,int n,int m);
  6. int main() {
  7. //初始化候选人
  8. Candidate can[3] = {
  9. {"assassin",0},
  10. {"wunworld",0},
  11. {"seafwg",0}
  12. };
  13. int count = 0;
  14. char buf[1024];
  15. //是个人选举
  16. for(int i = 0;i < 10;i++) {
  17. printf("请你选举自己心中的候选人");
  18. scanf("%s",buf);
  19. int flag = 1;
  20. for(int j = 0;j < 3;j++) {
  21. if(!strcmp(buf,can[j].name)) {
  22. can[j].voteCount++;
  23. flag = 0;
  24. }
  25. }
  26. if(flag != 0) {
  27. count++;
  28. }
  29. }
  30. disCandidate(can,3,count);
  31. }
  32. //显示选举后的选票人
  33. void disCandidate(Candidate *c,int n,int count) {
  34. for(int i = 0;i < n;i++) {
  35. printf("Name:10%s VoteCount:%2d\n",c[i].name,c[i].voteCount);
  36. }
  37. printf("the give up people: %d\n",count);
  38. //进行排序
  39. int idx = 0;
  40. for(int i = 0;i < n;i++) {
  41. if(c[i].voteCount > c[idx].voteCount) {
  42. idx = i;
  43. }
  44. }
  45. printf("恭喜%s获得了选举!\n",c[idx].name);
  46. }

结构体的嵌套

  1. struct _birth {
  2. int year;
  3. int month;
  4. int day;
  5. };
  6. typedef struct _stu {
  7. char name[20];
  8. int num;
  9. char sex;
  10. float score;
  11. struct _birth birth;
  12. //<=>
  13. /*struct _birth {
  14. int year;
  15. int month;
  16. int day;
  17. }birth;*/
  18. }Stu;
  19. int main() {
  20. Stu s = {"assassin",10001,'f',99,{1992,04,15}};
  21. printf("name = %s\n",s.name);
  22. printf("year = %d\n",s.birth.year);
  23. printf("month = %d\n",s.birth.month);
  24. printf("day = %d\n",s.birth.day);
  25. }
  26. /*
  27. name = assassin
  28. year = 1992
  29. month = 4
  30. day = 15
  31. */

结构体类型的大小

类型本身不占空间,类型产生的变量才占空间

结构体中的每个成员的地址均是可以获得的。

  1. typedef struct _staff{
  2. char sex;
  3. int age;
  4. }Staff;
  5. int main() {
  6. Satff s;
  7. printf("sizeof(Staff) = %d\n",sizeof(Staff));
  8. printf("sizeof(s) = %d\n",sizeof(s));
  9. printf("&s = %p\n",&s);
  10. printf("&s.sex = %p\n",&s.sex);
  11. printf("&s.age = %p\n",&s.age);
  12. return 0;
  13. }
  14. /*
  15. sizeof(Staff) = 8
  16. sizeof(s) = 8
  17. &s = 0061FEA8
  18. &s.sex = 0061FEA8
  19. &s.age = 0061FEAC
  20. */
  1. typedef struct _staff{
  2. char sex;
  3. int age;
  4. short like;
  5. }Staff;
  6. int main() {
  7. Staff s;
  8. printf("sizeof(Staff) = %d\n",sizeof(Staff));
  9. printf("sizeof(s) = %d\n",sizeof(s));
  10. printf("&s = %p\n",&s);
  11. printf("&s.sex = %p\n",&s.sex);
  12. printf("&s.age = %p\n",&s.age);
  13. printf("&s.like = %p\n",&s.like);
  14. return 0;
  15. }
  16. /*
  17. sizeof(Staff) = 12
  18. sizeof(s) = 12
  19. &s = 0061FEA4
  20. &s.sex = 0061FEA4
  21. &s.age = 0061FEA8
  22. &s.like = 0061FEAC
  23. */

为什么结构体里面的char,short是4个字节

sex后面空了三个字节,然后去填age,like后面空了两个字节,sex与age直接空了三个字节。like应该填到那个位置。

内存对齐

一个成员变量需要多少个机器周期去读的现象,称为内存不对齐。x实现内存对齐主要原因是牺牲空间换取时间的方法。

对齐规则

x86linux默认#pragma(4),window默认#pragma pack(8)。linux最大支持4字节对齐。

方法:

1.取pack(n)的值(n=1 2 4 8--),去结构体中类型最大值m,两者取小即为外对齐 大小Y=(m<n?m:n);

2.将每一个结构体的成员大小与Y比较取较小者为X作为内对其的大小。

3.所谓按X对齐,即为地址(设起始地址为0)能被X整除的地方开始存放数据。

4.外部对其原则是依据Y的值(Y的最小整数倍),进行补空操作。

例如:以上述为例

  1. typedef struct _staff{
  2. char sex;
  3. short num;
  4. int age;
  5. }Stu;
  1. 1.外对齐:pack(8)默认为8 n=8,则按照1m=4,即Y=4,----外对齐。(sexage直接空了三个字节)
  2. 2.内对齐:上述Y=4,与成员大小1,2,4比较取小值(x=1,2,4)---内对齐
  3. 3.按照X对齐:
  4. 0-1 2-4 4-8-----8(外侧是Y的最小整数倍补齐)
  5. 例如:成员大小1,4,2比较后(X=1,4,2)则:
  6. 0-1 4-8 8-10(10不是Y的最小整数倍取12)---大小为12
  7. eg:pack(1), n=1,m=4,Y=1,
  8. 成员:1 4 2,则X=1 1 1,
  9. 外对齐:0-1 1-5 5-7(71的倍数)---大小为7

eg:

  1. #pragma pack(4)
  2. typedef struct _stu{
  3. char sex;
  4. double num;
  5. int age;
  6. }Stu;
  7. int main() {
  8. printf("sizeof(Stu) = %d\n",sizeof(Stu));
  9. }
  10. /*
  11. sizeof(Stu) = 16
  12. sizeof(s) = 16
  13. */
  14. /*pack(4),n=4,m=8--->Y=4
  15. 成员:1 8 4与Y比较取小者X=1 4 4
  16. 0-1 4(能与X整除放成员个大小)-12 12-16-----大小为16
  17. */

结构体注意事项

  1. typedef struct _stu{
  2. char name[20];
  3. int score;
  4. }Stu;
  5. int main() {
  6. Stu s;
  7. strcpy(s.name,"bob");
  8. s,score = 99;
  9. }
  1. typedef struct _stu{
  2. char *name;
  3. int score;
  4. }Stu;//只有8个字节,name未初始化
  5. int main() {
  6. Stu s;
  7. strcpy(s.name,"bob");//Error 会挂机
  8. s.name = (char*)malloc(100);//解决办法放在堆上
  9. strcpy(s.name,"jim");
  10. printf("name = %s score = %d\n",s.name,s.score);
  11. free(s.name);//必须要释放
  12. s.score = 99;
  13. }

申请空间的时候从外至内,释放空间的时候从内之外。

  1. typedef struct _stu{
  2. char *name;
  3. int score;
  4. }Stu;//只有8个字节,name未初始化
  5. int main() {
  6. Stu *ps = (Stu *)malloc(sizeof(Stu));//ps实在栈上申请了8,结构体在堆上,没有初始化。并没有指向。解决办法,再次申请一个堆空间存放地址
  7. ps->name = (char*)malloc(100);
  8. strcpy(ps->name,"assassin");
  9. ps->score = 200;
  10. printf("name = %s score = %d\n",ps->name,ps->score);
  11. free(ps->name);//
  12. free(ps);
  13. return 0;
  14. }

数据类型:内存是以字节为单位进行线性编址的硬件基础,对内存进行格式化。

C/C++(结构体)的更多相关文章

  1. Go结构体实现类似成员函数机制

    Go语言结构体成员能否是函数,从而实现类似类的成员函数的机制呢?答案是肯定的. package main import "fmt" type stru struct { testf ...

  2. C#基础回顾(二)—页面值传递、重载与重写、类与结构体、装箱与拆箱

    一.前言 -孤独的路上有梦想作伴,乘风破浪- 二.页面值传递 (1)C#各页面之间可以进行数据的交换和传递,页面之间可根据获取的数据,进行各自的操作(跳转.计算等操作).为了实现多种方式的数据传递,C ...

  3. go语言结构体

    定义: 是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体. 成员: 每个值称为结构体的成员. 示例: 用结构体的经典案例处理公司的员工信息,每个员工信息包含一个唯一的员工编号.员工的名字. ...

  4. C语言中的结构体

    用户自己建立自己的结构体类型 1.  定义和使用结构体变量 (1).结构体的定义 C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体. (2).声明一个结构体类型的一般形式为: ...

  5. C++_系列自学课程_第_12_课_结构体

    #include <iostream> #include <string> using namespace std; struct CDAccount { double bal ...

  6. java socket传送一个结构体给用C++编写的服务器解析的问题

    另一端是Java写客户端程序,两者之间需要通信.c++/c接收和发送的都是结构体,而Java是直接发送的字节流或者byte 数组.解决方法:c++/c socket 在发送结构体的时候其实发送的也是字 ...

  7. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  8. HDOJ 1009. Fat Mouse' Trade 贪心 结构体排序

    FatMouse' Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  9. C语言结构体对齐

    1.结构体变量中的元素如何访问? (1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式):实质上都是指针方式访问.(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来 ...

  10. C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用

    类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...

随机推荐

  1. <Sicily>Fibonacci

    一.题目描述 In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn-1 + Fn-2 for n ≥ 2. For exampl ...

  2. mongodb 的查询深入剖析

           db.表名.find({goods_id:3});                     //查询出 goods_id 为 3 的数据        db.表名.find({cat_i ...

  3. 巧用MAC地址表

    对于身处网络环境的人来说,不少朋友应该遇到过这种的情况:某一个终端找不到接在了哪一个交换机口上,也不知道数据包怎样走的. ok,那么这时候MAC地址表就作用了,拿下图的实验环境(H3C)来说好了 环境 ...

  4. Varnish 问题点 与 技术方案 Varnish 优劣分析

      A10 有没有能做热点统计   1 Varnish 分布式 HA  (目前没有HA) 2 Varnish 热点监控     (建议热点需要外部插件统计,API的话目前并木有发现,但是他自带一个伪热 ...

  5. Varnish 缓存加速, Varnish 菜鸟看过来,Varnish实战

    Varnish可以有效降低web服务器的负载,提升访问速度.按照HTTP协议的处理过程,web服务器接受请求并且返回处理结果,理想情况下服务器要在不做额外处理的情况下,立即返回结果,但实际情况并非如此 ...

  6. 【LeetCode-面试算法经典-Java实现】【057-Insert Interval(插入区间)】

    [057-Insert Interval(插入区间)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a set of non-overlapping in ...

  7. 一种提高单片机i/o口驱动能力的方法

    一.简述问题 当你用单片驱动发光二极管的时,你还感觉不到P0.P1口的差别.(10-20mA之间,当中P0驱动能力最强,但对于驱动直流电机依旧非常弱.其结果就是电机不转).那么有什么办法提高驱动能力吗 ...

  8. Delphi新语法 For ..In

    首先我们要知道哪些类型可以用For In吧,下面就是: for Element in ArrayExpr do Stmt;      数组 for Element in StringExpr do S ...

  9. android学习笔记五。2、其他组件

    一.ContentProvider内容提供者.是是android中一个应用向第三方共享数据的方式,android中的联系人,sms(短信记录)等都是通过这一方式来向外提供的 1.使用: 在应用中使用C ...

  10. 【js基础】判断是否是合法邮箱地址(正则表达式的应用)

    2019-01-21 09:11:21 <!DOCTYPE html> <html> <head> <meta charset="utf-8&quo ...