什么时候用得到结构体数组

目录

为什么要写这篇

为什么要用结构体数组

什么时候用得到结构体数组

C代码实现运用结构体数组

程序运行结果

达到预期目的

程序优化

程序优化后源代码


为什么要写这篇

近期一直在看C Primer Plus,对于C语言的掌握能力有了显著提升,运用也更灵活。因此对C语言刷新的认知是:C语言是把刻刀。同时在 “习以为常” 之前记录一下成长:成长中实践

编译出错,语义错误什么的不再是简单的认为改改就好,问题解决能用就行,而成了如何用好C语言,少犯一些低级错误。为什么觉得错误低级,又为什么觉得是C语言是刻刀?因为工具参考书就在那里,写得明明白白。不去使用手册,遇到问题不从自身找原因,而是吃一堑长一智,这种做法,前期可行,但想一直用下去,永远无法对C语言掌握透彻,永远不会觉得这只是一个工具(刻刀)。而且不看C语言的书籍,不会清楚明白C语言和其它编程语言的界限在哪里。更别提以他山之石,攻己之玉。

为什么要用结构体数组

对于结构体数组,前些天有个同事说链表真好用,他的关注点是插入排序(用于对蓝牙设备顺序存入,然后将新的蓝牙设备按照接收灵敏度插入到链表中,既完成了存入,又完成了排序)。因为他是第一次用链表,表述成了链表排序真好用,当时我说的是用结构体数组应该更好一些吧,数组的排序要比链表快吧(回头查了一下链表的插入排序与数组的冒泡排序或快速排序 的对比)。我却劝别人用,但自己还没用过结构体数组,因此在心里留下了个结,一直想着解开这个结。

什么时候用得到结构体数组

后来一个灯板的电路进行了更改,选择的芯片引脚不够控制那么多RGB灯,就用上了74HC595芯片(串转并)。关于74HC595想了解的可以看一下这篇文章:74HC595引脚图详解

一开始没有想到更改硬件之后会对原来的功能产生影响,认为只需要把RGB灯控制部分的程序更改为用74HC595控制就好了,但后来发现个问题。

之前RGB灯的七种颜色控制是直接用红、绿、蓝颜色的灯亮灭来拼出来的,控制红、绿、蓝颜色灯的引脚高低就可以控制灯颜色,程序的实现并非用宏定义常量来标识要显示的颜色,而是通过枚举类型的常量来表示颜色。当常量要控制的颜色修改时,只需修改枚举类型的颜色标识符顺序(标识符还是那个标识符,但对应的常量值变了),而无需修改程序内部逻辑。

但换成74HC595后,红绿蓝颜色灯的引脚不能单独控制了,而是通过按位输入到74HC595。一次性控制多个RGB灯,要还是用这种switch...case的方式,情况是多个灯的情况, 比如红红红 是一种case, 红红黄是一种case, 如果是3个灯的话7*7*7 = 343 个case分支,灯越多case分支越多。因此需要一种新的方式实现:设置颜色控制颜色 相分离,即标记颜色的常量(设置颜色的常量)控制颜色的常量无关。

分离后,如果使用switch...case方式,仍然可以是七八个case分支(case 是设置颜色,具体执行的case分支是将控制颜色存入某个变量),最后将几个灯控制颜色的变量拼接起来按位送入74HC595。但这样无形中引入了新的问题,硬件更改,这个switch...case函数也得更改,从我的理解角度来说,硬件更改,只是数据发生了变动,又不是有了新的需求,程序实现逻辑不该发生改动

设置颜色 控制颜色 相关的变量并不用函数来将其关联,而是通过某种数据结构,这种数据结构要能表示这种关联 的 集合。这时候就想到结构体数组了。

C代码实现运用结构体数组

程序运行结果

达到预期目的

之后要修改常量对应的颜色只需修改枚举类型 rgb_color(标记颜色的常量(设置颜色的常量))的标识符顺序就可以啦, 硬件电路有修改只需要更改total_color数组每一项的set_color值就可以啦。

程序优化

访问结构体数组的函数使用顺序查找是比较低效的,因为结构体数组在迁就(设置颜色的常量),数组最好的访问方式不是通过顺序查找,而是使用下标直接访问到数组元素,此时时间复杂度为O(1)。

结构体数组的每一项下标是固定的(0,1,2  ...),只是每一项的结构体的成员变量可能发生改变,导致设置颜色的常量与结构体数组的下标值不相等。若按照标记颜色的常量(设置颜色的常量) 由小到大进行排序,只需初始化时进行一次,使其与结构体的下标相对应,之后就可以通过下标直接访问结构体另一项成员变量了。

优化后访问结构体数组函数

程序优化后源代码

下面是改进后的测试程序,可以直接在菜鸟C在线工具运行。

