Ir ao conteúdo
  • Cadastre-se

C Alocação dinâmica de Matriz


UmPrograma

Posts recomendados

Bom dia. Como vão?

 

Estava a resolver um exercício de alocação dinamica, so que dessa vez de matriz. Mas o conceito não entrou muito bem não. 

No vetor criamos um ponteiro que ira apontar para um espaço, e entao alocamos certa quantidade desse espaço usando o malloc (e sizeof).

Já na matriz fariamos como? Eu seguindo um video aqui do youtube entendi que deve ser declarado um ponteiro para ponteiro, e que apontará para um espaço de memoria, como num vetor, e desse cada espaço apontará para uma certa quantidade. Não sei se deu para entender.

(Não sei se pode deixar o link do video aqui, mas so pesquisa alocação de matriz.)

 

Acredito que o conceito nao seja exatamente esse.

 

Deixarei o codigo abaixo, se puderem olhar. Nele funciona normalmente quando é colocado um numero diferente de 1 na coluna ou na linha, (isso depende de como eu fiz o segundo malloc, ESTARÁ COMENTADO ESSA PARTE NO CODIGO).

 

#include <stdio.h>
#include <stdlib.h>
/**3. Construa um programa (main) que aloque em tempo de execução (dinamicamente) uma
matriz de ordem m x n(linha por coluna), usando 1+m chamadas a função malloc. Agora,
aproveite este programa para construir uma função que recebendo os parametros m e n
aloque uma matriz de ordem m x n e retorne um ponteiro para esta matriz alocada. Crie
ainda uma função para liberar a área de memória alocada pela matriz. Finalmente, crie um
novo programa (main) que teste/use as duas funções criadas acima.*/

/// Protóticos das funções.
int **aloca_matriz(int **mat,int m, int n);
void libera_matriz(int **mat);
main(){
    int  **mat = NULL, m, n, i, j;
    printf("Quantas linhas a matriz tera? ");
    scanf("%d", &m);
    printf("Quantas colunas a matriz tera? ");
    scanf("%d", &n);


    mat=aloca_matriz(mat,m, n);

    ///Preenchendo a matriz.
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            printf("Matriz [%d][%d]: ", i,j);
            scanf("%d", &mat[i][j]);
        }
    }

    ///Imprimir na tela o resultado!!!
    printf("\n\nAgora sera impresso na tela o resultado.\n");
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            printf("Matriz [%d][%d]: %d.\n", i,j,mat[i][j]);
        }
    }
    ///Liberando o espaco usado pela matriz alocada.
   libera_matriz(mat);

   /*printf("\n\nAgora sera impresso na tela o resultado apos libera-los.\n");
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            printf("Matriz [%d][%d]: %d.\n", i,j,mat[i][j]);
        }
    }*/
    return 0;
}
int **aloca_matriz(int **mat,int m, int n){
    int i,j;
    ///Aloco vetor principal
    mat = (int **) malloc(m * sizeof(sizeof(int *)));

    ///Aloca matriz
    for(i=0;i<n;i++){
        //for(j=0;j<n;j++){
        mat[i] = (int *) malloc(n * sizeof(int)); /// AQUI JÁ APARECE ERRO POR NAO CONSEGUIR COLOCAR 1 NA COLUNA.  AQUI SE MUDAR O n * sizeof , POR M * ... APARECE PROBLEMA SE EU COLOCAR 1 NA LINHA, 
        //}
    }

return mat;
}
void libera_matriz(int **mat) {
    free(mat);
}

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Bom D!

 

 

O erro é tratar o ponteiro como se fosse um arranjo (no sentido de ser uma implementação interna da linguagem com aritmética de ponteiros implícita) quando na verdade ponteiros não são arranjos, cada qual tem sua implementação.

 

Então, use a nomenclatura de arranjos apenas se for um ponteiro de arranjo, e ainda se for uma referência de arranjo.

 

Ponteiro de ponteiro não é a mesma coisa que arranjos (vetores e matrizes), ele é apenas ponteiro.

 

 

26 minutos atrás, Josesousa disse:

Já na matriz fariamos como?

Um ponteiro de Arranjo.geeksforgeeks.org

 

 

