Seguem alguns comentários:
Por que a função print_usage
manda a saída para o stderr
? Esta é a saída de erro padrão, mas a meu ver o usage não é um erro, e sim uma mensagem informativa.
Outro detalhe é que vc trocou a ordem dos parâmetros. Veja que na documentação do seq
a ordem é:
seq [OPTION]... LAST
seq [OPTION]... FIRST LAST
seq [OPTION]... FIRST INCREMENT LAST
Ou seja, se passar apenas um valor, é o último. Se passar 2 valores, são o primeiro e último, e se passar 3, serão o primeiro, o incremento e o último.
Mas no seu programa vc trocou a ordem deles:
-./myseq [ENDNUMBER] [STARTNUMBER]
-./myseq [ENDNUMBER]
-./myseq [ENDNUMBER] [STARTNUMBER] [STEP]
O único caso que está certo é quando passa apenas 1 valor. Já nos outros casos a ordem dos valores está diferente.
Além disso, o código não funciona se passar apenas 2 parâmetros. Isso porque vc tenta sempre pegar o terceiro (argv[3]
), quando na verdade deveria verificar o argc
antes para saber se existe o terceiro valor. É isso que está dando o segmentation fault.
Outro detalhe é que o seq
, por padrão, imprime um número por linha, mas vc está imprimindo todos na mesma linha.
Enfim, para ficar mais parecido, poderia ser assim:
#include <stdio.h>
#include <stdlib.h>
#define PROGRAM_NAME "myseq"
void print_usage() {
printf("Usage: %s LAST\n", PROGRAM_NAME);
printf(" or: %s FIRST LAST\n", PROGRAM_NAME);
printf(" or: %s FIRST INCREMENT LAST\n", PROGRAM_NAME);
printf("Print numbers from FIRST to LAST, in steps of INCREMENT.\n");
}
int main(int argc, char *argv[]) {
int first = 1, last, increment = 1;
switch (argc) {
case 1:
print_usage();
return 0;
case 2:
last = atoi(argv[1]);
break;
case 3:
first = atoi(argv[1]);
last = atoi(argv[2]);
break;
case 4:
first = atoi(argv[1]);
increment = atoi(argv[2]);
last = atoi(argv[3]);
break;
default:
/* Aqui sim faz sentido mandar pro stderr, pois é um erro mesmo */
fprintf(stderr, "Extra operand: %s\n", argv[4]);
return 1;
}
while (increment > 0 ? first <= last : first >= last) {
printf("%d\n", first);
first += increment;
}
return 0;
}
Ou seja, se apenas um valor é passado, é o último. Se 2 valores são passados, são o primeiro e o último, e se 3 são passados, são o primeiro, o incremento e o último. Se forem passados mais valores, mostra uma mensagem de erro (e aqui sim faz sentido mandar a saída para o stderr
).
E caso o primeiro ou o incremento não sejam informados, o valor destes será 1
.
Por fim, não precisa ficar verificando se o primeiro é maior que o último, pois neste caso, ele não imprime nada: seq 4 1
não imprime nenhum número, a menos que o incremento seja negativo: seq 4 -1 1
por exemplo, imprime 4, 3, 2 e 1 nesta ordem.
A condição increment > 0 ? first <= last : first >= last
usa o operador condicional (também conhecido como "ternário"), e verifica se o incremento é positivo. Caso seja, verifica se o primeiro é menor ou igual ao último, caso contrário, verifica se o primeiro é maior ou igual ao último. Assim não precisa de funções separadas para cada caso, pois este loop serve para ambos.
Melhorias futuras
Para ficar igual mesmo, teria que implementar as opções (veja no já citado manual), como --help
para mostrar o usage, além de opções de formatação e suporte a float
(pois o seq
não funciona só com números inteiros: teste seq 1.5 0.4 5.8
por exemplo), mudar o separador, entre outros.
Sem contar outras validações, como o incremento não pode ser zero, dar erro se passar um valor que não é um número (seq xyz
), etc.