【MATLAB】结构体那些事

   关于结构体这个字眼,对于我们这些从事编程工作的人来讲,熟悉得不能再熟悉了。当然,结构体也是需要掌握的重中之重。不论是C/C++,还是matlab,结构体都占据着重要的一环。结构体属于构造类型,就像生活中用来整理生活用具的盒子,只是它装的是数据类型而已。通过使用结构体,可以为程序设计带来很多便利。在此,将介绍matlab结构体的使用,包括结构体的基本用法、结构体在GUI设计中的应用以及C-MEX文件生成结构体等。
1、结构体的基本用法
   对于结构体的基本用法而言,主要涉及结构体创建和常见结构体函数使用两个部分。其中,关于结构体的创建,matlab有以下两种创建方式:
   a.使用点(.)运算符。如图1-(a)所示。
   b.使用struct函数创建结构体。如图1-(b)所示。Alt

图1 创建结构体
   有了结构体之后,便可使用或操作结构体数据。此处将列举常用的结构体函数,我们在使用过程中,若是记不住函数的具体用法,可在命令行通过help或者doc指令查看每个函数的具体用法。

  以下为常用结构体函数:

1、isfield()						%  检查结构体中是否含有某一字段名的字段
2、refield() 						%  从结构体中移出特定的字段
3、struct2cell()					%  将结构体转换成单元数组
4、fieldnames()						%  返回结构体的字段名,或对象的属性名
5、isstruct()						%  检查某一数据是否为matlab结构体

2、结构体在GUI设计中的应用
   Matlab结构体在程序设计中的使用频率相对较高,尤其是在GUI设计中最为常见。其中最常见、也是最重要的一个结构体便是handles结构。handles结构体作为一种重要的GUI数据管理机制,用于保存所有GUI对象数据。它是在运行GUIDE创建GUI时,由M文件自动生成的一种结构体。通常作为GUI回调函数的第三个输入参数传入回调函数,以便于用户在回调函数中任意访问GUI数据。
   handles结构体主要有两种用途。首先便是访问或修改GUI数据。由于handles保存有GUI对象数据,可在回调函数中,通过UI控件的tag值和句柄属性获取相关数据。其次是在回调函数间共享数据。用户可在handles中存储数据,在其他位置访问已经保存更新的数据。

1、访问或修改GUI数据
	get(handles.edit1, 'String');							%  访问GUI数据
	set(handles.pushbutton1, 'FontName', 'default');		%  修改GUI数据
2、共享数据
	resoultion = handles.Resolution;						%  获取数据
	handles.Resolution = resolution;						%  保存数据
	guidata(hObject, handles);								%  更新数据

3、C-MEX文件生成结构体
   Matlab在矩阵运算上有这很强的优势,但涉及到多重循环时,效率非常低下,而C/C++对于循环由着很高效的处理。因此可通过混合编程的方式提高代码执行效率。通过编写mex文件,能够让matlab调用C/C++程序如同调用内置函数一般。
   对于matlab和C/C++混合编程,matlab提供了很多API函数。由于文中主要涉及结构体使用,故在此仅列举与结构体相关的API函数,对于每个API函数的原型,可在MathWorks的Documentation主页中查到。
   以下为结构体相关的API函数:

01. mxCreateStructArray()        			// 创建一个N维未赋值的结构体阵列
02. mxCreateStructMatrix()       			// 创建一个2维未赋值的结构体阵列
03. mxGetField()                 			// 通过索引和字段名, 获得字段值
04. mxGetFieldByNumber()        			// 通过索引和字段位置,获取字段值
05. mxGetFieldNameByNumber()     			// 通过字段位置,获取字段名
06. mxGetFieldNumber()           			// 通过字段名,获取字段位置
07. mxGetNumberOfFields()       		    // 获取结构体的字段数量
08. mxIsStruct()                 			// 判断阵列是否为结构体阵列
09. mxSetField()                 			// 通过索引值和字段名,设置字段值
10. mxSetFieldByNumber()        		    // 通过索引值和字段位置,设置字段值

   在此将以一个实例,讲述C-MEX文件生成复杂结构体。该文件主要用于将图2-(a)所示的txt文件内容转换成图2-(b)所示的结构。Alt

图2 数据存储转换示意图

