mirror of
https://gitlab.com/blau_araujo/cblc.git
synced 2025-05-09 18:16:37 -03:00
258 lines
6.9 KiB
Org Mode
258 lines
6.9 KiB
Org Mode
#+title: Curso Básico da Linguagem C
|
|
#+subtitle: Aula 9: Argumentos e ambiente
|
|
#+author: Blau Araujo
|
|
#+startup: show2levels
|
|
#+options: toc:3
|
|
|
|
* Aula 9: Argumentos e ambiente
|
|
|
|
[[https://youtu.be/uufnW60rg2Q][Vídeo desta aula]]
|
|
|
|
** Vetores e strings
|
|
|
|
#+begin_src c
|
|
char str[] = "banana";
|
|
printf("Tamanho de str : %zu\n", sizeof(str)); // Imprime 7.
|
|
#+end_src
|
|
|
|
O vetor =str= é do tipo "/array of char/", tem 7 elementos (=char[7]=) e seu
|
|
nome é o endereço do primeiro caractere.
|
|
|
|
#+begin_src c
|
|
char *pstr = "cabana";
|
|
printf("Tamanho de pstr: %zu\n", sizeof(pstr)); // Imprime 8.
|
|
#+end_src
|
|
|
|
#+begin_quote
|
|
O operador =sizeof= avaliou 8 bytes porque é o tamanho de um endereço.
|
|
#+end_quote
|
|
|
|
O ponteiro =pstr= é do tipo "/pointer to char/", não tem referência sobre
|
|
o tamanho da string e seu nome avalia o endereço do primeiro caractere.
|
|
|
|
*** Vetores de "ponteiros"
|
|
|
|
Um vetor de /ponteiros/ é um ponteiro para um vetor de endereços:
|
|
|
|
#+begin_src c
|
|
int d1[] = {1,2,3};
|
|
int d2[] = {4,5,6};
|
|
int d3[] = {7,8,9};
|
|
|
|
int *v[] = {d1, d2, d3};
|
|
|
|
printf("Tamanho de v : %zu\n", sizeof(v)); // Imprime 8.
|
|
printf("Tamanho de v[0]: %zu\n", sizeof(v[0])); // Imprime 24 (3*8).
|
|
printf("Tamanho de d1 : %zu\n", sizeof(d1)); // Imprime 12 (3*4).
|
|
#+end_src
|
|
|
|
#+begin_quote
|
|
O operador =sizeof= avaliou 8 bytes porque é o tamanho de um endereço.
|
|
#+end_quote
|
|
|
|
O tipo de =v= é =int *= porque os tipos de seus elementos serão interpretados
|
|
na compilação como "/pointer to int/", em vez de "/array of int/".
|
|
|
|
Para receber esse tipo de vetor, o parâmetro dessa função teria que ser
|
|
decladado como...
|
|
|
|
#+begin_src c
|
|
void print_arr(int *arr[], int size);
|
|
#+end_src
|
|
|
|
Ou...
|
|
|
|
#+begin_src c
|
|
void print_arr(int **arr, int size);
|
|
#+end_src
|
|
|
|
*** Vetores de strings
|
|
|
|
Vetores de strings são vetores de ponteiros:
|
|
|
|
#+begin_src c
|
|
char *frutas[] = {"banana", "laranja", "abacate"};
|
|
|
|
printf("Tamanho de frutas : %zu\n", sizeof(frutas)); // Imprime 24 (3*8).
|
|
printf("Tamanho de frutas[0]: %zu\n", sizeof(frutas[0])); // Imprime 8.
|
|
#+end_src
|
|
|
|
#+begin_quote
|
|
O operador =sizeof= avaliou 8 bytes porque é o tamanho de um endereço.
|
|
#+end_quote
|
|
|
|
As strings literais são interpretadas como /"pointer to char"/ (=char *=).
|
|
|
|
Numa função...
|
|
|
|
#+begin_src c
|
|
void print_list(char **list);
|
|
#+end_src
|
|
|
|
*** Vetor de strings terminado com NULL
|
|
|
|
Os vetores de argumentos e de ambiente são vetores de strings terminados
|
|
com uma string nula (contendo apenas '\0'), o que pode ser representado por
|
|
=(void *)0= (ponteiro nulo) ou simplesmente =NULL=.
|
|
|
|
Esta seria uma lista de strings terminada com =NULL=.
|
|
|
|
#+begin_src c
|
|
char *frutas[] = {"banana", "laranja", "abacate", NULL};
|
|
|
|
int i = 0;
|
|
while (frutas[i]) {
|
|
printf("[%d] => %s\n", i, frutas[i]);
|
|
i++;
|
|
}
|
|
/* Imprime:
|
|
[0] => banana
|
|
[1] => laranja
|
|
[2] => abacate
|
|
*/
|
|
#+end_src
|
|
|
|
** Parâmetros da função 'main'
|
|
|
|
As especificação dizem que a função =main= pode ser definida sem receber
|
|
nenhum parâmetro...
|
|
|
|
#+begin_src c
|
|
int main(void) { /* ... */ }
|
|
#+end_src
|
|
|
|
Ou com dois parâmetros:
|
|
|
|
- *Primeiro parâmetro:* variável inteira para a quantidade de argumentos
|
|
(tipicamente =argc=).
|
|
- *Segundo parâmetro:* ponteiro para o endereço da lista de argumentos da linha do
|
|
comando (strings) que iniciou o programa (tipicamente =argv=).
|
|
|
|
#+begin_src c
|
|
int main(int argc, char **argv) { /* ... */ }
|
|
#+end_src
|
|
|
|
Em algumas implementações, a função =main= pode declarar um terceiro parâmetro
|
|
para receber a lista das variáveis exportadas para o ambiente do processo:
|
|
|
|
#+begin_src c
|
|
int main(int argc, char **argv, char **envp) { /* ... */ }
|
|
#+end_src
|
|
|
|
Mesmo que o terceiro parâmetro não seja declarado, o ambiente pode ser
|
|
acessado com a função =getenv= (=stdlib.h=) ou com o ponteiro global =environ=.
|
|
|
|
|
|
#+begin_src c
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
// Para informar que 'environ' existe...
|
|
extern char **environ;
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
printf("environ[0] => %s\n", environ[0]); // Imprime: SHELL=/bin/bash
|
|
|
|
char *env = getenv("SHELL");
|
|
printf("getenv(\042SHELL\042) => %s\n", env); // Imprime: /bin/bash
|
|
|
|
return 0;
|
|
}
|
|
#+end_src
|
|
|
|
** Conversão de strings para números
|
|
|
|
Como todos os argumentos são recebidos como strings, haverá situações em
|
|
que eles deverão ser convertidos para os valores numéricos correspondentes.
|
|
|
|
*** Exemplo: programa =soma.c=
|
|
|
|
#+begin_src c
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
|
|
long str2int(char *str) {
|
|
|
|
int num; // Recebe o inteiro convertido.
|
|
char *end; // Recebe o endereço onde termina o inteiro na string.
|
|
|
|
errno = 0; // Zerar a variável global 'errno'.
|
|
|
|
// Converte a parte numérica inicial de 'str' pata long int.
|
|
num = strtol(str, &end, 10);
|
|
|
|
// Checagem de erros...
|
|
if (str == end) {
|
|
// A parte inicial da string não era numérica...
|
|
fprintf(stderr, "Nenhum dígito encontrado!\n");
|
|
exit(EXIT_FAILURE);
|
|
} else if (errno == ERANGE) {
|
|
// O número está fora dos limites do tipo 'long int'...
|
|
fprintf(stderr, "Número fora dos limites!\n");
|
|
exit(EXIT_FAILURE);
|
|
} else if (*end != '\0') {
|
|
// Caracteres não convertidos restantes...
|
|
fprintf(stderr, "Caracteres inválidos: %s\n", end);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
int soma = 0;
|
|
int num;
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
num = str2int(argv[i]);
|
|
if (i == 1) {
|
|
printf("%d ", num);
|
|
} else {
|
|
printf("+ %d ", num);
|
|
}
|
|
soma += num;
|
|
}
|
|
printf("= %d\n", soma);
|
|
|
|
return 0;
|
|
}
|
|
#+end_src
|
|
|
|
Aqui, nós usamos a função =strtol=, que converte os dígitos encontrado na parte
|
|
inicial de uma string em seu correspondente numérico com o tipo =long int= na
|
|
base numérica especificada no terceiro argumento.
|
|
|
|
#+begin_src c
|
|
long strtol(const char *restrict nptr, char **_Nullable restrict endptr, int base);
|
|
#+end_src
|
|
|
|
Seu retorno é o valor numérico convertido, a menos que o valor exceda os limites
|
|
do tipo =long int=, o que fará com que o retorno seja =LONG_MIN= ou =LONG_MAX=. Se esta
|
|
for a situação, a global =errno= receberá o valor da constante simbólica =ERANGE=,
|
|
o que nos levou a utilizar o cabeçalho =errno.h= no exemplo.
|
|
|
|
#+begin_quote
|
|
Como a conversão pode retornar o valor =0=, é preciso inicializar =errno= com =0= antes
|
|
de chamar =strtol=.
|
|
#+end_quote
|
|
|
|
Ao fazer a conversão, o endereço do término da parte numérica é registrado no
|
|
parâmetro =endptr=, o que possibilita fazer diversas verificações, como:
|
|
|
|
- Se o endereço em =endptr= for igual ao endereço do início da string, a parte
|
|
inicial contém dígitos;
|
|
- Se o valor em =endptr= for igual a =\0=, a string só contém dígitos.
|
|
|
|
Além disso, se houver uma parte final não numérica, ela pode ser recuperada
|
|
a partir do endereço em =endptr=.
|
|
|
|
*Compilando e executando...*
|
|
|
|
#+begin_example
|
|
:~$ gcc -Wall -o soma soma.c
|
|
:~$ ./soma 1 2 3 4
|
|
1 + 2 + 3 + 4 = 10
|
|
#+end_example
|