Enviado em 09/06/2018 - 15:02h
Dúvida em realação a alocação e endereçamento de matrizes [RESOLVIDO]
Responder tópico2. Re: Dúvida em realação a alocação e endereçamento de matrizes
Enviado em 09/06/2018 - 17:27h
Portanto, QUE DIABOS TEM NESSE CÓDIGO?
Quando você faz isso:int **matrix=(int**)malloc(ROWS*sizeof(int*)); //Alocando as linhas da matrizCada linha da matriz vai ser alocada em um endereço que muito provavelmente não vai ser contíguo ao da linha anterior.
for(unsigned int i=0; i<ROWS; i++){
matrix[i]=(int*)malloc(COLUMNS*sizeof(int)); //Alocando as colunas
}
O SO pode dar qualquer endereço a cada malloc que vc chama....
De forma que isso aqui não tem sentido nenhum:
int *ptr=matrix[0];Pois você está lendo apenas a primeira linha da matriz e depois saindo pra fora do limite dela, lendo valores aleatórios da memória...
//Exibindo valores
for(unsigned int i=0; i<(ROWS*COLUMNS); i++){
printf("[%d] ", ptr[i]);
}
Na versão usando alocação automática (stack) isso dá certo pois quando acaba uma linha obrigatoriamente vai começar a outra pois um array obrigatoriamente tem endereços contiguos de memória.
Mas isso não significa que é uma boa prática de programação mesmo que funcione.
O certo seria algo assim:
//Exibindo valoresEm resumo: Alocação automática (stack) os elementos vão estar todos um depois do outro. Já na alocação dinâmica (heap) a cada malloc que você chama vai ser obtido um endereço qualquer...
for(unsigned int row=0; row<ROWS; row++){
int* ptr = matrix[row]; // Nem é necessário isso, assumo que vc queira o ponteiro pra outra coisa
for(unsigned int column=0; column<COLUMNS; column++){
printf("[%d] ", ptr[column]);
}
printf("\n");
}
3. Re: Dúvida em realação a alocação e endereçamento de matrizes
Enviado em 09/06/2018 - 17:54h
Agora utilizando os preceitos de POG (Programação Orientada a Gambiarras)
Note que se você utilizar apenas um malloc todos endereços vão ser contíguos, mesmo usando alocação dinâmica.
Aqui um código igual ao seu, que apesar de não ser correto, funciona:
Abração
Note que se você utilizar apenas um malloc todos endereços vão ser contíguos, mesmo usando alocação dinâmica.
Aqui um código igual ao seu, que apesar de não ser correto, funciona:
Espero que vc tenha entendido a diferença.
#include <stdio.h>
#include <stdlib.h>
#define ROWS 4
#define COLUMNS 4
int main(void){
// Inicializando com 1 malloc pra tudo
int **matrix=(int**)malloc(sizeof(int*) * ROWS);
matrix[0]=(int*)malloc(sizeof(int) * ROWS * COLUMNS);
for(int i = 0; i < ROWS; i++) // Arrumando os ponteiros
matrix[i] = (*matrix + COLUMNS * i);
//Preenchendo a matriz
for(unsigned int row=0; row<ROWS; row++){
for(unsigned int column=0; column<COLUMNS; column++){
matrix[row][column]=42; //42? Seria isso a resposta para "tudo"?
}
}
int *ptr=matrix[0];
//Exibindo valores
for(unsigned int i=0; i<(ROWS*COLUMNS); i++){
if (i % ROWS == 0)
printf("\n");
printf("[%d] ", ptr[i]);
}
free(matrix[0]);
free(matrix); //Desalocando
return 0;
}
Abração
4. Re: Dúvida em realação a alocação e endereçamento de matrizes
Enviado em 11/06/2018 - 22:03h
Talvez até não tenha nada de errado. Mas não me parece certo... Sei lá, costume é difícil de mudar...
Digamos que você tenha uma matriz[4][4]
O ponteiro começa com matriz[0]...
Você começa imprimindo em matriz[0][0], matriz[0][1], matriz[0][2].... e assim por diante
Quando chega em matriz[0][3] ele depois vai para matriz[0][4] pois está lendo apenas a linha matriz[0].
Porém matriz[0][4] não existe (aqui existe porque eu aloquei, mas no codigo dele não e da forma que geralmente é feito também não) e você estaria lendo pra fora dos limites do array (que tem indices de 0 a 3)
Acontece que por uma coincidência - forçada propositalmente neste caso - o endereço de matriz[1][0] na linha seguinte vai ser o mesmo. Pois os endereços são contíguos na memória e por isso o código funciona imprimindo a matriz inteira.
Eu forcei a barra pra explicar para o autor da pergunta o que estava acontecendo...
Acredito que não deva dar problema se você desalocar da mesma forma que alocou...
Se alocar de um jeito e desalocar de outro daí acho que não é bom...
Eu considero POG porque você está mascarando uma matrix em um array, daí a pessoa que for usar vai estar usando uma coisa achando que é outra...
Comprando gato por lebre ;)
Digamos que você tenha uma matriz[4][4]
O ponteiro começa com matriz[0]...
Você começa imprimindo em matriz[0][0], matriz[0][1], matriz[0][2].... e assim por diante
Quando chega em matriz[0][3] ele depois vai para matriz[0][4] pois está lendo apenas a linha matriz[0].
Porém matriz[0][4] não existe (aqui existe porque eu aloquei, mas no codigo dele não e da forma que geralmente é feito também não) e você estaria lendo pra fora dos limites do array (que tem indices de 0 a 3)
Acontece que por uma coincidência - forçada propositalmente neste caso - o endereço de matriz[1][0] na linha seguinte vai ser o mesmo. Pois os endereços são contíguos na memória e por isso o código funciona imprimindo a matriz inteira.
Eu forcei a barra pra explicar para o autor da pergunta o que estava acontecendo...
Acredito que não deva dar problema se você desalocar da mesma forma que alocou...
Se alocar de um jeito e desalocar de outro daí acho que não é bom...
Eu considero POG porque você está mascarando uma matrix em um array, daí a pessoa que for usar vai estar usando uma coisa achando que é outra...
Comprando gato por lebre ;)
5. Re: Dúvida em realação a alocação e endereçamento de matrizes
Enviado em 12/06/2018 - 01:59h
Não considero POG. É uma maneira de fazer mais eficiente em espaço e em tempo, por alocar (e gastar espaço de gerenciamento para) apenas 2 ponteiros, em vez de N+1. Você até tem os N+1 ponteiros, mas N-1 deles reaproveitam pedaços da segunda alocação.
Nessa ideia, apenas duas coisas me incomodam, uma muito pouco, e outra um bocado mais. O que me incomoda pouco é a ligeira assimetria, que se deve ao fato de a primeira “linha” da matriz ser construída de um jeito, e as demais, de outro.
A segunda coisa, que me incomoda mais, é a falta de encapsulamento. Como você está mostrando o “como fazer”, não há muito como fugir disso. Mas ter esses ponteiros todos visíveis é algo que provavelmente seria melhor evitar.
Para encapsular, eu pensei na seguinte ideia em C++. Note que em momento nenhum eu devolvo um objeto que possa ser usado para chegar ao ponteiro alocado para conter os dados (isto é: nem como ponteiro diretamente, nem como referência direta para algum elemento do array usado internamente — especialmente o primeiro elemento da primeira linha, cujo endereço é igual ao do array). Para isso eu tive de criar um tipo para encapsular ponteiros para as linhas, e outro para encapsular elementos individuais, bem como os devidos operadores.
Nessa ideia, apenas duas coisas me incomodam, uma muito pouco, e outra um bocado mais. O que me incomoda pouco é a ligeira assimetria, que se deve ao fato de a primeira “linha” da matriz ser construída de um jeito, e as demais, de outro.
A segunda coisa, que me incomoda mais, é a falta de encapsulamento. Como você está mostrando o “como fazer”, não há muito como fugir disso. Mas ter esses ponteiros todos visíveis é algo que provavelmente seria melhor evitar.
Para encapsular, eu pensei na seguinte ideia em C++. Note que em momento nenhum eu devolvo um objeto que possa ser usado para chegar ao ponteiro alocado para conter os dados (isto é: nem como ponteiro diretamente, nem como referência direta para algum elemento do array usado internamente — especialmente o primeiro elemento da primeira linha, cujo endereço é igual ao do array). Para isso eu tive de criar um tipo para encapsular ponteiros para as linhas, e outro para encapsular elementos individuais, bem como os devidos operadores.
#include <iostream>
#include <cstddef>
class matriz {
private:
size_t _lins, _cols;
int *_elementos;
class linha {
private:
friend class matriz;
int *_elementos;
size_t _cols;
class elemento {
private:
friend class matriz::linha;
friend std::ostream &operator<<(std::ostream &, const elemento &);
int *_elemento;
elemento(int *p): _elemento(p) { }
elemento(const elemento &) = delete; // Impede construtor de cópia default.
elemento(elemento &&old): elemento(old._elemento) { }
public:
operator int() const { return *_elemento; } // Retorna cópia do inteiro, não referência.
elemento &operator=(int val){
*_elemento=val;
return *this; // Retorna referência para o encapsulador, não para o dado.
}
elemento &operator=(const elemento &outro){
*_elemento=*outro._elemento;
return *this; // Retorna referência para o encapsulador, não para o dado.
}
template <class T> operator T() const { return T(*_elemento); }
};
friend std::ostream &operator<<(std::ostream &, const elemento &);
linha(int *elems_linha, size_t cols): _elementos(elems_linha), _cols(cols) { }
linha(const linha &) = delete;
linha(linha &&old): linha(old._elementos, old._cols) { }
public:
size_t cols(){ return _cols; }
const elemento operator[](size_t col) const { return _elementos+col; }
elemento operator[](size_t col){ return _elementos+col; }
/*
Outros recursos:
- iterator/const_iterator sobre elementos da linha;
- funções begin()/cbegin()/end()/cend() etc.
*/
};
friend std::ostream &operator<<(std::ostream &, const linha::elemento &);
public:
matriz(size_t lins, size_t cols):
_lins(lins), _cols(cols), _elementos(new int [lins*cols])
{
}
virtual ~matriz(){ delete [] _elementos; }
size_t lins() const { return _lins; }
size_t cols() const { return _cols; }
const linha operator[](size_t lin) const { return linha(_elementos+lin*_cols, _cols); }
linha operator[](size_t lin){ return linha(_elementos+lin*_cols, _cols); }
/*
Outros recursos:
- iterator/const_iterator sobre linhas da matriz;
- funções begin()/cbegin()/end()/cend() etc.
*/
};
std::ostream &operator<<(std::ostream &os, const matriz::linha::elemento &e){
return os << int(e);
}
// Utiliza versões que retornam “const matriz::linha” e “const matriz::linha::elemento”.
void print(const matriz &m){
for(size_t l=0; l<m.lins(); l++){
for(size_t c=0; c<m.cols(); c++)
std::cout << '\t' << m[l][c];
std::cout << '\n';
}
}
int main(){
matriz m(3, 4);
int i=0;
for(size_t l=0; l<m.lins(); l++)
for(size_t c=0; c<m.cols(); c++)
m[l][c]=i++;
print(m);
}
6. Re: Dúvida em realação a alocação e endereçamento de matrizes [RESOLVIDO]
Enviado em 12/06/2018 - 11:44h
paulo1205 escreveu:
Não considero POG. É uma maneira de fazer mais eficiente em espaço e em tempo, por alocar (e gastar espaço de gerenciamento para) apenas 2 ponteiros, em vez de N+1. Você até tem os N+1 ponteiros, mas N-1 deles reaproveitam pedaços da segunda alocação.
Eu quis dizer eficiente em termos da alocação e algumas operações.Não considero POG. É uma maneira de fazer mais eficiente em espaço e em tempo, por alocar (e gastar espaço de gerenciamento para) apenas 2 ponteiros, em vez de N+1. Você até tem os N+1 ponteiros, mas N-1 deles reaproveitam pedaços da segunda alocação.
Para outros tipos de operação com matrizes, porém, essa forma de trabalhar é pouco conveniente. Há um outro tópico em discussão corrente na comunidade que fala sobre escalonamento de matrizes. Nesse caso, uma operação comum é trocar a ordem de linhas inteiras. Se a primeira linha é a única que tem uma alocação real, e as demais apontam para dados que são parte dessa alocação, a primeira linha deixa de poder ser diretamente trocada com qualquer das demais, e teriam de ser trocados os elementos em cada linha individualmente.
7. Re: Dúvida em realação a alocação e endereçamento de matrizes [RESOLVIDO]
Enviado em 16/06/2018 - 12:06h
Nada exato...não é como o stackoverflow...
Responder tópico
Entre na sua conta para responder.