PDA

View Full Version : [C]Uso opzioni alfanumeriche "simil BASH"


tookie
09-05-2009, 10:00
Ciao a tutti ,
volevo sapere in che modo C può utilizzare opzioni alfanumeriche come per esempio fa in bash il comando cmp:

$ cmp -n2 file

dove in questo caso "-n" identifica l'opzione chiamata, e 2(che può essere qualsiasi intero chiamato da riga di comando a discrezione dell'utente) che permette di limitare l'opzione a 2 "elementi"

Io mi ritrovo in una situazione simile,in cui devo lanciare da riga di comando un programma C con un opzione che richiede un limitatore numerico.
La sitassi della riga è la seguente

$ ./prog -n arg1....argn

e in questo caso processa tutti gli argomenti

e devo arrivare ad avere

$ ./prog -nm arg1....argn


dove processa solo m argomenti

sono riuscito a implementare l'opzione attraverso la libreria <string.h> ma nn ho idea di come fare per implementare m,l'intero limitatore.

scusate se ho scritto qualche imprecisione ma al momento non ho il codice sotto mano e spero di essere stato il più chiaro possibile

DanieleC88
09-05-2009, 13:41
Leggi il parametro e vedi a quanto è impostato il limite massimo, poi per ogni argomento (che non è un'opzione) incrementi un contatore e confronti col limite: se lo hai superato, smetti di considerare gli argomenti.

tookie
09-05-2009, 15:02
aspetta, dopo che sono riuscito ad acquisirlo da riga di comando so come gestirlo, il problema è fargli prendere l'opzione
questo è il pezzo di codice interessato:

if ((strcmp(argv[2],"-lm")) == 0) { //strcmp è metodo di <string.h>
j=1;
for (i = c-1; i > 0; --i) {
if(j<m){
printf("Il %d numero e' = %d\n", j, array[i]);
++j;
}else{break;
}
}
}


dove array[] è un vettore di c elementi, non vuoto, definito in precedenza e m è il numero che gli passo da riga di comando

se io gli passo

$ ./prog -l5 arg1...argn


(in questo caso m=5)mi deve stampare gli elementi dell'array dall'ultimo al primo, bloccandosi quando arriva a m iterazioni

DanieleC88
09-05-2009, 15:15
In tal caso -lm non può funzionare, fai così:

Controlla che l'opzione inizi per -l (diciamo che la tua opzione è char *opzione = argv[i], con i l'indice dell'opzione che analizzi)
Scarta i primi due caratteri e controlla che l'opzione non si terminata (in altre parole, il puntatore alla stringa che ti interessa a quel punto è (opzione+2) - o, in modo equivalente, &opzione[2] - e devi controllare che non sia una stringa vuota)
Tenta la conversione da stringa a numero - a questo proposito non ti consiglio atoi() perché non rileva errori: ad esempio se la stringa fosse "10f" ti darebbe un 10; personalmente userei strtol() e controllerei che restituisse un puntatore NULL al secondo parametro.


Può sembrare un po' cervellotico ma credo sia la maniera più corretta di farlo (se non ti appoggi a routine esterne preconfezionate).

ciao ;)

DanieleC88
09-05-2009, 15:18
if ((strcmp(argv[2],"-lm")) == 0) { //strcmp è metodo di <string.h>
j=1;
for (i = c-1; i > 0; --i) {
if(j<m){
printf("Il %d numero e' = %d\n", j, array[i]);
++j;
}else{break;
}
}
}

Dimenticavo, i pezzi che ti ho evidenziato ti danno un tipico errore off-by-one (in quel modo di ciclare con la j effettui m-1 iterazioni, allo stesso modo in cui con la i effettui c-1 iterazioni), sostituisci il < con <= e il > con >=. ;)

tookie
09-05-2009, 16:33
questo è il mio codice modificato, spero come intendevi tu. Questa è un altra sezione del mio programma che in parole povere ordina in maniera crescente e si dovrebbe bloccare una volta che il la scansione dell'array arriva ad un numero maggiore del limite "-ln"