Ok? Tchau!

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@AnsiC  Na verdade não (Em parte, somente). Não entendi muito bem o que voce quis dizer.

 

voce se referia a mat que é aritmetica de ponteiros? E sobre essa de arranjo ser diferente de ponteiro para ponteiro, não sei.

No caso teria que resolver usando ponteiro para ponteiro não? Que seria um arranjo.

 

Esse ponterio nao vai apontar para um bloco e desse bloco  cada pedaco (ponteiro) apontara para uma linha da matriz?

 

Usei o seguinte site -> https://www.pucsp.br/~so-comp/cursoc/aulas/ca70.html , e conseguir resolver meu problema, eu acho.

A parte que mudei. A diferenca que declarei o ponteiro para ponteiro na funcao. E usei calloc.

mat = (int **) calloc (m, sizeof(int *));
    for ( i = 0; i < m; i++ ) {
      mat[i] = (int*) calloc (n, sizeof(int));	/* m vetores de n floats */
      if (mat[i] == NULL) {
         printf ("** Erro: Memoria Insuficiente **");
         return (NULL);
         }
      }

 

voce poderia me tirar outra duvida. Qual a diferenca e malloc e calloc, alem do prototico. Pois parece que fazem a mesma coisa. So que o calloc zera quando aloca alguma coisa.

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@AnsiC Acho que entendi.

No caso um ponteiro aponta apenas para o primeiro elemento da matriz, ai teria que faze-lo apontar para a matriz inteira.

 

* (* (arr + i) + j) = e a funcao malloc......ou calloc...

adicionado 6 minutos depois

Entao eu estava alocando parte a parte, e não diretamente.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

4 horas atrás, Josesousa disse:

* (* (arr + i) + j)

Correto! Essa é a nomenclatura certa para ponteiros.

 

 

4 horas atrás, Josesousa disse:

Entao eu estava alocando parte a parte, e não diretamente.

Acertou! Porém se alocou parte a parte, vai ter que desalocar parte a parte do mesmo jeito, caso não faça assim, ai terá errado. Essa função de desalocar é "análoga" a de alocar.

 

 

A função que fiz para aloca memória de um arranjo é igual a sua.

int **  novo_arranjo (int largura, int comprimento){
    int **arr =  malloc (largura * sizeof(int *));

    for (int l =  0; l  <  largura; l ++){
          *(arr + l) =  malloc (comprimento * sizeof(int)); }

    return  arr; }

 

 

Ok? aguardando!

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@Josesousa Olá. Dei um "tapinha" no seu código e o mesmo poderia ficar assim:

 

#include <stdio.h>
#include <stdlib.h>

/// Protóticos das funções.
int **aloca_matriz(int **,int, int);
void libera_matriz(int **, int);

int main() {

    int  **mat = NULL, lines, cols, i, j;

    printf("Quantas linhas a matriz tera?: ");
    scanf("%d", &lines);

    printf("Quantas colunas a matriz tera?: ");
    scanf("%d", &cols);

    mat = aloca_matriz(mat, lines, cols);

    ///Preenchendo a matriz.
    for (i = 0; i < lines; i++) {
        for (j = 0; j < cols; j++) {
            printf("Matriz [%d][%d]: ", i,j);
            scanf("%d", &mat[i][j]);
        }
    }

    ///Imprimir na tela o resultado!!!
    printf("\n\nAgora sera impresso na tela o resultado.\n\n");
    for (i = 0; i < lines; i++) {
        for (j = 0; j < cols; j++) {
            printf("Matriz [%d][%d]: %d.\n", i, j, mat[i][j]);
        }
    }

    libera_matriz(mat, lines);

    return 0;
}

int **aloca_matriz(int **mat,int lin, int cols) {

    int i, j;

    mat = malloc(lin * sizeof(int *));

    for (i = 0; i < lin; i++) {
        mat[i] = malloc(cols * sizeof(int));
    }

    return mat;
}

void libera_matriz(int **mat, int lines) {
    int i;

    for (i = 0; i < lines; i++) {
        free(mat[i]); // libera primeiro a segunda dimensão
    }
    free(mat); // libera a primeira dimensão
}

 

