Search code examples
c++cunixgdbdbx

C code - need to clarify the effectiveness


Hi I have written a code based upon a requirement.

(field1_6)(field2_30)(field3_16)(field4_16)(field5_1)(field6_6)(field7_2)(field8_1)..... this is one bucket(8 fields) of data. we will receive 20 buckets at a time means totally 160 fields. i need to take the values of field3,field7 & fields8 based upon predefined condition. if teh input argument is N then take the three fields from 1st bucket and if it is Y i need to take the three fields from any other bucket other than 1st one. if argumnet is Y then i need to scan all the 20 buckets one after other and check the first field of the bucket is not equal to 0 and if it is true then fetch the three fields of that bucket and exit. i have written the code and its also working fine ..but not so confident that it is effctive. i am afraid of a crash some time.please suggest below is the code.

int CMI9_auxc_parse_balance_info(char *i_balance_info,char  *i_use_balance_ind,char *o_balance,char *o_balance_change,char *o_balance_sign
)
{
  char *pch = NULL;
  char *balance_id[MAX_BUCKETS] = {NULL};
  char balance_info[BALANCE_INFO_FIELD_MAX_LENTH] = {0};
  char *str[160] = {NULL};
  int i=0,j=0,b_id=0,b_ind=0,bc_ind=0,bs_ind=0,rc;
  int total_bukets ;
  memset(balance_info,' ',BALANCE_INFO_FIELD_MAX_LENTH);
  memcpy(balance_info,i_balance_info,BALANCE_INFO_FIELD_MAX_LENTH);
  //balance_info[BALANCE_INFO_FIELD_MAX_LENTH]='\0';
  pch = strtok (balance_info,"*");
  while (pch != NULL && i < 160)
  {
     str[i]=(char*)malloc(strlen(pch) + 1);
     strcpy(str[i],pch);
     pch = strtok (NULL, "*");
     i++;
  }
total_bukets  = i/8  ;
  for (j=0;str[b_id]!=NULL,j<total_bukets;j++)
  {
  balance_id[j]=str[b_id];
  b_id=b_id+8;
  }
  if (!memcmp(i_use_balance_ind,"Y",1))
  {
     if (atoi(balance_id[0])==1)
     {
        memcpy(o_balance,str[2],16);
        memcpy(o_balance_change,str[3],16);
        memcpy(o_balance_sign,str[7],1);
        for(i=0;i<160;i++)
        free(str[i]);
        return 1;
     }
     else
     {
        for(i=0;i<160;i++)
        free(str[i]);
      return 0;
     }
  }
  else if (!memcmp(i_use_balance_ind,"N",1))
  {
      for (j=1;balance_id[j]!=NULL,j<MAX_BUCKETS;j++)
      {
        b_ind=(j*8)+2;
        bc_ind=(j*8)+3;
        bs_ind=(j*8)+7;
       if (atoi(balance_id[j])!=1 && atoi( str[bc_ind] )!=0)
       {
        memcpy(o_balance,str[b_ind],16);
        memcpy(o_balance_change,str[bc_ind],16);
        memcpy(o_balance_sign,str[bs_ind],1);
        for(i=0;i<160;i++)
        free(str[i]);
        return 1;
       }
      }
     for(i=0;i<160;i++)
     free(str[i]);
    return 0;
  }
 for(i=0;i<160;i++)
 free(str[i]);
return 0;
}

Solution

  • I had a hard time reading your code but FWIW I've added some comments, HTH:

    // do shorter functions, long functions are harder to follow and make errors harder to spot
    // document all your variables, at the very least your function parameters
    // also what the function is suppose to do and what it expects as input
    int CMI9_auxc_parse_balance_info
    (
      char *i_balance_info,
      char *i_use_balance_ind,
      char *o_balance,
      char *o_balance_change,
      char *o_balance_sign
    )
    {
      char *balance_id[MAX_BUCKETS] = {NULL};
      char balance_info[BALANCE_INFO_FIELD_MAX_LENTH] = {0};
      char *str[160] = {NULL};
      int i=0,j=0,b_id=0,b_ind=0,bc_ind=0,bs_ind=0,rc;
      int total_bukets=0; // good practice to initialize all variables
    
      //
      // check for null pointers in your arguments, and do sanity checks for any
      // calculations
      // also move variable declarations to just before they are needed
      //
    
      memset(balance_info,' ',BALANCE_INFO_FIELD_MAX_LENTH);
      memcpy(balance_info,i_balance_info,BALANCE_INFO_FIELD_MAX_LENTH);
      //balance_info[BALANCE_INFO_FIELD_MAX_LENTH]='\0';  // should be BALANCE_INFO_FIELD_MAX_LENTH-1
    
      char *pch = strtok (balance_info,"*"); // this will potentially crash since no ending \0
    
      while (pch != NULL && i < 160)
      {
        str[i]=(char*)malloc(strlen(pch) + 1);
        strcpy(str[i],pch);
        pch = strtok (NULL, "*");
        i++;
      }
      total_bukets  = i/8  ;
      // you have declared char*str[160] check if enough b_id < 160
      // asserts are helpful if nothing else assert( b_id < 160 );
      for (j=0;str[b_id]!=NULL,j<total_bukets;j++)
      {
        balance_id[j]=str[b_id];
        b_id=b_id+8;
      }
      // don't use memcmp, if ('y'==i_use_balance_ind[0]) is better
      if (!memcmp(i_use_balance_ind,"Y",1))
      {
        // atoi needs balance_id str to end with \0 has it?
        if (atoi(balance_id[0])==1)
        {
          // length assumptions and memcpy when its only one byte
          memcpy(o_balance,str[2],16);
          memcpy(o_balance_change,str[3],16);
          memcpy(o_balance_sign,str[7],1);
          for(i=0;i<160;i++)
            free(str[i]);
          return 1;
        }
        else
        {
          for(i=0;i<160;i++)
            free(str[i]);
          return 0;
        }
      }
      // if ('N'==i_use_balance_ind[0]) 
      else if (!memcmp(i_use_balance_ind,"N",1))
      {
        // here I get a headache, this looks just at first glance risky. 
        for (j=1;balance_id[j]!=NULL,j<MAX_BUCKETS;j++)
        {
          b_ind=(j*8)+2;
          bc_ind=(j*8)+3;
          bs_ind=(j*8)+7;
          if (atoi(balance_id[j])!=1 && atoi( str[bc_ind] )!=0)
          {
            // length assumptions and memcpy when its only one byte
            // here u assume strlen(str[b_ind])>15 including \0
            memcpy(o_balance,str[b_ind],16);
            // here u assume strlen(str[bc_ind])>15 including \0
            memcpy(o_balance_change,str[bc_ind],16);
            // here, besides length assumption you could use a simple assignment
            // since its one byte
            memcpy(o_balance_sign,str[bs_ind],1);
            // a common practice is to set pointers that are freed to NULL.
            // maybe not necessary here since u return
            for(i=0;i<160;i++)
              free(str[i]);
            return 1;
          }
        }
        // suggestion do one function that frees your pointers to avoid dupl
        for(i=0;i<160;i++)
          free(str[i]);
        return 0;
      }
      for(i=0;i<160;i++)
        free(str[i]);
      return 0;
    }
    

    A helpful technique when you want to access offsets in an array is to create a struct that maps the memory layout. Then you cast your pointer to a pointer of the struct and use the struct members to extract information instead of your various memcpy's

    I would also suggest you reconsider your parameters to the function in general, if you place every of them in a struct you have better control and makes the function more readable e.g.

    int foo( input* inbalance, output* outbalance )
    

    (or whatever it is you are trying to do)