先说句题外话,个人认为,基本上所有的高级语言被设计出来的最终目的是降低软件开发难度,提升软件开发人员素质和团队协作能力,降低软件维护的难度。在学习语言的时候,可以从这么方面来推测各种语言语法设计的原因,从来更好的掌握各种编程语言。

总结一下C语言中的数据类型结构:

1.常用基本数据类型(int, char, float, double, short, long等等)

2.数组

3.指针

4.枚举

5.结构体

6.公用体

...

这其中除了共用体不常用外,其他都是实际开发中经常用到的数据结构。其他的之前两篇都有说明,今天来说说枚举和结构体。

(初学者应该养成读代码从main开始读的习惯)

1.枚举

枚举作为一种数据类型,用于声明一组命名的常数,用来说明一种事物的不同类型或属性。实际应用作用的话,个人认为是提高代码的可读性,减小程序的维护难度。

举个例子,一个程序中需要使用变量表示颜色,那么写程序前我们需要先设定标准:0表示白色,1表示红色,2表示黄色,3表示蓝色...,那么程序代码如下:

 #include <stdio.h>
#include <stdlib.h> void printColor(int color)
{
switch (color)
{
case :
printf("白色\n");
break;
case :
printf("红色\n");
break;
case :
printf("黄色\n");
break;
case :
printf("蓝色\n");
break;
default:
break;
}
} int main(int arg, char *args)
{
int color0 = ; // 白色
int color1 = ; // 红色
int color2 = ; // 黄色
int color3 = ; // 蓝色 printColor(color0);
printColor(color1);
printColor(color2);
printColor(color3); getchar();
return ;
}

(关于枚举的例子只是作为说明,这些作为例子有些不太好)如果程序代码量很大的情况下,0,1,2,3的这种数字意义很容易忘记,这时可以用到枚举

 #include <stdio.h>
#include <stdlib.h> enum Color
{
White, // 白色
Red, // 红色
Yellow,// 黄色
Blue // 蓝色
}; void printColor(int color)
{
switch (color)
{
case White:
printf("白色\n");
break;
case Red:
printf("红色\n");
break;
case Yellow:
printf("黄色\n");
break;
case Blue:
printf("蓝色\n");
break;
default:
break;
}
}
int main(int arg, char *args)
{
int color0 = White; // 白色
int color1 = Red; // 红色
int color2 = Yellow; // 黄色
int color3 = Blue; // 蓝色 printColor(color0);
printColor(color1);
printColor(color2);
printColor(color3); getchar();
return ;
}

对枚举的理解应用暂时就如此,关于枚举的作为属性应用,以及其他方面的应用,有兴趣的可以查查其他资料。

2.结构体

结构体的意义之一同样是增加代码可读性。而且结构体配合指针使得C语言变得非常灵活。

结构体是由一系列具有相同或不同类型的数据组成。

下面用两种方法定义并输出一个学生的信息。

首先是不用结构体和枚举的方法

 #define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int getSex(short sex, char * sexVal)
{
if (sexVal == NULL)
{
return -;
}
switch (sex)
{
case :
strcpy(sexVal, "男");
break;
case :
strcpy(sexVal, "女");
break;
default:
return -;
break;
}
return ;
}
// 不用结构体和枚举的方法
int main(int arg, char * args[])
{
int num = ;
char name[] = "LiLei";
short sexN = ;
char sex[] = { '\0' };
if (getSex(sexN, sex) != )
{
return -;
}
printf("学号:%d,姓名:%s,性别:%s\n", num, name, sex); getchar();
return ;
}

下面使用结构体和枚举改造代码:

 #define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef enum _Sex
{
Male,
Female
}Sex; struct Student
{
int num;
char name[];
short sex;
}; int getSex(Sex sex, char * sexVal)
{
if (sexVal == NULL)
{
return -;
}
switch (sex)
{
case Male:
strcpy(sexVal, "男");
break;
case Female:
strcpy(sexVal, "女");
break;
default:
return -;
break;
}
return ;
} int main(int arg, char * args[])
{
struct Student stu = { , "LiLei", Male };
char sex[] = { };
if (getSex(stu.sex, sex) != )
{
return -;
}
printf("学号:%d,姓名:%s,性别:%s\n", stu.num, stu.name, sex);
getchar();
return ;
}

