C语言——结构体数组

简介: 结构体数组

目录

为什么要写这篇

为什么要用结构体数组

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

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个灯的话777 = 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

typedefstructcolor_set

{

   uint8_tcolor;

   uint8_tset_color;

}COLOR_SET;

enumrgb_color        ///< 为测试而修改

{

   NO_COLOR=0,

   PURPLE,

   RED,    

   GREEN,

   BLUE,

   WHITE,

   YELLOW,

   CHING,

};

COLOR_SETtotal_color[8] =

{

   {NO_COLOR, 0},

   {RED, 1},

   {YELLOW, 3},

   {GREEN, 2},

   {CHING, 6},

   {BLUE, 4},

   {PURPLE, 5},

   {WHITE, 7}

};

typedefvoid (*Exchange_Func)(void*, void*);

uint8_t_74HC595_set_color(uint8_tcolor);

voidstruct_binary_exchange(void*num1, void*num2);

voidbubble_sort(void*buf, uint16_tnum, uint8_tsize, Exchange_Funcoperator_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_tcolor)

{

#if DEBUG_OUTPUT

   printf("output color is: %d", total_color[color].set_color);

#endif

   returntotal_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_SETtemp=*(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_tnum, uint8_tsize, Exchange_Funcoperator_func)

{

   uint16_tex_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_ti=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_ti=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

}

intmain(void)

{

   _74HC595_set_color_Init();

#if DEBUG_OUTPUT

   srand((unsigned)time(NULL));

   uint8_trandom_val=rand() %7+1;

   printf("random_val is %d \n", random_val);

   _74HC595_set_color(random_val);

#endif

   return0;

}

目录
相关文章
|
2月前
|
存储 C语言 C++
【C语言数组】
【C语言数组】
|
23天前
|
存储 编译器 C语言
【C语言基础考研向】09 一维数组
数组是一种有序集合,用于存储相同类型的数据,便于统一操作与管理。例如,将衣柜底层划分为10个格子存放鞋子,便于快速定位。在C语言中,数组定义格式为 `类型说明符数组名[常量表达式];`,如 `int a[10];` 表示定义了一个包含10个整数的数组。数组初始化时可以直接赋值,也可以部分赋值,且数组长度必须固定。数组在内存中连续存储,访问时需注意下标范围,避免越界导致数据异常。数组作为参数传递时,传递的是首地址,修改会影响原数组。
|
23天前
|
存储 C语言
【C语言基础考研向】10 字符数组初始化及传递和scanf 读取字符串
本文介绍了C语言中字符数组的初始化方法及其在函数间传递的注意事项。字符数组初始化有两种方式:逐个字符赋值或整体初始化字符串。实际工作中常用后者,如`char c[10]=&quot;hello&quot;`。示例代码展示了如何初始化及传递字符数组,并解释了为何未正确添加结束符`\0`会导致乱码。此外,还讨论了`scanf`函数读取字符串时忽略空格和回车的特点。
|
26天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第六章 数组_一维数组_二维数组_字符数组详解
本章介绍了C语言中的数组概念及应用。数组是一种存储同一类型数据的线性结构,通过下标访问元素。一维数组定义需指定长度,如`int a[10]`,并遵循命名规则。数组元素初始化可使用 `{}`,多余初值补0,少则随机。二维数组扩展了维度,定义形式为`int a[3][4]`,按行优先顺序存储。字符数组用于存储字符串,初始化时需添加结束符`\0`。此外,介绍了字符串处理函数,如`strcat()`、`strcpy()`、`strcmp()` 和 `strlen()`,用于拼接、复制、比较和计算字符串长度。
|
26天前
|
存储 C语言
C语言程序设计核心详解 第九章 结构体与链表概要详解
本文档详细介绍了C语言中的结构体与链表。首先,讲解了结构体的定义、初始化及使用方法,并演示了如何通过不同方式定义结构体变量。接着,介绍了指向结构体的指针及其应用,包括结构体变量和结构体数组的指针操作。随后,概述了链表的概念与定义,解释了链表的基本操作如动态分配、插入和删除。最后,简述了共用体类型及其变量定义与引用方法。通过本文档,读者可以全面了解结构体与链表的基础知识及实际应用技巧。
|
1月前
|
C语言
c语言中的结构体
本文档详细介绍了C语言中结构体的使用方法,包括结构体的基本定义、变量声明与赋值、数组与指针的应用,以及结构体嵌套、与`typedef`结合使用等内容。通过示例代码展示了如何操作结构体成员,并解释了内存对齐的概念。
|
2月前
|
算法 C语言
C语言------数组
这篇文章是关于C语言数组的实训,包括一维数组、二维数组和字符数组的定义、赋值、输入、输出方法,并通过实例代码演示了数组的使用和一些基本算法,如冒泡排序。
C语言------数组
|
2月前
|
C语言
C语言结构体赋值的四种方式
本文总结了C语言结构体的四种赋值方式,并通过示例代码和编译运行结果展示了每种方式的特点和效果。
58 6
|
2月前
|
存储 编译器 程序员
七:《初学C语言》— 数组
【8月更文挑战第2天】本篇文章详细讲解了一维数组和二维数组的创建、使用和初始化及如何使用sizeof()计算数组中的元素个数。并附带了多个教学源码及代码练习
44 1
七:《初学C语言》— 数组
|
2月前
|
存储 编译器 数据处理
【编程秘籍】解锁C语言数组的奥秘:从零开始,深入浅出,带你领略数组的魅力与实战技巧!
【8月更文挑战第22天】数组是C语言中存储同类型元素的基本结构。本文从定义出发,详述数组声明、初始化与访问。示例展示如何声明如`int numbers[5];`的数组,并通过下标访问元素。初始化可在声明时进行,如`int numbers[] = {1,2,3,4,5};`,编译器自动计算大小。初始化时未指定的元素默认为0。通过循环可遍历数组,数组名视为指向首元素的指针,方便传递给函数。多维数组表示矩阵,如`int matrix[3][4];`。动态数组利用`malloc()`分配内存,需用`free()`释放以避免内存泄漏。掌握这些技巧是高效数据处理的基础。
56 2