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

总结一下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. [springBoot系列]--spring-boot-devtools在Idea中热部署方法

    1 pom.xml文件 注:热部署功能spring-boot-1.3开始有的 <!--添加依赖--> <dependency> <groupId>org.sprin ...

  2. 流畅的python和cookbook学习笔记(八)

    1.函数的默认参数必须不可变 如果函数的默认参数为可变的对象,那么默认参数在函数外被修改也会影响到函数本身的. >>> def spam(a, b=None): # b要为不可变参数 ...

  3. OkHttp完全解析之整体调用流程

    前言:阅读好的代码如同观赏美景一样的美妙 OkHttp是一个Square公司在github开源的Java网络请求框架,非常流行.OkHttp 的代码并不是特别庞大,代码很多巧妙的实现,非常值得学习. ...

  4. linux 添加开机自启动脚本

    原文 Linux设置服务开机自动启动的方式有好多种,这里介绍一下通过chkconfig命令添加脚本为开机自动启动的方法. 1. 编写脚本autostart.sh(这里以开机启动redis服务为例),脚 ...

  5. JDBC编程错误:Exception in thread "main" java.sql.SQLException: Access denied for user ''@'localhost' (using password: YES)

    出现上面的错误是因为连接数据库的用户名不对或密码赋值不对,请对用户名和密码进行检查. 或者在程序中没有获取到正确的用户名或密码.看是否少写了用户名或密码.

  6. maven仓库中的LastUpdated文件删除脚本

    cleanLastUpdated.bat(windows版本) @echo off rem create by NettQun rem 这里写你的仓库路径 set REPOSITORY_PATH=D: ...

  7. jquery解析XML在IE7下不兼容的问题

    jquery在解析XML内容的时候在IE7下无法显示,是因为数据格式的问题,解决办法如下: $.ajax({        type:"POST",        url:&quo ...

  8. Navicat工具、pymysql模块

    一 IDE工具介绍(Navicat) 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具,我们使用Navicat工具,这个工具本质上就是一个socket客户端,可视化的连接m ...

  9. nodejs项目windows下开机自启动

    Nodejs项目开机自启动 1. 在需要自启动的项目中安装 node-windows 模块 npm install node-windows --save 2. 在项目根目录创建nw.js文件 代码截 ...

  10. arcMap 进度条

    private void kk() { IProgressDialogFactory progressDialogFactory = new ProgressDialogFactoryClass(); ...