LinhaCodigo
001// Prof. Leo^nidas - http://www.matematica.br http://line.ime.usp.br
002// MAC0122 - 2017/09
003
004// Introducao aos apontadores em C
005// Principio: os sistema operacionais alocam memoria de modo consecutivo, ou seja, para "int a, b;"
006// o espaco para o 'a' estara' ao lado do espaco para o 'b'. No Linux o espaco do 'a' vem antes (i.e., alocacao "crescente").
007// Se voce^ usa outro sistema operacional, faca alguns testes para descobrir... (veja o bloco comentado com /* e */)
008
009// gcc -fsanitize=address -g -o introducao_apontadores introducao_apontadores.c
010
011#include <stdio.h>
012
013int main (void) {
014  int a, b, c;                            // os espacos para estas variaveis estarao consecutivos
015  int *ap_a = &a, *ap_b = &b, *ap_c = &c; // declarando apeontadores e fazendo-os apontar para as variaveis 'a, b, c': '&' devolve o endereco da variavel
016  float x, y, z;
017  float *ap_x = &x, *ap_y = &y, *ap_z = &z; // idem para 'x, y, z'
018
019  int M[2][3][4], conta = 1, i, j, k, *p; // para teste com matrizes/"arranjos"
020
021  // Agora vamos atribuir valores `as variaveis 'a,b,c,x,y,z' a partir de seus apontadores:
022  *ap_a = 1; *ap_b = 3; *ap_c = 5; // operador '*' devolve conteudo apontado (logo aplicavel apenas a apontadores)
023  *ap_x = 1; *ap_y = 3; *ap_z = 5; // assim, estamos atribuindo valores `as variaveis 'a,b,c,x,y,z'!
024  printf("a=%d, b=%d, c=%d\nx=%.1f, y=%.1f, z=%.1f\n", a, b, c, x, y, z); // devera imprimir: "a=1, b=3, c=5" e "x=1.0, y=3.0, z=5.0"
025
026  /* Esta e' a vantagem de usar comando de linha (quando necessario e' facil "desligar" um bloco inteiro
027  // Se fizer uma entrada via teclado, pode usar o "scanf" com os apontadores
028  printf("Digitar um inteiro e um float: ");
029  scanf("%d %f", ap_a, ap_x);     // passa os enderecos das variaveis 'a' e 'x'
030  printf("a=%d, x=%.1f\n", a, x); // logo imprime os valores digitados
031  */
032
033  // Agora facamos um teste com um agregado de dados do tipo matriz
034  // Ao declarar um vetor "int v[5];", reserva-se 5 posicoes para "int" sendo
035  // a primeira para X, entao a segunda para X+1 e assim por diante (supondo "end. crescente")
036  // Ao declarar uma matriz "int m[3][4];" reserva-se 3*4 posicoes, sendo
037  // * X,   X+1, X+2 para a primeira linha (m[0])
038  // * X+3, X+4, X+5 para a segunda linha (m[1]) e assim por diante
039  // Ao declarar uma matriz "int m[2][3][4];" reserva-se 2*3*4 posicoes, sendo
040  // * X,   X+1, X+2, X+3 para a "primeira" matriz m[0][0] (m[0][0][0] ate m[0][0][3])
041  // * X+3, X+4, X+5, X+6 para a "segunda"  matriz m[0][1] (m[0][1][0] ate m[0][1][3]) e assim por diante
042  // PORTANTO, "M[i][j]" comporta-se com um vetor, ou seja, havendo uma funcao que tenha vetor para parametro formal,
043  // pode receber como parametro efetivo "M[i][j]".
044  // Exercicio: Implemente uma funcao 'produtoInterno' que faca o produto interno de dois vetores, depois use-a para computar A*x (A matriz e x vetor)
045  for (i=0; i<2; i++)
046    for (j=0; j<3; j++)
047      for (k=0; k<4; k++)
048        M[i][j][k] = conta++;
049
050  // Supondo um sistema operacional como o Linux no qual o enderecamento e' crescente.  
051  p = M; // aponta para inicio da matriz
052  for (i=0; i<2*3*4; i++)
053    printf("%2d ", *p++);
054  printf("\n");
055  // Revendo, agora imprimindo via matriz e pulando linhas
056  for (i=0; i<2; i++) {
057    printf("---\nMatriz %d\n", i);
058    for (j=0; j<3; j++) {
059      for (k=0; k<4; k++)
060        printf("%2d ", M[i][j][k]);
061      printf("\n");
062      }
063    }   
064
065  // Supondo um sistema operacional que use enderecamento decrescente (e.g., como o ?)
066  /*
067  p = M; // aponta para inicio da matriz
068  for (i=0; i<2*3*4; i++)
069    printf("%2d ", *p--);
070  printf("\n");
071  */
072
073  return 0;
074  }