Link para o comentário
Compartilhar em outros sites

Eu prefiro usar ponteiro para arranjo ( (*ponteiro)[n] ), ao invés de ponteiro de ponteiro ( **ponteiro ):

#include <stdio.h>
#include <stdlib.h>

int (*nova_matriz(int nlinhas, int ncolunas))[] {
    int (*matriz)[ncolunas] = NULL;
    matriz = malloc(nlinhas * sizeof *matriz);
    if (matriz == NULL){
        printf("\nERRO: Memoria livre insuficiente!\n");
        exit(EXIT_FAILURE);
    }
    return matriz;
}

int main() {
    int (*matriz)[5];
    
    matriz = nova_matriz(4, 5);
    
    /*Faz algo com a matriz de 4 linhas x 5 colunas*/
    
    free(matriz);

    return 0;
}

 

Assim só precisa usar 1 free para liberar a matriz inteira, e usando 1 único malloc a matriz inteira é armazenada em um lugar continuo da memória.

Com vários mallocs cada um deles reserva espaço em um lugar diferente da memória então a matriz fica fragmentada em vários lugares perdendo desempenho, e também aumenta a chance de vazamento de memória.

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@giu_d Osh que nada foi até bom mesmo!

 
14 minutos atrás, isrnick disse:

Eu prefiro usar ponteiro para arranjo ( (*ponteiro)[n] ), ao invés de ponteiro de ponteiro ( **ponteiro ):

Além dos motivos mencionados, é mais elegante.

 

 

Agora leia mais uma vez enunciado da lista, e diz se é do jeito que você pensa @isrnick .

8 horas atrás, Josesousa disse:

3. Construa um programa (main) que aloque em tempo de execução (dinamicamente) uma matriz de ordem m x n(linha por coluna), usando 1+m chamadas a função malloc. Agora, aproveite este programa para construir uma função que recebendo os parametros m e n aloque uma matriz de ordem m x n e retorne um ponteiro para esta matriz alocada. Crie ainda uma função para liberar a área de memória alocada pela matriz. Finalmente, crie um novo programa (main) que teste/use as duas funções criadas acima.

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@isrnick Cara... devo dizer q esse dias atrás quis fazer um código usando essa questão de só um malloc e um só free usando a sintaxe abaixo em uma função q retornava essa matriz:

char (*mat)[50];