可以发现,在没有什么注释的情况下,从Main开始读代码,第二段代码是比较好理解。

使用结构体一般都会使用typedef给结构体起个别名,当然typedef在指针、数组等方面都有应用,使用typedef可以精简代码。下面举个例子

 #define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h> enum Sex
{
Male,
Female
}; typedef struct _Student
{
long num;
char name[];
short sex;
} Student; // 使用typedef给结构体起别名 int main(int arg, char * args[])
{
struct _Student stu1 = { , "hel", Male }; // 不使用typedef前的定义方式
Student stu2 = { , "yao", Male }; // 使用typedef的定义方式,主要是省去一个struct return ;
}

typedef的用法,先正常定义,然后用别名替代掉原变量(或函数名)名称的位置,如:

 #define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef int mI;
typedef char mCh;
typedef char mStr[];// 原来定义char数组是 char * str[32]; 这里将str替换为别名
typedef int (* name)(int a, int b); // int sum(int a, int b), 因为函数需要以指针形式表示,所以把sum替换为 * name int sum(int a, int b)
{
return a + b;
} int main(int arg, char *args[])
{
mI num = ;
mCh ch = 'x';
mStr str = "hello"; // 这里相当于定义 char str[32] = "hello";
name func = sum; // 函数指针,相当于 int func(int a, int b); func中的执行代码和sum函数相同
printf("num:%d,a=%c,str=%s,func(1, 2)=%d\n", num, ch, str, func(, ));
getchar();
return ;
}

再说说结构体的长度。结构体的长度要略大于或等于其内部成员的总长度。主要是为了程序速度,在一个结构体内有多个类型的成员的时候,会做一些“对齐”处理,该处理有可能导致结构体变量占用空间变大。

 #define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h> struct Student1
{
int num;
char name[];
short sex;
};
struct Student2
{
long long num;
char name[];
short sex;
}; int main(int arg, char * args[])
{
struct Student1 stu1;
struct Student2 stu2;
printf("int:%d, char:%d, short:%d, longlong:%d\n", sizeof(int), sizeof(char), sizeof(short), sizeof(long long)); // 比较4种数据类型的长度
printf("long:%d,int:%d\n", sizeof(struct Student2), sizeof(struct Student1)); // 比较两种结构体的长度
printf("stu1:%x,stu2:%x\n", &stu1, &stu2); // 两个结构体变量的地址
getchar();
return ;
}

上面这段程序的输出结构为:

int:, char:, short:, longlong:
long:,int:
stu1:eafeb4,stu2:eafe7c

从第一行输出信息来看,我们可以算出结构体Student1声明的变量(int num, char name[32], short sex)的总长度应该为38,而第二行的实际输出结果为40.

同样可以算出结构体Student2声明的变量(long long num, char name[32], short)的总长度应该为42,而实际结果为48.

一个结构体的长度必定是其内部长度最大基本数据类型元素的整数倍,上面Student1和Student2都符合该项(数组不是基本数据类型)。

而且结构体变量的首地址必定能被其内部长度最大基本数据类型元素整除,如上面eafeb4可以被4整除,eafe7c可以被8整除。

3.结构体的一点高级用法

1.通过地址取结构体内成员的值(代码作为示例,真实开发中应该不会这样写)

 #define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h> enum Sex
{
Male,
Female
}; struct Student1
{
int num;
char name[];
short sex;
};
struct Student2
{
long long num;
char name[];
short sex;
}; int main(int arg, char * args[])
{
char * stu1Name = NULL;
char * stu2Name = NULL;
struct Student1 stu1 = { , "LiLei", Male };
struct Student2 stu2 = { , "WaLiu", Female }; printf("int:%d, char:%d, short:%d, longlong:%d\n", sizeof(int), sizeof(char), sizeof(short), sizeof(long long)); // 比较4种数据类型的长度
printf("long:%d,int:%d\n", sizeof(struct Student2), sizeof(struct Student1)); // 比较两种结构体的长度
printf("stu1:%x,stu2:%x\n", &stu1, &stu2); // 两个结构体变量的地址
printf("stu1:%x,stu2:%x\n", &stu1 + , &stu2 + ); stu1Name = (char *)(((char *)&stu1) + ); // 取stu1的地址,向后偏移4位,这个地址就是name的首地址,将其赋给stu1Name
stu2Name = (char *)(((char *)&stu2) + ); // 取stu2的地址,向后偏移8位,这个地址就是name的首地址,将其赋给stu2Name printf("stu1:%s,stu2:%s\n", stu1Name, stu2Name); // 打印出值
getchar();
return ;
}

