vlambda博客
学习文章列表

C语言实现动态结构体数组

C语言实现动态结构体数组

原因是因为以前使用C++来实现的,主要用VERCTOR C++标准库的失代器

而不是纯C;C++是C语言的超集,除了包含C外,还有C++各种新语法,新库!

不过虽然C++用起来简单,开发效率高,不过相对C语言来说运行速度慢,占用内存大。

最烦得就是编译速度贼慢!

以前小仙使用C++BUILDER 开发WINDOWS桌面应用,基本上编译需要5分钟时间。

而最近编译MYSQL 8.0.20 DEBUG版本,编译近6个小时!就MYSQLD和另外个文件最慢,反复读写硬盘。

而且这两个文件都500-600MB. 而PG源码编译才20分钟就完成了。


MYSQL的C++源码看起来像是看抓妖玄学,鬼画桃符,又跳来跳去。PG就非常清爽!

另外PG基本上概念和ORACLE接近!


这次我要实现读取配置文件的参数,这参数是数据源配置,而且是多个!


这些数据库在私有云上的PDB,每个环境,每个项目,每个微服务一个

那么这样数据源是很多的。这样可以装进数组中。

比如长的这样子


CLASSA=DEV

CLASSB=GOODS

CLASSC=ACCOUNT

CLASSD=小凡仙

USER=ROOT

PASSWD=123456

IP=192.168.3.31

PORT=3306

DBNAME=SHARKDB



CLASSA=TEST

CLASSB=GOODS

CLASSC=ACCOUNT

CLASSD=小凡仙

USER=ROOT

PASSWD=123456

IP=192.168.4.31

PORT=3306

DBNAME=SHARKDB



/* 
 * File:   main.cpp
 * Author: zengfankun@小凡仙
 * 
 * Created on 2020年8月13日, 下午4:11

 */

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


//定义配置文件结构体类型


typedef struct  
    {


        char* pclassA;
        char* pclassB;
        char* pclassC;
        char* pclassD;
        char* pUser;
        char* pPassword;
        char* pIP;
        char* pPort
        char* pDBName;
    } Tdbconf_conten;


 void Load_Conf(char* pFileName);//读入配置文件
 Tdbconf_conten* GetDBconfArray( FILE* pFileHandle);//返回结构体数组
 int strleftcpy(char* pDest, char* pSrc,int n)   ;//复制字符串左边
 int strsub(char* pDest,const char* pSrc,int post,int size)//复制字符串任意位置

int main(int argc, char** argv) //sqlid classA classB classC dbname
{         
    char FileName[]="./conf/db.conf";
    char caSubStr[10];
    Load_Conf(FileName);

    strleftcpy(caSubStr,FileName,5);
    printf("%s\n",caSubStr);

    strsub(caSubStr,FileName,8,7);
    printf("%s\n",caSubStr);

}    

 int strleftcpy(char* pDest, char* pSrc,int n)
 
{
     int len= strlen(pSrc);
     if(n>len) 
        n=len;

    while (n--)   
    { 
        *(pDest++)=*(pSrc++);
    }

    *(pDest++)='\0'; //后面打入字符串结束标志

    return strlen(pDest);
 }

  int strsub(char* pDest,const char* pSrc,int post,int size)
 
{
     int len = strlen(pSrc);
     if ( size > len ) 
        size = len - post;
     if ( post < 0 ) 
        size = 0;
     if ( size > len )
        return 0;

     pSrc =pSrc+post-1//数组下标是从0开始,所以要减1 

     while (size--)
     {
         *(pDest++)=*(pSrc++);  //步进再赋值 
     }
     *(pDest++)='\0';         //后面补结束标志 

     return 1;

 }

  void Load_Conf(char* pFileName)         //装入配置文件
 
