diff --git a/aulas/07-vps/.#testes.c b/aulas/07-vps/.#testes.c new file mode 120000 index 0000000..607f149 --- /dev/null +++ b/aulas/07-vps/.#testes.c @@ -0,0 +1 @@ +blau@xeon.1422306:1741809967 \ No newline at end of file diff --git a/aulas/07-vps/README.org b/aulas/07-vps/README.org new file mode 100644 index 0000000..6468639 --- /dev/null +++ b/aulas/07-vps/README.org @@ -0,0 +1,213 @@ +#+title: Curso Básico da Linguagem C +#+subtitle: Aula 7: Vetores, ponteiros e strings +#+author: Blau Araujo +#+startup: show2levels +#+options: toc:3 + +* Aula 7: Vetores, ponteiros e strings + +[[https://youtu.be/hhySl3ClTLE][Vídeo desta aula]] + +#+begin_quote +Parte do conteúdo desta aula foi antecipado nas [[../06-vetores/README.org][anotações da aula 6]]! +#+end_quote + +Embora sejam conceitos totalmente distintos, existem relações importantes entre +vetores e ponteiros que nós precisamos conhecer. + +** Notações de acesso + +Tanto ponteiros quanto vetores (e seus elementos) podem ser acessados de +duas formas... + +| Acesso | Aritmética | Subscrito | +|----------------+------------------+---------------| +| Valor/Elemento | =*(nome + índice)= | =nome[índice]= | +| Endereço | =nome + índice= | =&nome[índice]= | + +*** Exemplo + +*Dados o vetor e o ponteiro abaixo...* + +#+begin_src c +char v[] = {65, 66, 67, 68, 69, 0}; // Vetor de caracteres (bytes) +char *ptr = "FGHIJ"; // Ponteiro para uma string em .rodata (read only) +#+end_src + +*Impressão do endereço de um caractere...* + +#+begin_src c +// Impressões do vetor... +printf("v[2] : %c (%d) --> &v[2]: %p\n", v[2], v[2], &v[2]); +printf("*(v + 2): %c (%d) --> v + 2: %p\n", *(v + 2), *(v + 2), v + 2); + +// Impressões do ponteiro... +printf("p[2] : %c (%d) --> &p[2]: %p\n", p[2], p[2], &p[2]); +printf("*(p + 2): %c (%d) --> p + 2: %p\n", *(p + 2), *(p + 2), p + 2); +#+end_src + +*Saída do programa...* + +#+begin_example +v[2] : C (67) --> &v[2]: 0x7ffda53a16c4 +*(v + 2): C (67) --> v + 2: 0x7ffda53a16c4 +p[2] : H (72) --> &p[2]: 0x562d0c93100a +*(p + 2): H (72) --> p + 2: 0x562d0c93100a +#+end_example + +** Vetores e funções + +Observe esta função: + +#+begin_src c +int array_sum(int arr[], int size) { + int sum = 0; + for (int i = 0; i < size; i++) + sum += arr[i]; // arr é um ponteiro, não um vetor! + return sum; +} +#+end_src + +- Funções não podem receber vetores como argumentos, apenas seus endereços. +- Escreve-se =int arr[]= apenas para indicar que o argumento esperado é o + endereço de um vetor, já que =arr= será compilado como um ponteiro. +- Do mesmo modo, utiliza-se =arr[i]=, na iteração, para manter a coerência + semântica, já que a notação =nome[índice]= também pode ser utilizada com + ponteiros. + +Este mesmo exemplo poderia ser escrito apenas com notações de ponteiros +e aritmética de ponteiros: + +#+begin_src c +int array_sum(int *arr, int size) { + int sum = 0; + for (int i = 0; i < size; i++) + sum += *(arr + i); // Notação aritmética! + return sum; +} +#+end_src + +Em ambos os casos, a função lidará com o ponteiro (=arr=) que recebeu como +argumento o endereço de um vetor. O vetor em si, jamais será convertido +em ponteiro e nem tampouco /"decairá para um ponteiro"/! + +** Strings são vetores de caracteres + +Strings são vetores de caracteres terminados com o caractere nulo (=\0=). + +*Declaração de um vetor para receber uma string...* + +#+begin_src c +char str[TAMANHO]; +#+end_src + +Quando o vetor é declarado sem ser inicializado, é obrigatório definir +a quantidade de elementos que o vetor receberá. + +*Declaração e inicialização de um vetor com uma string...* + +#+begin_src c +char str[] = {'b', 'a', 'c', 'a', 'n', 'a', '\0'}; +#+end_src + +Quando o vetor é inicializado, a quantidade de elementos pode ser +omitida para ser definida na compilação. + +#+begin_quote +A presença da terminação do caractere terminador ='\0'= é que define +uma cadeia de caracteres como uma string, ou seja: uma cadeia de bytes +que pode ser utilizada com segurança em funções que procuram o terminador +para determinar o fim do processamento da cadeia de caracteres. +#+end_quote + +*Declaração e inicialização de um vetor com uma string literal...* + +#+begin_src c +char str[] = "bacana"; +#+end_src + +Quando a string literal ="bacana"= é utilizada na inicialização do vetor, +o compilador copia cada um de seus bytes para o vetor e inclui o terminador +nulo ('\0') como último elemento. + +*Inicialização de um ponteiro com uma string literal...* + +#+begin_src c +char *ptr = "cabana"; +#+end_src + +Ponteiros são variáveis que recebem endereços como argumentos. Sendo assim, +o compilador copia os bytes da string literal ="cabana"= e inclui o terminador +nulo na seção =.rodata= (/read only data/) como um vetor de caracteres de 7 +elementos e passa o endereço do primeiro byte para o ponteiro. + +#+begin_quote +O endereço de uma string, que é um vetor, é o endereço de seu primeiro byte. +#+end_quote + +** Inicializadores escalares e agregados + +Ponteiros são variáveis e, portanto, requerem /inicializadores escalares/: no +caso, especificamente endereços. + +Todos esses dados são escalares e podem inicializar variáveis: + +#+begin_src c +// Variável inicializada com o valor '10' (expressão constante)... +int a = 10; + +// Ponteiro inicializado com valor '&a' (endereço de 'a')... +int *pa = &a; + +// Ponteiro inicializado com o endereço do primeiro byte de uma string... +char *ps = "uma string literal"; +#+end_src + +Vetores, por sua vez, são estruturas que agrupam vários dados de mesmo tipo e, +por isso, requerem /inicializadores agregados/. + +Todos esses dados são agregados de valores e podem inicializar vetores... + +#+begin_src c +// Vetor inicializado com uma lista de 5 valores... +int n[5] = {1, 2, 3, 4, 5}; + +// Vetor inicializado com 5 valores '0'... +int z[5] = {0}; + +// Vetor inicializado com 5 caracteres (bytes)... +char c[] = {'a', 'b', 'c', 'd', '\0'}; // Quantidade de elementos definida na compilação... + +// Vetor inicializado com 7 caracteres (bytes)... +char s[] = "qwerty"; // O sétimo byte é o caractere nulo (\0 == 0x00)... +#+end_src + +Mas, repare nessas linhas... + +#+begin_src c +char *ps = "uma string literal"; +char s[] = "qwerty"; +#+end_src + +As strings literais são dados agregados do tipo =char *=, mas podem ser +utilizadas para inicializar tanto variáveis quanto vetores: tudo depende +do contexto... + +#+begin_src c +long a = (long)"uma string"; // Endereço da string modelado para long int. + +char *p = "outra string"; // O endereço da string é do tipo 'char[N bytes]'. + +char s[] = "mais uma"; // O endereço da string será o endereço do vetor, + // que só recebe os caracteres como elementos. + +char f[] = {'o', 'i', '\0'}; // Equivale e inicializar com "oi". +#+end_src + +*Nota:* + +Por ser uma estrutura de dados, o tipo de um vetor é frequentemente +descrito como =TIPO[TAMANHO]=. Sendo um vetor de caracteres, o tipo de +uma string literal na memória é =char[TAMANHO]=. Quando atribuída a +uma variável, a string literal expressa o endereço de seu primeiro +byte, ou seja, o endereço de um dado do tipo =char=. diff --git a/aulas/07-vps/diagrama.txt b/aulas/07-vps/diagrama.txt new file mode 100644 index 0000000..817e761 --- /dev/null +++ b/aulas/07-vps/diagrama.txt @@ -0,0 +1,31 @@ + + + Notações de acesso (vetores e ponteiros para endereços de vetores): + + =============================================== + | Expressa | Aritmética | Subscrito | + =============================================== + | Valor | *(nome + índice) | nome[índice] | + |----------+------------------+---------------| + | Endereço | nome + índice | &nome[índice] | + =============================================== + + + Incialização de vetores: Inicialização de ponteiros: + Requer inicializadores "agregados" Requer inicializadores "escalares" + + + &c[0] &c[1] &c[2] &c[3] &p[0] &p[1] &p[2] &p[3] + +--------+--------+--------+--------+ +--------+--------+--------+--------+ + char c[] = {65, 66, 67, 0}; ==> | 0x41 | 0x42 | 0x43 | 0x00 | char *p = "xyz"; ==> | 0x78 | 0x79 | 0x7a | 0x00 | + +--------+--------+--------+--------+ +--------+--------+--------+--------+ + ↑ + &s[0] &s[1] &s[2] &s[3] | + +--------+--------+--------+--------+ +--- Endereço em .rodata (read only) + char s[] = "abc"; ==> | 0x61 | 0x62 | 0x63 | 0x00 | + +--------+--------+--------+--------+ + + &b[0] &b[1] &b[2] &b[2] + +--------+--------+--------+--------+ + char b[4] = {0}; ==> | 0x00 | 0x00 | 0x00 | 0x00 | + +--------+--------+--------+--------+ diff --git a/aulas/07-vps/inicializa.c b/aulas/07-vps/inicializa.c new file mode 100644 index 0000000..52c2e52 --- /dev/null +++ b/aulas/07-vps/inicializa.c @@ -0,0 +1,34 @@ +#include + +int main(void) { + + // Declaração do vetor... + float notas[4]; + + // Definição individual dos elementos... + notas[0] = 7.5; + notas[1] = 9.0; + notas[2] = 8.3; + notas[3] = 8.6; + + // Inicialização do vetor... + int vetor[3] = {1, 2, 3}; + + // Inicialização sem número de elementos... + char c[] = {65, 66, 67, 68, 69}; // char[5] + char str[] = "string"; // = {'s', 't', 'r', 'i', 'n', 'g', '\0'}; + + // Inicialização parcial... + int n[6] = {1, 2, 3}; // = {1, 2, 3, 0, 0, 0}; + + // Inicialização com zeros... + int z[5] = {0}; // = {0, 0, 0, 0, 0}; + + // Inicialização com elementos de mesmo valor... + int r[4] = {23}; // = {23, 0, 0, 0}; + + for (int i = 0; i < 4; i++) r[i] = 23; + + + return 0; +} diff --git a/aulas/07-vps/notations.c b/aulas/07-vps/notations.c new file mode 100644 index 0000000..af4f1af --- /dev/null +++ b/aulas/07-vps/notations.c @@ -0,0 +1,33 @@ +#include + +int main() { + + /* + Notações de acesso: + + =============================================== + | Expressa | Aritmética | Subscrito | + =============================================== + | Valor | *(nome + índice) | nome[índice] | + |----------+------------------+---------------| + | Endereço | nome + índice | &nome[índice] | + =============================================== + */ + + long s = (long int)"banana"; + printf("%lx\n\n", s); + + char v[] = {65, 66, 67, 68, 69, 0}; + char *p = "FGHIJ"; + + // Impressão do vetor... + printf("v[2] : %c (%d) --> &v[2]: %p\n", v[2], v[2], &v[2]); + printf("*(v + 2): %c (%d) --> v + 2: %p\n", *(v + 2), *(v + 2), v + 2); + + // Impressão do ponteiro... + printf("p[2] : %c (%d) --> &p[2]: %p\n", p[2], p[2], &p[2]); + printf("*(p + 2): %c (%d) --> p + 2: %p\n", *(p + 2), *(p + 2), p + 2); + + + return 0; +} diff --git a/aulas/07-vps/string.c b/aulas/07-vps/string.c new file mode 100644 index 0000000..efca0e6 --- /dev/null +++ b/aulas/07-vps/string.c @@ -0,0 +1,13 @@ +#include + +int main(void) { + + // Vetor de caracteres com terminador nulo... + char vstr[] = "bacana"; + + // Ponteiro para um vetor char[7] em .rodata... + char *pstr = "cabana"; + + + return 0; +} diff --git a/aulas/07-vps/testes.c b/aulas/07-vps/testes.c new file mode 100644 index 0000000..61f595e --- /dev/null +++ b/aulas/07-vps/testes.c @@ -0,0 +1,34 @@ +#include + +#define NBIM 4 + +float favg(float *arr, int size) { + float sum = 0; + for (int i = 0; i < size; i++) { + sum += arr[i]; + } + return sum / size; +} + +int main(void) { + + float notas[NBIM]; + + notas[0] = 7.5; + notas[1] = 9.0; + notas[2] = 8.3; + notas[3] = 8.6; + + float avg = favg(notas, NBIM); + + puts("============"); + + for (int i = 0; i < NBIM; i++) + printf("Bim. %d: %.1f\n", i + 1, notas[i]); + + puts("------------"); + printf("Média : %.1f\n", avg); + puts("============"); + + return 0; +}