Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] Não entendi como que ele lê o arquivo

Estava analisando o código e fiquei com dúvida em relação ao arquivo.txt da aula. Na primeira linha deste mesmo arquivo temos dois números indicando a quantidade de linhas e colunas, porém ao executar ele não imprime estes números, somente o mapa, mas como? Como ele consegue identificar o mapa destes números. Outro ponto também que tive dúvida foi na hora de armazenar as linhas e as colunas nas variáveis, não entendi muito bem como funciona esta parte do código.

Meu algoritmo caso precise dar uma olhada

#include <stdio.h>

    char** mapa;
    int linhas;
    int colunas;

void alocamapa(){
        mapa = malloc(sizeof(char*) * linhas);
    for(int i = 0; i < linhas; i ++){
     mapa[i] = malloc(sizeof(char) *(colunas+1));   
    }   
}

void liberamapa(){
     for(int i = 0; i < linhas; i ++){
        free(mapa[i]);
    }
    free(mapa);
}

void lemapa(){
    FILE* f;
    f = fopen("mapa.txt","r");
    if(f == 0){
        printf("Erro na leitura do mapa\n");
        exit(1);
    }
    fscanf(f, "%d %d", &linhas, &colunas);

    alocamapa();

    for(int i = 0; i < 5; i++){
        fscanf(f, "%s", mapa[i]);
    }
    fclose(f);
}

int main(){
    lemapa();

     for(int i = 0; i < 5; i++){
        printf("%s\n", mapa[i]);
    }

    liberamapa();
}
2 respostas
solução!

Oi Natan, tudo bem?

Primeiramente, sobre a leitura do arquivo "mapa.txt", o código utiliza a função fscanf(), que lê os dados formatados de um arquivo. No seu código, a linha fscanf(f, "%d %d", &linhas, &colunas); está lendo os dois primeiros números do arquivo, que representam a quantidade de linhas e colunas do mapa, e armazenando esses valores nas variáveis linhas e colunas.

Então, quando o código executa a função alocamapa(), ele aloca a quantidade de memória necessária para o mapa com base nas variáveis linhas e colunas que foram lidas do arquivo. A função malloc() é usada para alocar a memória necessária.

Para exemplificar, se o arquivo "mapa.txt" começa com "5 5", isso significa que o mapa tem 5 linhas e 5 colunas. Assim, a memória será alocada para um array de 5 ponteiros (representando as linhas) e, em seguida, para cada linha, será alocada memória para um array de 5 caracteres (representando as colunas).

Depois disso, o código lê o mapa do arquivo e armazena na memória que foi alocada. A parte do código que faz isso é:

for(int i = 0; i < 5; i++){
    fscanf(f, "%s", mapa[i]);
}

Esta parte do código está lendo uma string de cada vez do arquivo (que representa uma linha do mapa) e armazenando no array mapa. Note que ele está fazendo isso 5 vezes, que é a quantidade de linhas do mapa. No seu caso, ao invés de usar o número 5 diretamente, você poderia usar a variável linhas, assim o código se adapta para qualquer quantidade de linhas.

Um abraço e bons estudos.

Olá Natan!

vetores e ponteiros

Se vc já viu a aula sobre vetores, vc vai achar familiar essa sintaxe:

  • char palavra[6] = "Natan";

O que acontece é que essa variável palavra tbm pode ser escrita com notação de ponteiro:

  • char* palavra = "Natan";

vc pode imprimir ou modificar qualquer elemento dentro desse vetor passando o índice desejado, exemplo de impressão:

int main()
{
    //nome[0] = 'N', nome[1] = 'a', nome[2] = 't', ...
  char nome[] = "Natan"; 
  
  printf("%c\n", nome[0]); //print elemento 0
  printf("%c\n", nome[2]); //print elemento 2
  
  nome[0] = 'L'; // alterar elemento 0
  printf("%c\n", nome[0]); //printe novamente elemento 0
  
  /*saida:
  N
  t
  L
  */
  
  return 0;
}

agora o mesmo, mas utilizando ponteiro:

#include <stdio.h>

int main()
{
  const char nome[] = "Natan";
  char* ptr = &nome[0]; //aponta para o primeiro elemento de 'nome'
  
  printf("%c\n", *ptr); //mesmo que 'nome[0]'
  ptr++; // aponta para o proximo elemento
  
  printf("%c\n", *ptr);//memso que 'nome[1]'
  
  *ptr = 'L'; //mesmo que "nome[1] = 'L';"
  
  printf("%c\n", *ptr);//memso que 'nome[1]'
  
  /*saida
  N
  a
  L
  */
  
  return 0;
}

note que eu não inicializei com "char* ptr = "Natan"; " mas sim passando o primeiro elemento de 'nome', pois o ponteiro recebendo uma string literal é diferente de inicializar um array.

Mas qual a diferença entre um e outro?

  • Os vetores com a sintaxe de colchetes ( char variavel[] = "string" ) : É alocado um espaço de memória para armazenar os dados, logo, vc pode ler e escrever nesses endereços (alterar os dados de cada índice)

  • ponteiro char (char* ptr = "string literal") : Não é alocado um espaço de memória especial para ele, logo, essa variável serve APENAS para LEITURA. Note que vc pode ALTERAR o valor contido nesse espaço, mas isso não é aconselhado, visto que pode haver comportamentos indefinidos no programa .

Quando se utiliza ponteiros para apontarem para essas "strings literais", é aconselhado deixar o ponteiro como 'const';

//isso NÃO é obrigatório, mas evita que o programador tente alterar
const char* palavra = "Natan";

Vc altera o valor de uma string por ponteiro apenas em dois casos:

  • Ele aponta para uma outra variável ou vetor, ou seja, aquela string já está alocada em memória para leitura e escrita
  • Vc alocou manualmente o espaço de memória para os dados ( com a função 'malloc()', por exemplo);

matrizes

Uma matriz é um vetor de vetores, ou seja, é um vetor que armazena outros vetores. note a sintaxe de uma matriz bidimensional:

//armazena 2 vetores de char, cada vetor de char armazenado pode conter 10 elementos
char matriz[2][10] = { "Natan", "santos"}; 

a matriz PRÉ-ALOCA o espaço de memória, assim mesmo os nomes "Natan" e "santos" não ocupando aquele espaço de 10 caracteres, aquele espaço vai ficar alocado e vazio, Isso pode gerar um consumo desnecessário de memória.

char** mapa;

Tem a mesma lógica dos vetores e ponteiros. Isso é um ponteiro de ponteiro, como uma matriz, mas ele passa pelo mesmo problema que os ponteiro, caso receba valores literais, fica sendo apenas para leitura.

vantagem de ponteiros com função 'malloc'

Quando se utiliza o 'malloc', vc pode escolher o espaço de memória a ser alocado em tempo de execução, assim não há desperdício de memória. Mas como eu vou acessar essa memória alocada dinamicamente? Simples, utilizando um ponteiro!

Assim vc aloca o espeço necessário (no caso do seu código, para armazenar o mapa) e não gera desperdício de recurso.

Como o mapa tem linhas e colunas, vc tem que alocar o espaço necessário para as uma quantidade de linhas que vai haver vários elementos (caracteres) em cada uma, resumindo: vc vai alocar dinamicamente um vetor com varios vetores (matriz), por isso está sendo utilizado o 'char** mapa'.