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

总结一下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. 常用工具说明--GitHub团队项目合作流程

    注:其中 零.一.七 是由团队项目负责人来完成的.开发人员只要从 二 开始就行了. 零.前期准备: 首先把队友直接push的权限关掉,即设置成Read.这样可以防止队友误操作,未经审核就把代码push ...

  2. 资料汇总--Java

    01.从零开始学springBoot 02.java资源大全中文版 03.谷歌 中国

  3. 封装常用的跨浏览器的事件对象EventUtil

    var EventUtil = { addHandler: function(element,type,handler) { //事件监听 if(element.addEventListener) { ...

  4. jQuery插件 -- UI插件Tabs Widget 1.10

    最近将tabs(标签页)整合到Admin LTE( 一个完全响应式管理模板,基于Bootstrap3的框架.)中使用.过程中走了不少弯路,原因是没有注意版本问题,jquery ui tabs 每次升级 ...

  5. [android] android项目架构

    准备步骤: 1.创建工程(设置版本兼容,最低兼容版本) 2.导入常用jar包,(处理字符串和加密用的jar文件) Commons Lang,Commons Codec commons-codec.ja ...

  6. TCP基础知识(三)重传、流量控制、拥塞控制

    TCP详解(3):重传.流量控制.拥塞控制…… 数据传输 在TCP的数据传送状态,很多重要的机制保证了TCP的可靠性和强壮性.它们包括:使用序号,对收到的TCP报文段进行排序以及检测重复的数据:使用校 ...

  7. hdu 4055 Number String(递推DP)

    给一个只含‘I','D','?'三种字符的字符串,I表示当前数字大于前面的数字,D表示当前的数字小于前面一位的数字,?表示当前位既可以小于又可以大于. 问1~n的排列中有多少个满足该字符串. http ...

  8. Linux服务器安装tomcat、JDK、SVN等常用开发软件总结

    本来本文发布到首页的,该网站运营人员移除了,说我这篇博文太简单了,如果感觉我这篇博文有用的,大家给个推荐,打一下运营人员的脸 目录 一.Ubuntu 16.04下安装JDK(spring 3.2不支持 ...

  9. ueditor PHP版本使用方法

    1.ueditor是百度很好用的一款文本编辑器,第一次使用,在此记录使用方法. 2.从http://ueditor.baidu.com/website/download.html#ueditor下载e ...

  10. 微信小程序中使用wxParse展示HTML内容

    wxParse的GitHub地址:https://github.com/icindy/wxParse 一.数据内容: 请求地址:https://m.quanchepin.com/index.php?a ...