Programar em C/Mais sobre funções

Os argumentos argc e argv editar

A função main(), como dissemos antes, é uma função especial. Introduzimo-la como uma função sem parâmetros; no entanto, ela também pode receber parâmetros formais. No entanto, o programador não pode escolher quais serão. Eles devem ser os seguintes:

int main (int argc, char *argv[])
  • argc (argument count) é um inteiro e possui o número de argumentos com os quais o programa foi chamado na linha de comando. Ele é no mínimo 1, pois o nome do programa é contado como sendo o primeiro argumento.
  • argv (argument values) é um ponteiro para uma matriz de strings (conceitos que serão abordados mais à frente). Cada string desta matriz é um dos parâmetros da linha de comando. argv[0] sempre aponta para o nome do programa (que, como já foi dito, é considerado o primeiro argumento). É para saber quantos elementos temos em argv que temos argc.

Como pode se imaginar, os nomes dos parâmetros "argc" e "argv" podem ser mudados, mas por questão de padronização não se costuma modificá-los.

Exemplo: Escreva um programa que faça uso dos parâmetros argv e argc. O programa deverá receber da linha de comando o dia, mês e ano correntes, e imprimir a data em formato apropriado. Veja o exemplo, supondo que o executável se chame data:

data 19 04 99

O programa deverá imprimir: 19 de abril de 1999

#include <stdio.h> 
#include <stdlib.h>
 
int main(int argc, char *argv[]) 
{ 
    int mes; 
    char *nome_mes [] = {
        "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho",
        "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"
    };
    if(argc == 4) /* Testa se o número de parâmetros fornecidos está correto,
                    o primeiro parâmetro é o nome do programa, o segundo o dia,
                    o terceiro o mes e o quarto os dois últimos algarismos do ano */ 
   {
       mes = atoi(argv[2]);  /* argv contem strings. A string referente ao mes deve ser transformada
                               em um numero inteiro. A funcao atoi esta sendo usada para isto:
                               recebe a string e transforma no inteiro equivalente */ 
       if (mes<1 || mes>12)      /* Testa se o mes e' valido */ 
           printf("Erro!\nUso: data dia mes ano, todos inteiros"); 
       else 
           printf("\n%s de %s de 19%s", argv[1], nome_mes[mes-1], argv[3]); 
   }
   else printf("Erro!\nUso: data dia mes ano, todos inteiros"); 
}

Lista de argumentos editar

Na linguagem C é possível funções como "printf" onde o número de argumentos podem variar. As reticências ( ... ) indicam um numero variável de argumentos ou argumentos com tipos variável. Ex:

  void f_erro(int n, char *fmt, ...);

Essa declaração indica que se deve fornecer pelo menos dois argumentos, um do tipo int e um do tipo char mais pode se fornecer argumentos suplementares. Ou seja, "não há limites para sua criatividade"! Ex:

f_erro( 3, "Erro: missão impossível ");
f_erro( valor, "%s %d\n", mensagem, errno);

E necessário ter pelo menos um argumento antes dos pontos. Veja um exemplo incorreto.

void erreur(...);

O arquivo de cabeçalho stdarg.h declara um tipo va_list e define três macros para manipular uma lista de argumentos cuja quantidade e tipos são desconhecidos pela função.

va_start, va_arg et va_end (va como variable argument)

Sintaxe:

      #include <stdarg.h>
      void va_start(va_list ap, last);
      type va_arg(va_list ap, type);
      void va_end(va_list ap);
      void va_copy(va_list dest, va_list src);

Descrição:

va_start:

A macro va_start inicializa ap para uso posterior por va_arg e va_end e deve ser chamada primeiro.
O parâmetro last é o nome do último parâmetro antes da lista de argumentos variáveis, isto é, o último parâmetro o qual a função conheçe o tipo.
Porque o endereço deste parâmetro pode ser usado na macro va_start, ele não deve ser declarado como uma variável register, ou como uma função ou como um array.

va_arg:

A macro va_arg retorna o primeiro argumento variável e faz ap apontar o próximo argumento. O parâmetro ap é aquele inicializado por va_start. O parâmetro type é um nome de tipo. Pode-se apontar para um objeto de um tipo específico simplesmente adicionando um * ao tipo.
O primeiro uso da macro va_arg após a macro va_start retorna o argumento após last. Chamadas sucessivas retornam os valores dos outros argumentos.
Se não existe próximo argumento, ou se type não é compatível com o tipo do próximo argumento, erros aleatórios ocorrerão.
Se ap é passado para uma função que usa va_arg(ap,type) então o valor de ap é destruído após o retorno da função.

va_end:

Cada chamada de va_start deve ter uma chamada correspondente a va_end na mesma função. Após a chamada de va_end a variável ap é destruída. Várias chamadas com va_start e va_end aninhadas são possíveis. va_end pode ser uma macro ou uma função.

Exemplo 1

 
/* Calcula a soma de n inteiros   */
/* o ultimo argumento deve ser 0 */
#include <stdio.h>
#include <stdarg.h>

int soma(int n1, ...) {
  va_list  pa;
  int som, n;
  
  som = n1;
  va_start(pa, n1);
  while( (n = va_arg(pa, int)) != 0) 
     som = som + n;
  va_end(pa);
  return som;
} 

main() {
  printf("1 + 3 + 5 + 7 + 9 = %d\n", soma(1,3,5,7,9,0));
  printf("1 + 1 = %d\n", soma(1,1,0));
  return 0;
}
/*-- resultado ----------------------------
1 + 3 + 5 + 7 + 9 = 25
1 + 1 = 2
---------------------------------------------------------*/

Exemplo 2

 
    #include <stdio.h>
    #include <stdarg.h>

    void meu_printf(char *fmt, ...) {
      va_list pa;
      int n;
      char *s, c;
      float f;
      
      va_start(pa, fmt);
      while (*fmt != '\0') {
        if ( *fmt == '%' ) {
          /* (*++fmt) equivale a (*fmt = *fmt + 1 )*/
          switch (*++fmt) {
            case '%' : putchar('%'); break;
            case 'c' : /* char*/ 
                       c = va_arg(pa, int);
                       putchar(c);
                       break;
            case 'd' : /* int */ 
                       n = va_arg(pa, int);
                       printf("%d", n); 
                       break;
            case 'f' : /* float */ 
                       f = va_arg(pa, double);    /* !!!!! */
                       printf("%f", f); 
                       break;
            case 's' : /* string */ 
                       s = va_arg(pa, char *);
                       for ( ; *s != '\0'; s++ ) 
                         putchar( *s );
                       break;
          } /* end switch */
        }
        else 
          putchar( *fmt );
        /*incrementa o ponteiro*/
        fmt++;
      }   
      va_end(pa);
    } 

    int main() {
      meu_printf("float = %f\n", (float) 1.2345);
      meu_printf("int = %d   char = %c   String = %s\n", 123, 'A', "C is beautiful !" );
      return 0;
    }