Beraldo 864 Denunciar post Postado Outubro 26, 2008 Preciso recuperar uma matriz salva num arquivo binário. O problema é que essa matriz é alocada dinamicamente antes de ser salva no arquivo, então, ao ler o arquivo, não se sabe o tamanho dela. E, ao ler os seus valores, dá falha de segmentação. A fim de testes, criei este código: #include <stdio.h> #include <stdlib.h> #define ARQ "teste.bin" typedef struct { int x; int m_linhas; int m_colunas; char **matriz; } my_struct; void salvar(); void recuperar(); int main() { salvar(); recuperar(); return 0; } void salvar() { my_struct st; int i = 0, j = 0, cont = 40; FILE *fp; st.x = 42; st.m_linhas = 5; st.m_colunas = 2; if ((st.matriz = (char **) malloc(st.m_linhas * sizeof(char *))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } for (i = 0; i < st.m_linhas; i++) { if ((st.matriz[i] = (char *) malloc(2 * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } } printf("Definido...\n"); for (i = 0; i < st.m_linhas; i++) { for (j = 0; j < st.m_colunas; j++) { st.matriz[i][j] = (char)cont; printf("matriz[%d][%d] = %c\n", i, j, st.matriz[i][j]); cont++; } } fp = fopen(ARQ, "wb"); fwrite(&st, sizeof(my_struct), 1, fp); fclose(fp); for (i = 0; i < st.m_linhas; i++) { free(st.matriz[i]); } free(st.matriz); } void recuperar() { FILE *fp; my_struct st; int i = 0, j = 0; fp = fopen(ARQ, "rb"); fread(&st, sizeof(my_struct), 1, fp); fclose(fp); puts("\n\n\nRecuperando..."); printf("st.x = %d\n", st.x); for ( i = 0; i < st.m_linhas; i++) { for (j = 0; j < st.m_colunas; j++) { printf("matriz[%d][%d] = %c\n", i, j, st.matriz[i][j]); } } } Tentei, após o fread(), alocar memória para a matriz e chamar fread() de novo, mas não deu certo. void recuperar() { FILE *fp; my_struct st; int i = 0, j = 0; fp = fopen(ARQ, "rb"); fread(&st, sizeof(my_struct), 1, fp); if ((st.matriz = (char **) malloc(st.m_linhas * sizeof(char *))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } for (i = 0; i < st.m_linhas; i++) { if ((st.matriz[i] = (char *) malloc(2 * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } } fread(&st, sizeof(my_struct), 1, fp); fclose(fp); puts("\n\n\nRecuperando..."); printf("st.x = %d\n", st.x); for ( i = 0; i < st.m_linhas; i++) { for (j = 0; j < st.m_colunas; j++) { printf("matriz[%d][%d] = %c\n", i, j, st.matriz[i][j]); } } } Com essa modificação na função recuperar, ocorre o seguinte: $ gcc teste.c -o teste && ./teste Definido... matriz[0][0] = ( matriz[0][1] = ) matriz[1][0] = * matriz[1][1] = + matriz[2][0] = , matriz[2][1] = - matriz[3][0] = . matriz[3][1] = / matriz[4][0] = 0 matriz[4][1] = 1 Recuperando... st.x = 42 matriz[0][0] = matriz[0][1] = matriz[1][0] = p matriz[1][1] = matriz[2][0] = P matriz[2][1] = matriz[3][0] = 0 matriz[3][1] = matriz[4][0] = matriz[4][1] = Como posso solucionar esse problema? Compartilhar este post Link para o post Compartilhar em outros sites
José Enésio 4 Denunciar post Postado Outubro 27, 2008 Sugestão: Antes de cada matriz salva no arquivo, grave a ordem dela. typedef struct __ordem { int linhas; int colunas; } Ordem; Leia uma vez a ordem com fread Ordem ordem_matriz; fread(&ordem_matriz, sizeof(Ordem), 1, fp); Crie uma nova matriz de char como você quiser fazer. Agora não sei qual seria a maneira correta de criar uma matriz dinâmica multidimensional, se seria primeiro mallocar as linhas e então passar um for mallocando as colunas (kkkkk), ou mallocar direto o tamanho normal real, acho que o certo é a primeira opção não tenho certeza. Vou esperar a isis me corrigir :P Leia a quantidade de dados necessária de acordo com o que leu na Ordem. ordem_matriz.linhas * ordem_matriz.colunas * sizeof(char) Leia isso na nova matriz. Se você vai ler mais matrizes de um único arquivo, sugiro criar um header no seu arquivo, contendo a quantidade de matrizes e alguma outra informação que seja importante, e ler esse header antes de mais nada (header é uma struct que tu grava no arquivo antes de tudo mais, e é a primeira coisa que você lê do arquivo, geralmente contém informações importantes como por exemplo, a versão do arquivo, a quantidade de dados, onde começam os dados reais, quantas estruturas tem que ler, entre outras coisas). Você pode gazer algumas complicações com as funções de arquivo e algumas gambiarras pra saber se tem mais matrizes no arquivo, talvez até ficasse mais flexível mas só se o usuário vai poder e saber editar o arquivo diretamente com um editor de texto, aí no caso ele não tem obrigação de saber sobre os headers utilizados no seu programa, mas se é só seu programa que vai ler e escrever esses arquivos, escrever um header no início do arquivo seria a forma mais tri pra fazer isso. Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 27, 2008 Quanto ao malloc, uso sempre a primeira opção citada por você. :D São várias matriz, em estrturas diferentes. Eu pensei em fazer o que você sugeriu, mas imaginei que poderia haver uma forma diferente. Vou fazer isso amanhã cedo (agora estou começando a ficar com sono :P ) aí digo se deu certo. http://forum.imasters.com.br/public/style_emoticons/default/thumbsup.gif Obrigado Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 27, 2008 Ainda não deu certo... :( #include <stdio.h> #include <stdlib.h> #define ARQ "teste.bin" typedef struct { int x; int m_linhas; int m_colunas; char **matriz; } my_struct; typedef struct { int m_linhas; int m_colunas; } DIMENSOES; void salvar(); void recuperar(); int main() { salvar(); recuperar(); return 0; } void salvar() { my_struct st; DIMENSOES dims; int i = 0, j = 0, cont = 40; FILE *fp; st.x = 42; st.m_linhas = 5; st.m_colunas = 2; if ((st.matriz = (char **) malloc(st.m_linhas * sizeof(char *))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } for (i = 0; i < st.m_linhas; i++) { if ((st.matriz[i] = (char *) malloc(st.m_colunas * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } } printf("Definido...\n"); for (i = 0; i < st.m_linhas; i++) { for (j = 0; j < st.m_colunas; j++) { st.matriz[i][j] = (char)cont; printf("matriz[%d][%d] = %c\n", i, j, st.matriz[i][j]); cont++; } } dims.m_linhas = st.m_linhas; dims.m_colunas = st.m_colunas; fp = fopen(ARQ, "wb"); fwrite(&dims, sizeof(DIMENSOES), 1, fp); fwrite(&st, sizeof(my_struct), 1, fp); fclose(fp); for (i = 0; i < st.m_linhas; i++) { free(st.matriz[i]); } free(st.matriz); } void recuperar() { FILE *fp; my_struct st; DIMENSOES dims; int i = 0, j = 0; fp = fopen(ARQ, "rb"); fread(&dims, sizeof(DIMENSOES), 1, fp); printf("\n\nDimensões: %d x %d\n\n", dims.m_linhas, dims.m_colunas); if ((st.matriz = (char **) malloc(dims.m_linhas * sizeof(char *))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } for (i = 0; i < dims.m_linhas; i++) { if ((st.matriz[i] = (char *) malloc(dims.m_colunas * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } } fread(&st, sizeof(my_struct), 1, fp); fclose(fp); puts("\n\n\nRecuperando..."); printf("st.x = %d\n", st.x); for ( i = 0; i < st.m_linhas; i++) { for (j = 0; j < st.m_colunas; j++) { printf("matriz[%d][%d] = %c\n", i, j, st.matriz[i][j]); } } } Os valores das dimensões são recuperados corretamente. Faço a alocação da matriz, mas o resultado é o mesmo que postei anteriormente. Compartilhar este post Link para o post Compartilhar em outros sites
Antoniosp 2 Denunciar post Postado Outubro 27, 2008 [...] Agora não sei qual seria a maneira correta de criar uma matriz dinâmica multidimensional, se seria primeiro mallocar as linhas e então passar um for mallocando as colunas (kkkkk), ou mallocar direto o tamanho normal real, acho que o certo é a primeira opção não tenho certeza. Vou esperar a isis me corrigir :P [...] Então, eu sei que é meio chato isso, mas estou entrando de gaiato porque estava com essa mesma dúvida nesse post. Pelo que vi na solução do Beraldo, fiz do jeito dele. Tava com dúvida se precisava criar apontador do tipo ** mesmo. Se achar outra coisa nos diga, José. E Beraldo, o problema com a sua aplicação é que o programa está lendo os endereços de memória dos ponteiros, e não o conteúdo dos mesmos. Quando você passa o ponteiro da **matriz, o programa lerá a matriz, na verdade o vetor, de ponteiros mas não se redirecionará para ler o conteúdo a que eles apontam. E pior, após ler esse vetor ele continua lendo a memória logo após o fim do vetor, que não é, necessariamente, o começo da próxima linha (já que a matriz foi alocada dinamicamente). Pensei agora numa solução: alocar o primeiro vetor (**matriz) normalmente. Depois fazer uma alocação de todas as 10 (linhas*colunas) posições de uma vez, e só então redirecionar os ponteiros da **matriz para o começo de cada linha. Vou tentar agora e já posto. Abraço ----------- Edit ---------- Eita, quanta besteira falei nesse post... esquece tudo! :P Compartilhar este post Link para o post Compartilhar em outros sites
Antoniosp 2 Denunciar post Postado Outubro 27, 2008 Bom, depois debulhar as funções de fwrite e fread para entender como funcionam, consegui resolver o problema: #include <stdio.h> #include <stdlib.h> #define ARQ "teste.bin" typedef struct { int m_linhas; int m_colunas; } DIMENSOES; void salvar(); void recuperar(); int main() { salvar(); recuperar(); getchar(); return 0; } void salvar() { char **matriz; DIMENSOES dims; int i = 0, j = 0, cont = 40; FILE *fp; dims.m_linhas = 5; dims.m_colunas = 2; if ((matriz = (char **) malloc(dims.m_linhas * sizeof(char *))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } for (i = 0; i < dims.m_linhas; i++) { if ((matriz[i] = (char *) malloc(dims.m_colunas * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } } printf("Definido...\n"); for (i = 0; i < dims.m_linhas; i++) { for (j = 0; j < dims.m_colunas; j++) { matriz[i][j] = (char)cont; printf("matriz[%d][%d] = %c\n", i, j, matriz[i][j]); cont++; } } fp = fopen(ARQ, "wb"); fwrite(&dims, sizeof(DIMENSOES), 1, fp); for (i = 0; i < dims.m_linhas; i++) { fwrite(matriz[i], sizeof(char), dims.m_colunas, fp); } fclose(fp); for (i = 0; i < dims.m_linhas; i++) { free(matriz[i]); } free(matriz); } void recuperar() { FILE *fp; char **matriz; DIMENSOES dims; int i = 0, j = 0; fp = fopen(ARQ, "rb"); fread(&dims, sizeof(DIMENSOES), 1, fp); printf("\n\nDimensões: %d x %d\n\n", dims.m_linhas, dims.m_colunas); if ((matriz = (char **) malloc(dims.m_linhas * sizeof(char *))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } for (i = 0; i < dims.m_linhas; i++) { if ((matriz[i] = (char *) malloc(dims.m_colunas * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } } for (i = 0; i < dims.m_linhas; i++) { fread(matriz[i], sizeof(char), dims.m_colunas, fp); } fclose(fp); puts("\n\n\nRecuperando..."); for ( i = 0; i < dims.m_linhas; i++) { for (j = 0; j < dims.m_colunas; j++) { printf("matriz[%d][%d] = %c\n", i, j, matriz[i][j]); } } } Bom, a minha primeira idéia de alocar um "salsichão" de chars e depois redirecionar os ponteiros da **matriz para ele foi descartada. Não faria diferença nenhuma. Deixei a alocação como estava. Não mantive aquela primeira estrutura my_struct porque ela não fazia muita coisa. Além de gravar aquele x (de teste, não era?) ela gravava de novo as dimensões da matriz e ainda gravava apenas o endereço do primeiro ponteiro da **matriz (não poderíamos aproveitá-lo para nada). Resolvi então declarar a **matriz na própria função mesmo, bele? Aí veio a solução: na hora de gravar, temos que gravar linha por linha e ainda dizer que cada linha tem o tamanho dims.m_colunas, sendo todos os elementos do tipo char. E a recuperação dos dados segue na mesma idéia: ler linha por linha e armazenar cada linha na matriz. Acho que ficou com um resultado satisfatório no final. :) Abraço! Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 27, 2008 A estrutura my_struct é inútil nesse exemplo, de fato. Mas esse código é um teste somente. Estou fazendo outra aplicação, que requer essa estrututura (há diversas outras informações nela). Por isso preciso salvar a estrutura e não somente a matriz. Aliás, não é apenas uma estrutura.São três. Cada uma delas possui uma, ou até mais matrizes desse tipo. Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 29, 2008 Problema resolvido. Como a matriz é dinâmica, não há como salvá-la no arquivo por meio da estrutura. É necessário salvá-la separadamente. O código final ficou assim: #include <stdio.h> #include <stdlib.h> #define ARQ "teste.bin" typedef struct { int x; int m_linhas; int m_colunas; char *matriz; } my_struct; void salvar(); void recuperar(); int main() { salvar(); recuperar(); return 0; } /****************************/ void salvar() { my_struct st; int i = 0, j = 0, cont = 42; FILE *fp; st.x = 42; st.m_linhas = 5; st.m_colunas = 2; if ((st.matriz = (char *) malloc(st.m_linhas * st.m_colunas * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } printf("Definido...\n"); for (i = 0; i < st.m_linhas; i++) { for (j = 0; j < st.m_colunas; j++) { *(st.matriz + i * st.m_colunas + j) = (char)cont; printf("matriz[%d][%d] = %c\n", i, j, *(st.matriz + i * st.m_colunas + j)); cont++; } } fp = fopen(ARQ, "wb"); fwrite(&st, sizeof(my_struct), 1, fp); fwrite(st.matriz, sizeof(char), st.m_linhas * st.m_colunas, fp); fclose(fp); free(st.matriz); } /************************************/ void recuperar() { FILE *fp; my_struct st; int i = 0, j = 0; fp = fopen(ARQ, "rb"); fread(&st, sizeof(my_struct), 1, fp); if ((st.matriz = (char *) malloc(st.m_linhas * st.m_colunas * sizeof(char))) == NULL) { fprintf(stderr, "Erro\n"); exit(1); } fread(st.matriz, sizeof(char), st.m_linhas * st.m_colunas, fp); fclose(fp); puts("\n\n\nRecuperando..."); printf("st.x = %d\n", st.x); for ( i = 0; i < st.m_linhas; i++) { for (j = 0; j < st.m_colunas; j++) { printf("matriz[%d][%d] = %c\n", i, j, *(st.matriz + i * st.m_colunas + j)); } } free(st.matriz); } /**********************************/ Não coloquei comentários no código. Mas se alguém tiver dúvidas sobre ele, pode postá-las. :) ) Compartilhar este post Link para o post Compartilhar em outros sites
Antoniosp 2 Denunciar post Postado Outubro 30, 2008 Ô Beraldo, conseguiu sozinho? Valeu pela consideração, viu? Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 30, 2008 Ô Beraldo, conseguiu sozinho? Valeu pela consideração, viu?Não pude usar sua solução pelo motivo que apresentei acima: a aplicação que fiz precisava daquela estrutura.Mas a gravação da matriz no arquivo é praticamente igual à maneira apresentada por você. http://forum.imasters.com.br/public/style_emoticons/default/thumbsup.gif Compartilhar este post Link para o post Compartilhar em outros sites
Antoniosp 2 Denunciar post Postado Outubro 30, 2008 É que nem pareceu que você tinha lido minha solução... Mas então, alocando com malloc(st.m_linhas * st.m_colunas * sizeof(char)) a matriz não fica como uma matriz "normal", né? Tipo o seu ponteiro de matriz é do tipo *, e não do **. Isso não muda muita coisa? Compartilhar este post Link para o post Compartilhar em outros sites
Beraldo 864 Denunciar post Postado Outubro 30, 2008 Li sua solução, sim. Testei o código também. Alocando como fiz, não dá para usar a notação de matriz. Tem que manipular a memória. É mais fácil de salvar num arquivo, já que não precisa de um loop. Aloca-se um vetor, mas o trata como se fosse uma matriz. http://forum.imasters.com.br/public/style_emoticons/default/thumbsup.gif Compartilhar este post Link para o post Compartilhar em outros sites