{
    FILE* fpFileHandle = NULL;
    Tdbconf_conten* pDBCONF_LIST;
    int iFileRow;
    char buff[255];

    fpFileHandle = fopen(pFileName,"r");
    if (fpFileHandle != NULL)
    {

      //fgets(buff,256,fpFileHandle);
      //printf("%s have row num:%d\n",pFileName,iFileRow);
      pDBCONF_LIST=GetDBconfArray(fpFileHandle);
      if(pDBCONF_LIST!=NULL)
      {
          printf("arrayp[0].ClassA is:%s\n",pDBCONF_LIST[0].pclassA);
          printf("arrayp[1].ClassA is:%s\n",pDBCONF_LIST[1].pclassA);
          printf("arrayp[0].ClassB is:%s\n",pDBCONF_LIST[0].pclassB);
          printf("arrayp[1].ClassB is:%s\n",pDBCONF_LIST[1].pclassB);
      }
    }

    fclose(fpFileHandle);
    fpFileHandle=NULL;
}

 Tdbconf_conten* GetDBconfArray( FILE* pFileHandle)  //暂时没有实现读取配置文件代码
{

    static Tdbconf_conten* pDBconf_List;   //必须定义静态才能返回给主调函数使用,一般C规范不建议这样做
    pDBconf_List=(Tdbconf_conten*) malloc(sizeof(Tdbconf_conten)*1); //分配内存
    pDBconf_List[0].pclassA="Proc";           //使用数组下标来赋值,结构体采用点号 pclassA也是CHAR 指针 可以直接指向字符串
    pDBconf_List[0].pclassB="Eorc";


    pDBconf_List=(Tdbconf_conten*) realloc (pDBconf_List,sizeof(Tdbconf_conten)*1);  //分配第二块内存,注意pDBconf_List带入
    pDBconf_List[1].pclassA="ProcX";
    pDBconf_List[1].pclassB="EorcX";

    return pDBconf_List;                 //返回内存指针
}
//设计不完善的读取文件
void ReadFile()
{
char buff[2048]; //行临时CHAR ARRAY
char* pKey; //KEY
static char* pContent; //VALUE 这个要返回

if (pFileHandle != NULL)    
  {
      if(!feof(pFileHandle))
      {
          fgets(buff,2049,pFileHandle); //读取2049字符遇\0 \n 就结束
          buff_size=strlen(buff);     //获得本次读取字符个数

          for (i=0;i++;i<buff_size)  //classA=env_produce\0  '= ' i=6  buff_size=19  buffsize-i=19-6=13
          {                          //01234567
              //printf("%c",buff[i]); 
              if (buff[i]=='=') //如果找到了等号前面就是KEY,后面就是VALUE
              {   
                  pKey=(char *)malloc( i * sizeof(char) ); //i位置 原本i是等号位置需要i-1,又因数组下标从0开始所以i+1,两者勾兑后就是i; 
                  strsub(pKey,buff,1,i);                   //strsub函数从人的习惯1开始 所以i 不用减1 

                  pContent=(char*)malloc ((buff_size-i-1)*sizeof(char));
                  strsub(pContent,buff,i+2,buff_size-i-1);


                  if( pContent != NULL)
                {

                      if(strcmp(DBconf_key.classA,pKey)==0)               
                          pdbconf_value.pclassA=pContent;                                         
                      if(strcmp(DBconf_key.classB,pKey)==0)               
                          pdbconf_value.pclassB=pContent;     
                      if(strcmp(DBconf_key.classC,pKey)==0)               
                          pdbconf_value.pclassC=pContent;     
                      if(strcmp(DBconf_key.classD,pKey)==0)               
                          pdbconf_value.pclassD=pdbconf_value;                        
                      if(strcmp(DBconf_key.user,pKey)==0)                 
                          pdbconf_value.pUser =pContent;                      
                      if(strcmp(DBconf_key.password,pKey)==0)                 
                          pdbconf_value.pPassword=pContent;                       
                      if(strcmp(DBconf_key.URL,pKey)==0)                  
                          pdbconf_value.pConnect=pContent;                
                    if(strcmp(DBconf_key.dbname,pKey)==0)               
                          pdbconf_value.pDBName=pContent; 
                      break;                              
                }
                free(pKey);
                pKey=NULL;
              }
          }


除了使用链表外,这个比较方便的数据结构可以实现动态结构体数组.

这里使用了3层, 

第一层是VALUE  字符串, 字符串长度不一.不能使用char[9]固定数组,只能使用char* pchar指针来指向字符数组.

第二层就是 结构体dbconf_conten   因为结构体里的成员是char* 指针,是第一层.

那么结构体成员的9个指针,也需要内存. 读第二个结构体时,会覆盖前面的指针;

那就需要保留前一个结构体9个指针,那么它就需要分配内存.

第三层 是指向结构体数组的指针 Tdbconf_conten* p


函数返回值一般是用于返回函数的执行状态,无论是int 还是void* char*

当然也有特殊情况,比如我们这里无法在主调函数分配内存再传给函数! 

只能在函数里分配好了内存,再返回给主调函数,这里必须使用静态关键字,告诉函数,当函数退出的时候不能释放该内存!

最后要在主函数用完后逐步循环释放内存