求用纯C语言序列化复杂结构体的方法

echo_qiang 2011-04-11 07:09:40
各位老师同学们好,问一个问题,最近做项目要求将一个最终生成的结构体序列化到外部文件里面保存,以便以后调用;上网看了很多资料,基本都是用java和C#弄的,C++我暂时还不考虑,目前只考虑用C来做,C里面只有一些简单的诸如fwrite和fread等函数,这些函数目前我发现只能序列化简单的结构体,如果结构体里面有指针和嵌套的结构体的时候,这种发发估计不适用,不知道有没有更好的方法去做这个,情各位大牛不吝赐教~谢谢~
...全文
1614 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
半兽人写程序 2011-08-29
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 newstudent_never 的回复:]

typedef struct _XY
{
int nX;
struct _XY* pNext;
}XY,* PXY;
typedef struct _MyStruct
{
int nA;
char cB;
PXY pXY;
struct _MyStruct* pLNext;
struct _MyStruct* pRNext;
}MYSTRUCT, *PMYST……
[/Quote]
另一个忠告。如果有自己不能做的,千万求助网络。网络力量无穷大,不过要区分好坏。
echo_qiang 2011-04-13
  • 打赏
  • 举报
回复
非常感谢你,拜读了,以后要好好锻炼了~
[Quote=引用 12 楼 newstudent_never 的回复:]
typedef struct _XY
{
int nX;
struct _XY* pNext;
}XY,* PXY;
typedef struct _MyStruct
{
int nA;
char cB;
PXY pXY;
struct _MyStruct* pLNext;
struct _MyStruct* pRNext;
}MYSTRUCT, *PMYSTRUC……
[/Quote]
xmu_才盛 2011-04-12
  • 打赏
  • 举报
回复
typedef struct _XY
{
int nX;
struct _XY* pNext;
}XY,* PXY;
typedef struct _MyStruct
{
int nA;
char cB;
PXY pXY;
struct _MyStruct* pLNext;
struct _MyStruct* pRNext;
}MYSTRUCT, *PMYSTRUCT;

这样的结构体够复杂吧???????

不再管你了, 记住一点 , 别人给你的代码都是别人的思路, 你copy的再好,不是你的东西, 像这样的底层操作, 你应该锻炼一下。。。


另外你是在校学生吧? 给你个忠告, 做项目时别依赖求助网上。。 我就是无聊给你写段代码。。。
xmu_才盛 2011-04-12
  • 打赏
  • 举报
回复

// 序列化.cpp : 定义控制台应用程序的入口点。
//
#include <stdlib.h>
#include<stdlib.h>
#include<time.h>

#define random(x) (rand()%x)

#define OUT
#define IN

typedef struct _XY
{
int nX;
struct _XY* pNext;
}XY,* PXY;
typedef struct _MyStruct
{
int nA;
char cB;
PXY pXY;
struct _MyStruct* pLNext;
struct _MyStruct* pRNext;
}MYSTRUCT, *PMYSTRUCT;

