paulo1205 
		 
		(usa Ubuntu)
		 
		Enviado em 27/08/2020 - 03:52h 
		danilomarto escreveu:
Para a minha pergunta ficar mais clara. Suponha que o meu programa, chamado main, precise receber uma quantidade qualquer de parâmetros do console.
Para tanto, eu teria que fazer isso.
int main( int argc, char *argv[] ){ 
    ... 
   return 0; 
}  
Correto? 
 
Sim.
Em seguida eu compilo e executo passando os seus parâmetros.
$ gcc main.c -o main 
 
$ ./main par1 par2 ... parn  
Eu gostaria de saber como a função main consegue pegar a quantidade de parâmetros passados (que pode ser arbitrária) e jogar na variável argc e jogar todos eles dentro do array *argv[]? 
 
O 
shell  interpreta o que você coloca na linha de comando e considera que um ou mais espaços (que não estejam cercados por aspas ou apóstrofos ou escapados por uma barra invertida) funcionam como separadores de argumentos. Esses argumentos são, então, colocados pelo 
shell  dentro de um 
array , e esse 
array  é passado como argumento para a chamada ao sistema 
execve () (junto com outro 
array , que contém as variáveis de ambiente).  Essa chamada dispara a execução de um novo comando, e coloca os dois 
arrays  numa região de memória que é entregue ao programa.
Quando o programa começa a executar, existe um código que executa antes de 
main () (sim, existe um código que executa dentro do seu programa antes de 
main (), que o 
linker  coloca no executável na hora em que o produz) associa essas regiões de memória ao 
array  recebido através de 
argv  e, no caso das variáveis de ambiente, ao 
array  global (declarado como pointeiro) 
environ .
Ou seja, o 
shell  provavelmente tem algum código parecido com o seguinte.
    char *command, **new_args=NULL, **new_environ=NULL; 
ptrdiff_t token_offset=0; 
 
// Extrai o comando e a lista de argumentos. 
command=get_token(cmd_line, &token_offset);  // Extrai o primeiro token da linha de comando (get_token é um nome fictício, mas possível de ser feito). 
if(command==NULL){ 
  fprintf(stderr, "Erro: ponteiro nulo ao tentar extrair comando.\n"; 
  return -1; 
} 
 
size_t n_args=1; 
new_args=reallocarray(new_args, n_args+1, sizeof *new_args); 
if(new_args==NULL){ 
  fprintf(stderr, "Não foi possível alocar memória: %s.\n", strerror(errno); 
  return -1; 
} 
new_args[0]=command; 
new_args[1]=NULL; 
 
char *next_arg; 
while((next_arg=get_token(cmd_line, &token_offset))!=NULL){ 
  ++n_args; 
  void *new_ptr=reallocarray(new_args, n_args+1, sizeof *new_args); 
  if(new_ptr==NULL){ 
    fprintf(stderr, "Não foi possível alocar memória: %s.\n", strerror(errno); 
    free(new_args); 
    return -1; 
  } 
  new_args=new_ptr; 
  new_args[n_args-1]=next_arg; 
  new_args[n_args]=NULL; 
} 
 
// Para as variáveis de ambiente, poderia também ser um laço de repetição varrendo alguma coisa, mas eu 
// preferi colocar com valores fixos para ilustrar (poderiam ser valores fixos para os argumentos,  também). 
new_environ=malloc((N_ENVVARS+1)*sizeof *new_environ); 
new_environ[0]="PATH=/bin:/usr/bin:/usr/local/bin"; 
new_environ[1]="HOME=/home/paulo1205"; 
new_environ[2]="TZ=America/Sao_Paulo"; 
/* ... */ 
new_environ[N_ENVVARS-1]="ULTIMA_VARIAVEL=ultimo valor"; 
new_environ[N_ENVVARS]=NULL;  // O último elemento tem de ser um ponteiro nulo. 
 
execve(caminho_executavel, new_args, new_environ);  
Com a chamada acima, o programa que vier a ser executado terá 
n_args  entregue como valor de 
argc , e os argumentos dispostos em 
argv  vão corresponder exatamente ao que tiver sido colocado no 
array  new_args  no código acima, incluindo o 
n_args+1 -ésimo (ou 
argc+1 -ésimo) elemento, que é o ponteiro nulo.  Semelhantemente, os valores dispostos no código acima no 
array  new_environ  vão aparecer no programa no 
array  global 
environ , incluindo também o ponteiro nulo para demarcar o final da lista de argumentos.
Há duas formas, portanto, de percorrer os argumentos recebidos em 
argv , mostrados abaixo.
for(int n=0; n<argc; ++n) 
  puts(argv[n])  
for(char **parg=argv; *parg!=NULL; ++parg) 
  puts(*parg);  
De modo parecido com o segundo, você pode percorrer as variáveis de ambiente.
extern char **environ; 
 
void print_env(void){ 
  for(char **penv=environ;  *penv!=NULL; ++penv) 
    puts(*penv); 
}  
Mais ainda, tem como reproduzir esse comportamento em uma função ordinária? Caso sim, Como? Poderia me fornecer um exemplo. 
Acho que está bem explicado acima.  A única coisa que eu não detalhei foi a implementação interna de 
get_token (), mas isso é relativamente fácil de fazer.  E você pode até mesmo usar funções da biblioteca padrão para tanto, tais como 
strtok (), 
strsep () ou mesmo 
sscanf ().
... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)