E aí no main a mesma coisa para a matriz q iria receber o retorno dessa função, mas dava um warning e não consegui resolver. Agora taí a resposta para o erro q estava dando :(

9 minutos atrás, isrnick disse:

ponteiro para arranjo 

 

Link para o comentário
Compartilhar em outros sites

Para mim era mais intuitivo trabalhar usando ponteiro para ponteiro pois estavos fazendo algo similar (ponteiro para inteiro) no vetor.

@AnsiC Por isso que não estava entendendo o link que voce enviou, pois lá, se me recordo, não falava sobre criar dinamicamente diretamente. Fora nas pesquisas que fiz encontrei somente usando de ponteiro para ponteiro.

Sobre a funcao libera eu cheguei a modificar o meu aqui. Colocando num for, so que parece que liberaria so a segunda dimensao, baseando no codigo do @giu_d

 

@isrnick Nome de funcao estranha, ainda mais com esses paranteses separando ele do seu tipo. Parece uma matriz, ainda mais com esses colchetes no final.

1 hora atrás, isrnick disse:

int (*novo_arranjo(int nlinhas, int ncolunas))[] {

int (*matriz)[ncolunas] = NULL;

matriz = malloc(nlinhas * sizeof *matriz);

 

E aqui embaixo voce não colocou o igual lá em cima (sem o * e o parenteses). São tantas nuances. MAS LEGAL SABER DESSA POSSIBILIDADE.:thumbsup:

1 hora atrás, isrnick disse:

matriz = novo_arranjo(4, 5);

 

:D

Link para o comentário
Compartilhar em outros sites

@Josesousa Sim, esta notação (*ponteiro)[n] criar 1 ponteiro que aponta para um arranjo/vetor inteiro, ao invés de apontar para apenas 1 variável como num ponteiro normal, assim se você incrementa sobre o ponteiro estará incrementando proporcionalmente ao tamanho do arranjo, logo passa a apontar para o próximo arranjo (nesse caso a próxima linha da matriz).

 

Ex:

 

- linha 1 e coluna 0: 

(*(ponteiro + 1))[0]

ou

ponteiro[1][0]

 

 

adicionado 8 minutos depois
13 minutos atrás, Josesousa disse:

Agora colocando para rodar o programa , nao rodou não.

Bom meu programa não faz nada, só aloca e libera uma matriz. Mas em todos os lugares que testei compila e roda sem problemas, que erro deu?

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@isrnick  Daria para passar um exemplo do algo parecido com o q você acaba d explicar:

#include <stdio.h>

int main(void) {

    static int M[5] = { 92, 81, 70, 69, 58};
    int i;
    // O nome de uma matriz é um ponteiro constante
    for (i = 0; i < 5; i++)
        printf("%d\n", M[i]); // Notacao Matriz

    printf("\n");

    for (i = 0; i < 5; i++)
        printf("%d\n", *(M + i)); // Notacao ponteiro

    return 0;
}

Foge um pouco do assunto, mas é q me empolguei com o negócio hehe

Link para o comentário
Compartilhar em outros sites

@giu_d Sim, eu até postei um código num tópico demonstrando que as notações de ponteiro e de vetores são intercambiáveis e valem em todas as situações:

 

Em 04/07/2018 às 23:58, isrnick disse:

Fiz outro exemplo, agora usando as notações de ponteiros e de vetores, demonstrando que ambas são válidas para todos os casos:


#include <stdio.h>

int main()
{
    /* Para variaveis: */
    
    int d = 10; //variavel
    printf("d = %d\n", d         ); //normal
    printf("d = %d\n", *(&d)     ); //notacao de ponteiros
    printf("d = %d\n", *(&d + 0) ); //notacao de aritmetica de ponteiros
    printf("d = %d\n", (&d)[0]   ); //notacao de vetores
    printf("\n");
    
    
    int *p; //ponteiro
    
    p = &d; //guarda uma copia da referencia de d no ponteiro p
    printf("*p = %d\n", *p       ); //notacao de ponteiros
    printf("*p = %d\n", *(p + 0) ); //notacao de aritmetica de ponteiros
    printf("*p = %d\n", p[0]     ); //notacao de vetores
    *p = 20; //atribuicao de valor
    printf("*p = %d --- d = %d\n", *p, d); //alterou o valor de d
    printf("\n");
    
    
    /* Para vetores: */
    
    int vet[2]; //vetor
    
    vet[0] = 5; //atribuicao com notacao de vetores
    *(vet + 1) = 7; //atribuicao com notacao de ponteiros
    printf("vet[0] = %d | vet[1] = %d\n", *vet       , *(vet + 1) ); //notacao de ponteiros
    printf("vet[0] = %d | vet[1] = %d\n", *(vet + 0) , *(vet + 1) ); //notacao de aritmetica de ponteiros
    printf("vet[0] = %d | vet[1] = %d\n", vet[0]     , vet[1]     ); //notacao de vetores
    printf("\n");
    
    
    int *pv; //ponteiro
    
    pv = vet; //guarda uma copia da referencia de vet no ponteiro pv
    printf("pv[0] = %d | pv[1] = %d\n", *pv       , *(pv + 1) ); //notacao de ponteiros
    printf("pv[0] = %d | pv[1] = %d\n", *(pv + 0) , *(pv + 1) ); //notacao de aritmetica de ponteiros
    printf("pv[0] = %d | pv[1] = %d\n", pv[0]     , pv[1]     ); //notacao de vetores
    pv[0] = 6; //atribuicao com notacao de vetores
    *(pv + 1) = 8; //atribuicao com notacao de ponteiros
    printf("pv[0] = %d | pv[1] = %d --- vet[0] = %d | vet[1] = %d\n",
                *pv, *(pv + 1), vet[0], vet[1]); //alterou  vet[0] e vet[1]
    printf("\n");
    
    
    return 0;
}

 

Execute o código aqui: https://onlinegdb.com/ry8NUZoMQ

 

Note que o código usa as diferentes notações para fazer as mesmas coisas várias vezes, de maneiras diferentes.

 

Claro, algumas dessas notações não são convenientes de usar, mas isso foi só pra fazer uma demonstração de que são válidas, e tentar passar a ideia de como são obtidas e passadas/copiadas as referências/endereços de memória de variáveis ou de vetores para ponteiros. Funciona do mesmo modo quando fazemos essa passagem para ponteiros nos parâmetros de funções.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@Josesousa Esse seria um pequeno exemplo do uso da função q o @isrnick mostrou p gente um pouco acima:

#include <stdio.h>
#include <stdlib.h>

char (*novo_arranjo(int nlinhas, int ncolunas))[] {

    char (*matriz)[ncolunas] = NULL;

    matriz = malloc(nlinhas * sizeof *matriz);

    if (matriz == NULL){
        printf("\nERRO: Memoria livre insuficiente!\n");
        exit(EXIT_FAILURE);
    }
    return matriz;
}

void limpa_linha() {
    scanf("%*[^\n]");
    scanf("%*c");
}

int main() {

    char (*matriz)[40], i;

    matriz = novo_arranjo(2, 40);

    for (i = 0; i < 2; i++) {
        printf("Digite o nome %d: ", i + 1);
        scanf(" %39[^\n]", matriz[i]); // ou *(matriz + i)
        limpa_linha();
    }

    printf("\n");

    for (i = 0; i < 2; i++) printf("%s\n", matriz[i]);

    free(matriz);

    return 0;
}

@isrnick Tá certo o uso do scanf

Link para o comentário
Compartilhar em outros sites

@Josesousa Olá. Pelo q notei o @isrnick não está online. Nesse caso p você entender bem a respeito dessa função limpa_linha vou t passar um tópico onde o @isrnick mesmo explica d maneira detalhada o funcionamento dessa função

https://www.clubedohardware.com.br/forums/topic/1307160-erro-ao-atualizar-dados-de-arquivo/

Creio q é importante você entender bem a respeito dessa função e assim já passar a fazer uso da mesma em seus projetos

 

Link para o comentário
Compartilhar em outros sites

@AnsiC Olá. Vi acima um post onde é usada a função calloc em um código.

Semana passada mesmo estava estudando a respeito dessa função e no livro q estou usando é falado q essa função (calloc), internamente, chama a função malloc. Está correto isso?

Pergunto porque nesse livro não foi dada uma explicação mais detalhada a respeito disso q comentei

Link para o comentário
Compartilhar em outros sites

@giu_d Olá, bom dia!

 

 

C é uma linguagem de programação incrível, essa é minha a opinião, e todos os finais de semana aprendoemos algo novo, ontem foi este protótipo que @isrnick nos mostrou na função do problema de @Josesousa , lindo protótipo de sintaxe bonita e confusa que representa o retorno de um ponteiro. O C tem uma bela sintaxe, elegante e izas.

 

C em termos de Sintaxe, só perda para o que vejo em Object-C. Para mim, ponteiro é marca registrada do C não existe C sem ponteiro, isso é uma questão valorativa.  Nessa categoria vem a dupla sertaneja malloc & calloc, cujo as diferença realmente significativas é nenhuma. Sintaticamente é a mesma coisa, com uma pequena diferença que conseguimos apreciar do lado de fora em seus protótipos. 

 

13 minutos atrás, giu_d disse:

 [...] internamente, chama a função malloc [...] Está correto isso?

Não faço a menor ideia do que existe no lado de dentro dessas funções, suponho que varias chamadas para API do sistema operacional exclusivamente que libere memória para o processo corrente. E respondo que SIM, de certo com preconceito, pois não li em lugar algum coisa do gênero, daí o motivo do meu preconceito. Muito possivelmente tirando o algoritmo de zero-inicialização de bytes, não há nada no comportamento de calloc que a faça diferente de malloc. Inclusive supor que um é interna da outra, também vem a ser perfeitamente lógico SIM. Eu inclusive, predileto o uso canônico de malloc, e deixo a calloc ao acaso.

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!