if ((strcmp(argv[1],"-l")) == 0) {

if(&argv[1][2]!=NULL){ //ho usato direttamente l'argomento
k=strtol(&(argv[1])[2],NULL,10);
sort(array, c);
for (i = 0; i < c; ++i) {
if(array[i]<=k){
printf("Il %d numero e' = %d\n", i + 1, array[i]);
}else{
free(array);
break;
}
}
free(array);
}

printf("limited!\n");/*LIMITED*/


}

e utilizzando sia l'atoi che il strtol ed entrambi non mi rilevano l'intero dopo "-l"e se ometto l'intero, l'output mi restituisce:

$./prog -l 7 6 4 9 0
Il 1 numero e' = 0
*** glibc detected *** ./cv: double free or corruption (fasttop): 0x08867008 ***
più altro....

DanieleC88
09-05-2009, 16:47
Aspetta, ci sono alcuni errori.
Innanzitutto lo strcmp() ad inizio blocco controlla se la stringa è esattamente quella, non se inizia per quella: usa strncmp() per confrontarne solo una porzione.

Poi, con il blocco:
if(&argv[1][2]!=NULL)
stai confrontando un char con NULL, che è un ((void*)0), e di certo non è quello che vuoi: confrontalo invece con '\0' (che è il terminatore di stringa).

Con questa riga:
k=strtol(&(argv[1])[2],NULL,10);
purtroppo non hai risolto molto, la chiamata è perfettamente equivalente ad atoi(), visto che passi un NULL al secondo parametro e la funzione non ha modo di informarti di un eventuale errore.
Io direi:
char *error;

n = strtol(stringaColNumero, &error, 10);

if (*error != '\0') /* ringrazio ||ElChE||88 per aver corretto la mia castroneria :D */
{
/* gestisci l'errore */
/* esci */
}

/* altrimenti usa il numero n */

Infine, cosa succede quando tu chiami free() ed esci dal for? C'è un altro free() identico lì ad aspettarlo... :D
Togli il free() prima del break. ;)

||ElChE||88
09-05-2009, 16:53
int main(int argc, char **argv)
{
long value;
char *end;

if (argc <= 1)
return 1;

if (strncmp(argv[1], "-l", 2) == 0)
{
value = strtol(argv[1] + 2, &end, 10);

if (*end != '\0')
{
printf("L'argomento e' nel formato sbagliato.\n");
}
else
{
printf("Il valore e': %ld.\n", value);
}
}

return 0;
}

DanieleC88
09-05-2009, 16:59
...
if (*end != '\0')
...

Hai ragionissima, errore mio.

DanieleC88
09-05-2009, 17:02
C'è rimasto da dire, a questo punto, che se strtol() restituisce 0 allora l'opzione è soltanto -l (senza numeri postfissi).

||ElChE||88
09-05-2009, 17:05
C'è rimasto da dire, a questo punto, che se strtol() restituisce 0 allora l'opzione è soltanto -l (senza numeri postfissi).
O -l0. :O

DanieleC88
09-05-2009, 17:08
O -l00000... Per quel che gli interessa non credo sia rilevante. :D

||ElChE||88
09-05-2009, 17:11
O -l00000... Per quel che gli interessa non credo sia rilevante. :D
Già... poi basta il più semplice degli if e si è a posto.

Una curiosità: ma l'indentazione usata da tookie esiste davvero? Perché mi fa un po' paura. :fagiano:

DanieleC88
09-05-2009, 17:14
Una curiosità: ma l'indentazione usata da tookie esiste davvero? Perché mi fa un po' paura. :fagiano:
Spero tanto di no, nessun editor sano di mente si sognerebbe di creargli un simile sfacelo... :D (a meno che non siano tabulazioni con una spaziatura personalizzata)

E ammetto che un po' paura la fanno anche a me. :eek:

tookie
10-05-2009, 10:12
ok grazie ragazzi, adesso mi funziona tutto perfettamente;-)