此处对排序的使用还是基于之前的架构,交换的函数有所不同,冒泡排序的实现和以前也有所不同,感兴趣的小伙伴可以拿这篇文章对照下:把数据滤波写成不明觉厉的样子

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>


#define DEBUG_OUTPUT 		1

typedef struct color_set
{
	uint8_t color;
	uint8_t set_color;
}COLOR_SET;

enum rgb_color        ///< 为测试而修改
{
	NO_COLOR = 0,
	PURPLE,
	RED,	
	GREEN,
	BLUE,
	WHITE,
	YELLOW,
	CHING,
};

COLOR_SET total_color[8] =
{
	{NO_COLOR, 0},
	{RED, 1},
	{YELLOW, 3},
	{GREEN, 2},
	{CHING, 6},
	{BLUE, 4},
	{PURPLE, 5},
	{WHITE, 7}
};



typedef void (*Exchange_Func)(void *, void *);

 uint8_t _74HC595_set_color(uint8_t color);
 void struct_binary_exchange(void* num1, void* num2);
 void bubble_sort(void * buf, uint16_t num, uint8_t size, Exchange_Func operator_func);
 uint8_t _74HC595_set_color_Init(void);

/**
 * _74HC595_set_color
 * @brief 	得到74HC595实际输出的值
 * @param	要设置的颜色对应的常量color_set.color
 * @return 	转换成要设置的颜色对应值 color_set.set_color
 */
 uint8_t 
 _74HC595_set_color(uint8_t color)
 {
#if DEBUG_OUTPUT
	printf("output color is: %d", total_color[color].set_color);
#endif
	return total_color[color].set_color;
 }

/**
 * uint8_t_binary_exchange
 * @brief 设计判断条件交换两数在数组中的位置
 * @param	num1 按照uint8_t类型进行处理
 * @param 	num2 按照uint8_t类型进行处理
 * @retval	None
 * @note	将 > 改为 < 即由递增序列变为递减序列
 */
void 
struct_binary_exchange(void* num1, void* num2)
{
	if((*(COLOR_SET *)num1).color > (*(COLOR_SET *)num2).color)
	{
		COLOR_SET temp = *(COLOR_SET *)num1;
		*(COLOR_SET *)num1 = *(COLOR_SET *)num2;
		*(COLOR_SET *)num2 = temp;
	}else
	{
		/* no code */
	}
}

/**
 * bubble_sort
 * @brief 	冒泡排序法,为处理不同数据准备的框架
 * @details 使用回调函数来实现只改底层,不动上层的分层思想
 * @param	buf 数组首地址,void* 修饰,表示任意类型传入
 * @param	num 数组大小,通常用sizeof(buf)/sizeof(buf[0]) 来得到
 * @param	size 要处理的数据类型占用字节数,通常用sizeof(buf[0]) 来得到
 * @param	operator_fuc 函数指针,用于调用相应函数实现功能
 * @retval 	None
 * @note	为功能测试而通过宏切换验证
 */
void 
bubble_sort(void * buf, uint16_t num, uint8_t size, Exchange_Func operator_func)
{
	uint16_t ex_cycle_i, in_cycle_j;
 
	if(size == 0 || size > 16)
	{
		printf("please check input data type size !\n");
		return;
	}else
	{
		for(ex_cycle_i = 0; ex_cycle_i < num - 1; ex_cycle_i++)
		{
			for(in_cycle_j = ex_cycle_i + 1; in_cycle_j < num; in_cycle_j++)
			{
				operator_func(buf + size*ex_cycle_i, buf + size*in_cycle_j);
			}
		}
	}
}

/**
 * _74HC595_set_color_Init
 * @brief 	将用于74HC595的数组排序
 * @note 	对于频繁调用的函数_74HC595_set_color 减轻工作量
 */ 
uint8_t 
_74HC595_set_color_Init(void)
{
#if DEBUG_OUTPUT
	printf("origin data is :\n");
	for(uint8_t i=0; i<8; i++)
	{
		printf("total_color[%d].color = %d, total_color[%d].set_color = %d \n", i, total_color[i].color, i, total_color[i].set_color);
	}
#endif
	bubble_sort((void *)total_color, sizeof(total_color)/sizeof(total_color[0]), sizeof(total_color[0]), struct_binary_exchange);
#if DEBUG_OUTPUT
	printf("sort data is :\n");
	for(uint8_t i=0; i<8; i++)
	{
		printf("total_color[%d].color = %d, total_color[%d].set_color = %d \n", i, total_color[i].color, i, total_color[i].set_color);
	}
	printf("\n");
#endif
}

int main(void)
{
	_74HC595_set_color_Init();

#if DEBUG_OUTPUT
	srand((unsigned)time(NULL));
	uint8_t random_val = rand() % 7 + 1;
	printf("random_val is %d \n", random_val);
	_74HC595_set_color(random_val);
#endif

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值