codice C - necessità di chiarire l'efficacia
Domanda
Ciao ho scritto un codice basato su un requisito.
(field1_6) (field2_30) (field3_16) (field4_16) (field5_1) (field6_6) (field7_2) (field8_1 ) ..... questo è un secchio (8 campi) di dati. riceveremo 20 secchi alla volta significa totalmente 160 campi. devo assumere i valori di field3, field7 & fields8 basato sulla condizione predefinita. se teh argomento di input viene N poi prendere i tre campi dall'1 secchio e se è Y i bisogno a prendere i tre campi da qualsiasi altro secchio diverso da primo uno. se argumnet è Y allora devo scansione di tutti i 20 secchi uno dopo l'altro e controllo il primo campo del secchio non è uguale a 0, e se è vero, quindi scarica i tre campi di quel secchio e di uscita. ho scritto il codice e la sua anche lavorando bene, non ..ma così sicuro che sia effctive. Io ho paura di un incidente qualche time.please suggeriscono di seguito è il codice.
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;
}
Soluzione
Ho avuto un momento difficile leggere il vostro codice, ma FWIW ho aggiunto alcuni commenti, 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;
}
Una tecnica utile quando si desidera accedere offset in un array è quello di creare una struttura che associa il layout di memoria. Poi si esegue il cast il puntatore a un puntatore del struct e utilizzare i membri struct per estrarre informazioni al posto delle varie memcpy di
Vorrei anche suggerire che si riconsiderare i parametri alla funzione, in generale, se si svolge ogni di loro in una struttura di avere un migliore controllo e rende la funzione più leggibile per es.
int foo( input* inbalance, output* outbalance )
(o qualunque cosa si sta cercando di fare)
Altri suggerimenti
La mia sensazione è che questo codice è molto fragile. Può anche funzionare quando gli input sono validi (non mi propongo di scrivania controllare la cosa per voi), ma se dato alcuni ingressi non corretti sarà o crash e bruciare o dare risultati fuorvianti.
Avete testato per gli ingressi inaspettate? Ad esempio:
- Supponiamo i_balance_info è nullo?
- Supponiamo i_balance_info è ""?
-
Supponiamo che ci siano meno di 8 elementi nella stringa di input, quale sarà questa riga di codice fare?
memcpy(o_balance_sign,str[7],1);
-
Supponiamo che che l'oggetto in str [3] ha una lunghezza inferiore a 16 caratteri, che cosa sarà questa riga di codice fare?
memcpy(o_balance_change,str[3],16);
Il mio approccio alla scrittura di tale codice sarebbe quello di proteggere contro tutti i tali evenienze. Per lo meno io aggiungerei dichiarazioni ASSERT (), Io di solito scrivere convalida dell'input esplicito e gli errori di tornare quando va male. Il problema qui è che l'interfaccia non sembra consentire qualsiasi possibilità che ci possa essere un male di ingresso.