该文件包含以下几个功能:
   a.获取matlab传入的txt存放路径;
   b.读取并解析txt文件,并用C/C++结构体存储解析到的数据;
   c.生成matlab结构体

其具体功能实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mex.h"

#define MAX 3
#define SIZE 12

struct subfield{
	int width;
	int height;
};

struct resolution{
	char field[SIZE];
	struct subfield Value;
};

int getIndex(char *s, char c);
void parseTxt(char *path, struct resolution *res);		// 解析txt文件
mxArray * createSubField(struct subfield *field);		// 填写结构体字段

void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
	struct resolution Resolution[MAX];
    const char *fieldnames[MAX];
    const int nfields = 3;
    mwSize dim[2] = {1, 1};
    mxArray *tmp;
    char *path;
    int i, *str_size;
    
    /*	获取matlab传入的txt存放路径	*/
    str_size = (int *)mxGetDimensions(prhs[0]);
	path = (char *)malloc(str_size[0]*str_size[1]+1);
	mxGetString(prhs[0], path, str_size[0]*str_size[1]+1);
    
    /*	解析txt文件	*/
	parseTxt(path, Resolution);
    
    /*	获取字段名,并创建一个matlab结构体类型的返回值	*/
    for (i = 0; i < MAX; i++)
    {
        fieldnames[i] = Resolution[i].field;
    }
    plhs[0] = mxCreateStructArray(2, dim, nfields, fieldnames);
    
    /*	   装载数据		*/
    for (i = 0; i < MAX; i++)
    {
        tmp = createSubField(&(Resolution[i].Value));
        mxSetFieldByNumber(plhs[0], 0, i, tmp);
    }
    
}

int getIndex(char *s, char c)
{
	int count = -1;

	for (; *s != c && *s != '\0'; s++)
		++count;

	return count;
}

void parseTxt(char *path, struct resolution *res)
{
	FILE *fp;
	char tmpChar[20];
	char *s1, *s2;
	int count = -1;
	int index;

	fp = fopen(path, "rb");

	while (!feof(fp))
	{
		fscanf(fp, "%s", tmpChar);
		if (tmpChar[0] == '[')
		{
			count++;
			memset(res[count].field, 0, SIZE);
			index = getIndex(tmpChar, ']');		// 解析主字段
			if (index != -1)
			{
				strncpy(res[count].field, tmpChar+1, index);
			}
			else
			{
				printf("Not found \"%c\"\n", ']');
			}
		}
		else if (tmpChar[0] == 'w')			// 解析 width
		{
			s1 = strtok(tmpChar, "=");
			s2 = strtok(NULL, "=");
			res[count].Value.width = atoi(s2);
		}
		else if (tmpChar[0] == 'h')			// 解析 height
		{
			s1 = strtok(tmpChar, "=");
			s2 = strtok(NULL, "=");
			res[count].Value.height = atoi(s2);
		}
	}

	fclose(fp);
}

mxArray * createSubField(struct subfield *field)
{
    mxArray *ret, *val;
    mwSize dim[2] = {1, 1};
    const int nfields = 2;
    const char *fieldnames[2] = {"width", "height"};
    
    /*	创建结构体   */
    ret = mxCreateStructArray(2, dim, nfields, fieldnames);
    
    /*	填写 width	*/
    val = mxCreateNumericMatrix(1, 1, mxINT16_CLASS, mxREAL);
    memcpy(mxGetPr(val), &(field->width), sizeof(double));
	mxSetFieldByNumber(ret, 0, 0, val);
    
    /*	填写 height	*/
    val = mxCreateNumericMatrix(1, 1, mxINT16_CLASS, mxREAL);
    memcpy(mxGetPr(val), &(field->height), sizeof(double));
    mxSetFieldByNumber(ret, 0, 1, val);   
    
    return ret;
}

参考文献:
   [1] 罗华飞,2014. MATLAB GUI设计学习手记(第三版)[M]. 北京:北京航空航天大学出版社
   [2] 李传军,2004. C语言与MATLAB接口——编程与实例[M]. 北京:北京邮电大学出版社

个人声明:
   以上内容,纯属个人观点,不喜勿喷。博客中出现的代码仅供学习参考,不得有其他用途。若有大佬见此拙作,还望指点一二。有好的建议或者文中存在纰漏,欢迎留言,也可邮箱联系:yxyx_0212@163.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值