以上代码执行结构为:

int:, char:, short:, longlong:
long:,int:
stu1:107fdb0,stu2:107fd70
stu1:107fe50,stu2:107ff30
stu1:LiLei,stu2:WaLiu

这说明可以通过地址偏移的方式取得结构体变量内部的值。

C/C++心得-结构体的更多相关文章

  1. CAN编写完分帧发送, 分帧接收,J1939位域型结构体心得

    关于由多个不同的C文件构成的工程,我采用以下方法 以为400Hz数字电源程序为例 假设工程由以下文件组成 DC_Comm.c 主要完成串口通讯部分 DC_Config.c 主要完成时钟,外设 中断初始 ...

  2. c++ 数组 结构体

    接下来的一点时间我将会记录下我看的c++的一些心得体会,人贵在坚持,希望我可以一直坚持下去!!Go Fighting!   一.c++复合数据类型: 数组类型的一些注意事项: sizeof的用法: 当 ...

  3. 漫谈C语言结构体

    相信大家对于结构体都不陌生.在此,分享出本人对C语言结构体的学习心得.如果你发现这个总结中有你以前所未掌握的,那本文也算是有点价值了.当然,水平有限,若发现不足之处恳请指出.代码文件test.c我放在 ...

  4. 漫谈C语言结构体【转】

    相信大家对于结构体都不陌生.在此,分享出本人对C语言结构体的学习心得.如果你发现这个总结中有你以前所未掌握的,那本文也算是有点价值了.当然,水平有限,若发现不足之处恳请指出.代码文件test.c我放在 ...

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

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

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

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

  7. go语言结构体

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

  8. C语言中的结构体

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

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

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

随机推荐

  1. spring mvc 基本配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  2. nodejs中引入art-template模板

    使用Webstorm创建nodejs express应用时,默认使用的是jade或者ejs模板,对于不习惯这两种模板语法的人来说确实不是很方便.没关系,这里我们使用art-template模板引擎,使 ...

  3. VirtualBox使用Centos7与主机共享文件夹

    最近使用VitrtualBox安装Centos7学习,liunx脚本和一些命令,经过一些研究完成了虚拟机与 主机共享文件夹,虚拟机链接外部网络,主机与虚拟机互相通信.在其中遇到一些我解决的技术问题记录 ...

  4. 使用 WireShark 分析 TCP/IP 三次握手 和 四次挥手

    TCP 三次握手 示意图 Wireshark 抓包注意事项 为了演示一个TCP三次握手建立连接的过程,我们通过 Chrome 访问一个网页. 已知 HTTP 协议就是建立在TCP链接上的 比如访问以下 ...

  5. java设计模式之装饰者模式学习

    装饰者模式 Decorator模式(别名Wrapper):动态将职责附加到对象上,若要扩展功能,装饰者提供了比继承更具弹性的代替方案. 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为 ...

  6. flask接收前台的ajax的post数据

    html <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8& ...

  7. PL/SQL 快速连接数据库

    打开PL/SQL 登录窗口,在数据库地址写入 服务器名:端口号/sid 即可, 例如: 192.168.100.100:1521/test

  8. vue2.0中v-on绑定自定义事件的理解

    vue中父组件通过prop传递数据给子组件,而想要将子组件的数据传递给父组件,则可以通过自定义事件的绑定. 每个Vue实例都实现了[事件接口],即: 1.使用 $on(eventName) 监听事件 ...

  9. table中的td自动换行

    总有那么几个时候会觉得,table的td不能自适应换行真坑,凭什么只能用tr来换行,经常数据都是连在一起的呀,你叫我怎么把它拆分放到tr里...... 那能不能用ul和li来替换?可以是可以,不过有时 ...

  10. puppeteer自动化测试

    1.基础知识 puppeteer.launch() 创建浏览器实例 puppeteer.newPage() 创建一个新页面 puppeteer.goto() 进入指定网站 page.screensho ...