Pergunta

Estou tentando implementar matrizes 3D contíguas dinamicamente alocadas em um código C. As matrizes devem ser contíguas porque estou confiando na saída NetCDF das matrizes. Agora eu adaptei uma solução postada aqui Solução de transbordamento de pilha. Isso funciona bem para alocar dinamicamente as matrizes e indexar -as ... no entanto, quando o NetCDF os gera, há um deslocamento que parece escalar como o 2º tamanho do índice (JCount). Aqui está a função modificada:

void*** newarray(int icount, int jcount, int kcount, int type_size)
{
  int i,j,k;
  void*** iret = (void***)malloc(icount*sizeof(void***)+icount*jcount*sizeof(void**)+icount*jcount*kcount*type_size);
  void** jret = (void**)(iret+icount);
  char* kret = (char*)(jret+icount*jcount);
  for(i=0;i<icount;i++)
  {
    iret[i] = &jret[i*jcount];
  }
  for(i=0;i<icount;i++)
  {
    for(j=0;j<jcount;j++)
    {
      jret[i*jcount+j] = &kret[i*jcount*kcount*type_size+j*kcount*type_size];
    }
  }
  return iret;
}

Se eu entendo que essa função corretamente o IRET é um espaço alocado para os ponteiros 3D que compõem o IRET (primeiro índice), os ponteiros 2D que compõem o JRET (2º índice) e o espaço para os valores reais que compõem o KRET. O ponteiro JRET 2D está então associado à seção de matriz 2D da IRET. Então o mesmo é feito para Kret. Em seguida, todo endereço do IRET é apontado para o primeiro valor de cada seção do JRET. Em seguida, cada endereço do JRET é apontado para o primeiro endereço do KRET.

Para o registro, tudo estava funcionando bem com os valores definidos pelo pré -processador para minhas matrizes. Além disso, se eu usar algumas instruções Printf no código para verificar os números das matrizes que todos parecem indexar corretamente e o código é executado corretamente, é apenas a saída parece ser o resultado do armazenamento de memória não contigioso das matrizes.

Eu tenho uma estrutura do formulário:

typedef struct
{
  double ***test;
} STRUCT_TYPE;

Que eu então alquei usando

mhd    = (STRUCT_TYPE *)  malloc(sizeof(STRUCT_TYPE));
mhd.test = (double***) newarray(101,7,101,sizeof(double));

Isso pode ser um problema com o NetCDF ... mas eu gostaria de saber que minha rotina de alocação não é o problema.

Foi útil?

Solução

Esta é realmente uma resposta para a pergunta na resposta de Lazer:

Isso me faz pensar que, quando C aloca memória para uma matriz, aloca a memória usada> para armazenar os valores primeiro, aloca a memória para os ponteiros que fornecem estrutura à matriz multidimensional.

Talvez alguém possa esclarecer isso para mim?

Há uma diferença muito fundamental em C entre

double arr[A][B][C];

e

double ***ptr;

Embora ambos possam ser indexados com x[i][j][k], o código da máquina resultante é muito diferente.

double arr[A][B][C] é uma variedade de uma matriz de matrizes B de C duplas. Ao indexar isso no código como arr[i][j][k], o compilador traduz isso para uma compensação de ((i*B + j)*C + k)*sizeof(double) bytes desde o início de arr. Não há ponteiros intermediários envolvidos aqui, mas as dimensões B e C devem ser conhecidas pelo compilador.

'Double *** ptr' é um ponteiro para (o início de uma matriz de) ponteiros para (o início de uma matriz de) ponteiros para (o início de uma matriz) o dobro. Ao indexar isso no código como ptr[i][j][k], o compilador não tem escolha a não ser fazer cada operação de indexação separadamente e seguir todos os ponteiros intermediários. Isso resulta em código semelhante a

temp1 = ptr[i];
temp2 = temp1[j];
result = temp2[k];

o newarray A função esculpe todos esses componentes-se destaca de um único bloco de memória, mas isso não é exigido pelo idioma e o compilador não tem o conhecimento de que isso está ocorrendo, por isso deve tratar todos os componentes como sendo completamente independentes um do outro.

Outras dicas

Bem, eu encontrei uma correção ... embora seja mais uma coisa de convenção. Quando originalmente projetei meu código, simplesmente usei uma diretiva de pré -processador para declarar meus tamanhos de matriz. Então eu simplesmente declarei cada matriz dentro da estrutura. Para salvar a memória, simplesmente passei um ponteiro para as estruturas para minhas sub-funções. Isso significava que, se eu ia fazer referência a um elemento fora da rotina principal (), usei algo como:

grid->x;

Agora e eu faço referência a cada elemento de x como

grid->x[i][j][k];

Obviamente, quando uma função netcdf precisava de um ponteiro para a variável, ela iria armazenar, eu apenas passei

grid->x

No entanto, usando essa nova função de alocação de memória, quando passo isso para uma função, estou realmente passando o primeiro endereço do espaço de memória reservado para os vários ponteiros. Em essência, eu estava passando um ponteiro para o endereço errado na memória. Tudo o que tive que fazer é mudar o argumento aprovado para:

&grid->x[0][0][0]

E eu recebo a saída de matriz adequada. Isso me faz pensar que, quando C aloca memória para uma matriz, aloca a memória usada para armazenar os valores primeiro, aloca a memória para os ponteiros que fornecem estrutura à matriz multidimensional.

Talvez alguém possa esclarecer isso para mim?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top