// 下面字符代表有指针数据
static unsigned char uszBufPointer[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// 下面字符代表有指针结束
static unsigned char uszBufEnd[8] = {0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};

// 递归序列化
void serialIn(PMYSTRUCT pList, FILE* pFile)
{
if (pList == NULL)
{
// 写入不存在后续指针标志
fwrite(uszBufEnd, 1, 8, pFile);
return;
}

// 写入存在后续指针标志
fwrite(uszBufPointer, 1, 8, pFile);
// 写入常量
fwrite(pList, 1, 5, pFile); // 先写入5个字节 int + char

// 写入pXY结构体
PXY pXY = pList->pXY;
while (pXY != NULL)
{
// 写入存在后续指针标志
fwrite(uszBufPointer, 1, 8, pFile);
// 写入数据
fwrite(&(pXY->nX), 1, 4, pFile);

pXY = pXY->pNext;
}
// 写入结束标志
fwrite(uszBufEnd, 1, 8, pFile);

// 写入左子树
serialIn(pList->pLNext, pFile);
// 写入结束标志
fwrite(uszBufEnd, 1, 8, pFile);

// 写入右子树
serialIn(pList->pRNext, pFile);
// 写入结束标志
fwrite(uszBufEnd, 1, 8, pFile);
}
// 序列化写入文件,-1代表失败
int serialInToFile(IN PMYSTRUCT pList, IN const char* pFileName)
{
int nReturn = -1;

FILE* pFile = fopen(pFileName, "wb+");
if (!pFile)
return nReturn;

// 递归序列化
serialIn(pList, pFile);

fclose(pFile);
nReturn = 1;
return nReturn;
}

unsigned char szBuf[8] = {0};
// 判断是否有下一个指针域
int judgeIfHaveNextPointer(unsigned char* pBuf)
{
int nReturn = 0;
int i = 0;
for (i = 0; i < 8; i ++)
if (pBuf[i] != 0x00)
break;
if (i != 8) // 说明可能有指针域
{
for (i = 0; i < 8; i ++)
if (pBuf[i] != 0xff)
break;
if (i == 8) // 有指针域
{
nReturn = 1;
return nReturn;
}
}
else
return nReturn;

return nReturn;
}
unsigned char uszTmpBuf[5] = {0};
// 递归读入
void serialRead(OUT PMYSTRUCT* ppList, FILE* pFile)
{
// 首先读8个字节判断是否有下一个节点
fread(szBuf, 1, 8, pFile);
int nTmp = judgeIfHaveNextPointer(szBuf);
if (nTmp == 0)
return;

// 声明指针域
*ppList = new MYSTRUCT;
(*ppList)->pXY = NULL;
(*ppList)->pLNext = NULL;
(*ppList)->pRNext = NULL;

// 先读入5个字节, int + char
fread(uszTmpBuf, 1, 5, pFile);
int* pInteger = (int*) uszTmpBuf;
(*ppList)->nA = *pInteger;
char* pChar = (char*) (uszTmpBuf + 4);
(*ppList)->cB = *pChar;

// 获取pXY区域
fread(szBuf, 1, 8, pFile);
nTmp = judgeIfHaveNextPointer(szBuf);
if(nTmp == 1)
{
(*ppList)->pXY = new XY;
PXY pXY = (*ppList)->pXY;
do
{
pXY->pNext = NULL;

// 读取4个字节 int
fread(uszTmpBuf, 1, 4, pFile);
pInteger = (int*) uszTmpBuf;
pXY->nX = *pInteger;

fread(szBuf, 1, 8, pFile);
nTmp = judgeIfHaveNextPointer(szBuf);
if (nTmp == 1)
{
pXY->pNext = new XY;
pXY = pXY->pNext;
}
} while (nTmp == 1);
}

// 左孩子指针
serialRead(&((*ppList)->pLNext), pFile);
fread(szBuf, 1, 8, pFile);
// 右孩子指针
serialRead(&((*ppList)->pRNext), pFile);
fread(szBuf, 1, 8, pFile);
}
// 序列化读入文件,-1代表失败
int serialOutFromeFile(OUT PMYSTRUCT* ppList, IN const char* pFileName)
{
int nReturn = -1;

FILE* pFile = fopen(pFileName, "rb");
PMYSTRUCT pCurNode = (PMYSTRUCT)malloc(sizeof(MYSTRUCT));
unsigned char uszBuf[8] = {0};
int i = 0;
int* pA = NULL;

if (!pFile)
return nReturn;

serialRead(ppList, pFile);


fclose(pFile);
nReturn = 1;
return nReturn;
}

// 初始化成为一个复杂的结构系统
void InitStruct(PMYSTRUCT pSTest, int nA)
{
pSTest->pXY = NULL;
pSTest->pLNext = NULL;
pSTest->pRNext = NULL;
if (nA == 0)
{
pSTest->nA = 0;
pSTest->cB = 0;
return;
}
// 撒下随机数种子,产生一个20以内的随机数
srand((int)time(0));
int nRand = random(20);

// 赋值
pSTest->nA = nRand;
if (nRand > 10)
pSTest->cB = 'A' + nRand;
else
pSTest->cB = 'a' + nRand;

// 自带的结构体
pSTest->pXY = new XY;
PXY pXY = pSTest->pXY;
pXY->pNext = NULL;
for(int i = 0; i < nRand / 4; i ++)
{
pXY->nX = nRand - i;
pXY->pNext = new XY;
pXY = pXY->pNext;
pXY->pNext = NULL;
}
pXY->nX = nRand + 1;
pXY->pNext = NULL;

// 对于两个左右节点赋值
pSTest->pLNext = new MYSTRUCT;
InitStruct(pSTest->pLNext, nA - 1);
pSTest->pRNext = new MYSTRUCT;
InitStruct(pSTest->pRNext, nA - 1);
}

// 递归删除
void DeleteStruct(PMYSTRUCT pSTest)
{
if(pSTest == NULL)
return;

PXY pXY = pSTest->pXY;
while (pXY != NULL)
{
PXY pTmp = pXY;
pXY = pXY->pNext;
delete pTmp;
}
pSTest->pXY = NULL;

// 删除左右子树
DeleteStruct(pSTest->pLNext);
pSTest->pLNext = NULL;
DeleteStruct(pSTest->pRNext);
pSTest->pRNext = NULL;

// 删除自己
delete pSTest;
}

// 递归打印数据
void printStruct(PMYSTRUCT pSTest,int nNum)
{
if(pSTest == NULL)
{
printf("NULL");
return;
}

printf("\n 第%d层节点数据\n", nNum);
printf("nA = %d, cB = %c XY---> ", pSTest->nA, pSTest->cB);
int i = 0;
PXY pXY = pSTest->pXY;
while (pXY != NULL)
{
++i;
printf("第%d个XY, nX = %d ---> ", i, pXY->nX);
pXY = pXY->pNext;
}
printf("NULL");

// 打印子节点
printf("\n打印下一层左孩子节点");
printStruct(pSTest->pLNext, nNum + 1);
printf("\n打印下一层右孩子节点");
printStruct(pSTest->pRNext, nNum + 1);
}
int main(int argc, _TCHAR* argv[])
{
int nReturn = 0;
const char* pFileName = "fileSerial.tmp";
const char* pFileName2 = "fileSerial2.tmp";
PMYSTRUCT pSTest = new MYSTRUCT;

// 初始化
InitStruct(pSTest, 5); // 2层比较好调试,5层
// 打印
printStruct(pSTest, 0);
// 序列化
serialInToFile(pSTest, pFileName);
// 删除
DeleteStruct(pSTest);
pSTest = NULL;

// 导出序列化
serialOutFromeFile(&pSTest, pFileName);
// 打印
printf("\n\n---------------------------------\n");
printStruct(pSTest, 0);
// 再次序列化,对比内容
serialInToFile(pSTest, pFileName2);
// 删除
DeleteStruct(pSTest);

getchar();
return 0;
}


echo_qiang 2011-04-12
  • 打赏
  • 举报
回复
我的结构体目前定义如下面这一部分,我要做的是一个dfa引擎,怎么将最后的dfa结构体导出,我这里面定义是嵌套了很多东西的,看的自己头大:
#define REG_MAGIC 256
struct vector_node {
struct vector_node *next, *prev;
};

struct vector_head {
struct vector_node *first, *last;
};

enum nfa_opcode {
NFA_NONE = 0,
NFA_BOL,
NFA_EOL,
NFA_CHAR,
NFA_FREE
};

struct nfa_transition {
struct vector_node list;
enum nfa_opcode type;
struct {
uint32_t lo;
uint32_t hi;
} alpha;
struct nfa_state *next;
};

struct nfa_state {
struct vector_node list;
struct vector_node set;
uint32_t id;
uint8_t final;
struct vector_head table;
};

struct nfa {
struct vector_node list;
struct nfa_state *start;
struct nfa_state *end;
struct vector_head states;
};

struct nfa_set {
uint32_t size;
struct nfa_state **head;
};

struct dfa_state {
struct vector_node list;
uint32_t id;
uint8_t final;
struct nfa_set *nfa;
struct {
struct dfa_state *next;
} table[REG_MAGIC];
};

struct dfa {
struct dfa_state *start;
struct vector_head states;
};


[Quote=引用 5 楼 newstudent_never 的回复:]
C/C++ code

#include <stdlib.h>

#define OUT
#define IN

typedef struct _MyStruct
{
int nA;
char cB;
struct _MyStruct* pNext;
}MYSTRUCT, *PMYSTRUCT;

// 序列化写入文件,-1代表失败
int ……
[/Quote]
xwfde 2011-04-12
  • 打赏
  • 举报
回复
看你结构体里面指针是指的什么了,如果指针是new 内存的那必须存储new 出内存的长度及内容,如果指针只是链表指向的下个结构,那么根本不需要存储,这种情况下指针没有指向存储信息,只是提供了下个数据存储的内存位置,而在文件中,所有数据都是希望顺序存储的,就像数组,所以不需要存储那个指针,只需顺序存储每个有用的信息即可,在读取文件时创建你的链表,没有反复删除插入节点的情况下请不要使用链表,用动态增长数组取代之
echo_qiang 2011-04-12
  • 打赏
  • 举报
回复
你好,能更详细点说说吗,谢谢~
[Quote=引用 7 楼 emailtome 的回复:]
和嵌套什么没一点关系 struct 只是单纯的数据块 注意下对齐的问题就好 如何解析 串行 去串

这东西用C写是最好不过的了呵呵
[/Quote]
emailtome 2011-04-12
  • 打赏
  • 举报
回复
和嵌套什么没一点关系 struct 只是单纯的数据块 注意下对齐的问题就好 如何解析 串行 去串

这东西用C写是最好不过的了呵呵
xmu_才盛 2011-04-11
  • 打赏
  • 举报
回复
不一定是完完全全的c语言程序, 一直都是做c++的,所以难免有c++的影子
xmu_才盛 2011-04-11
  • 打赏
  • 举报
回复

#include <stdlib.h>

#define OUT
#define IN

typedef struct _MyStruct
{
int nA;
char cB;
struct _MyStruct* pNext;
}MYSTRUCT, *PMYSTRUCT;

// 序列化写入文件,-1代表失败
int serialInToFile(IN PMYSTRUCT pList, IN const char* pFileName)
{
int nReturn = -1;
unsigned char uszBuf[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};

FILE* pFile = fopen(pFileName, "wb+");
if (!pFile)
return nReturn;

while (pList!= NULL)
{
fwrite(pList, 1, 5, pFile); // 5个字节 int + char
pList = pList->pNext;
if (pList)
fwrite(uszBuf, 1, 8, pFile);
}

fclose(pFile);

nReturn = 1;
return nReturn;
}

// 序列化写入文件,-1代表失败
int serialOutFromeFile(OUT PMYSTRUCT* ppList, IN const char* pFileName)
{
int nReturn = -1;

FILE* pFile = fopen(pFileName, "rb");
PMYSTRUCT pCurNode = (PMYSTRUCT)malloc(sizeof(MYSTRUCT));
unsigned char uszBuf[8] = {0};
int i = 0;
int* pA = NULL;

if (!pFile)
return nReturn;

*ppList = pCurNode;
while(!feof(pFile))
{
pCurNode ->pNext = NULL;
fread(uszBuf, 1, 4, pFile);
pA = (int*)uszBuf;
pCurNode->nA = *pA;
fscanf(pFile, "%c", &(pCurNode->cB));
fread(uszBuf, 1, 8, pFile);

for (i = 0; i < 8; i ++)
{
if (uszBuf[i] != 0xff)
break;
}
if (i == 8)
{
pCurNode->pNext = (PMYSTRUCT)malloc(sizeof(MYSTRUCT));
pCurNode = pCurNode->pNext;
}
}

fclose(pFile);
nReturn = 1;
return nReturn;
}
void InitStruct(PMYSTRUCT pSTest)
{
pSTest->nA = 1;
pSTest->cB = 'C';
pSTest->pNext = (PMYSTRUCT)malloc(sizeof(MYSTRUCT));
pSTest->pNext->nA = 2;
pSTest->pNext->cB = 'A';
pSTest->pNext->pNext = NULL;
}
void DeleteStruct(PMYSTRUCT pSTest)
{
PMYSTRUCT pTmp = NULL;
while (pSTest!= NULL)
{
pTmp = pSTest;
pSTest = pSTest->pNext;
free(pTmp);
}
}
void printStruct(PMYSTRUCT pSTest)
{
int i = 0;
while (pSTest!= NULL)
{
++i;
printf("第%d, nA = %d, cB = %c \n", i, pSTest->nA, pSTest->cB);
pSTest = pSTest->pNext;
}
}
int main(int argc, _TCHAR* argv[])
{
int nReturn = 0;
const char* pFileName = "fileSerial.tmp";
PMYSTRUCT pSTest = (PMYSTRUCT)malloc(sizeof(MYSTRUCT));

InitStruct(pSTest);

// 序列化
nReturn = serialInToFile(pSTest, pFileName);
// 删除
DeleteStruct(pSTest);
if (nReturn == -1)
return nReturn;

pSTest = NULL;
// 导出
serialOutFromeFile(&pSTest, pFileName);
// 打印
printStruct(pSTest);
// 删除
DeleteStruct(pSTest);

return 0;
}

echo_qiang 2011-04-11
  • 打赏
  • 举报
回复
谢谢,呵呵,这个东西我不是很熟悉,也知道有一种要自己定义规则的办法,但是不知道具体怎么去操作,有没有好的例子可以参考一下啊,辛苦你了~
[Quote=引用 1 楼 newstudent_never 的回复:]
链接的序列化,, 没考虑过,
你为什么不 循环链表,然后一个一个顺序序列化链表
然后设置一个特殊的值 标志这个地方存的是下一个链表 比如连续8个0xff
举个例子
struct A
{
int nA;
char b;
struct A * pNext;
}
假设 nA 为-1, b为 0, 有下一个指针
哪么序列化后就成为
0x01 0x00 0x00 0x1……
[/Quote]
echo_qiang 2011-04-11
  • 打赏
  • 举报
回复
哦,谢谢你,我这块不是很熟悉,不知道怎么去写,有没有好一点的例子啊,我参考一下~
[Quote=引用 2 楼 bdmh 的回复:]
老老实实的,把里面的东西都写进去,不要想能省几步代码
[/Quote]
bdmh 2011-04-11
  • 打赏
  • 举报
回复
老老实实的,把里面的东西都写进去,不要想能省几步代码
xmu_才盛 2011-04-11
  • 打赏
  • 举报
回复
链接的序列化,, 没考虑过,
你为什么不 循环链表,然后一个一个顺序序列化链表
然后设置一个特殊的值 标志这个地方存的是下一个链表 比如连续8个0xff
举个例子
struct A
{
int nA;
char b;
struct A * pNext;
}
假设 nA 为-1, b为 0, 有下一个指针
哪么序列化后就成为
0x01 0x00 0x00 0x10 0x30 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff

读取的时候先用unsigned char 获取数值, 判断其中是否有 0xff ,如果有则向后连续测试7个字节,看是否为0xff

c语言没有向java,c#那么强大的功能, 你只能自己控制程序,自己设置规则
时间序列分析 一个时间序列通常由4种要素组成:趋势、季节变动、循环波动和不规则波动。 趋势:是时间序列在长时期内呈现出来的持续向上或持续向下的变动。 季节变动:是时间序列在一年内重复出现的周期性波动。它是诸如气候条件、生产条件、节假日或人们的风俗习惯等各种因素影响的结果。 循环波动:是时间序列呈现出得非固定长度的周期性变动。循环波动的周期可能会持续一段时间,但与趋势不同,它不是朝着单一方向的持续变动,而是涨落相同的交替波动。 不规则波动:是时间序列中除去趋势、季节变动和周期波动之后的随机波动。不规则波动通常总是夹杂在时间序列中,致使时间序列产生一种波浪形或震荡式的变动。只含有随机波动的序列也称为平稳序列。 时间序列建模基本步骤是:①用观测、调查、统计、抽样等方法取得被观测系统时间序列动态数据。②根据动态数据作相关图,进行相关分析,自相关函数。相关图能显示出变的趋势和周期,并能发现跳点和拐点。跳点是指与其他数据不一致的观测值。如果跳点是正确的观测值,在建模时应考虑进去,如果是反常现象,则应把跳点调整到期望值。拐点则是指时间序列从上升趋势突然变为下降趋势的点。

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