kodiak Posted May 25, 2012 at 01:17 PM Report #458078 Posted May 25, 2012 at 01:17 PM Olá pessoal. Estou aqui com uns problemas que requerem alguma explicação. tenho a seguinte estrutura: typedef struct nomes{ char *nome; char *apelido; }Nomes; typedef struct noNomes{ int numNomes; Nomes *identificacao; struct noNomes *next; struct noNomes *prev; }NoNomes; Basicamente tenho uma lista que o cabeçalho vai conter a quantidades de nomes inseridos no sistema, um ponteiro para uma estrutura de nomes e ponteiros para os nomes que estão antes e depois na lista. Para criar a minha lista, crio da seguinte forma: int criaListaNomes(NoNomes **inicioLista, NoNomes **fimLista){ Nomes *n; (*inicioLista) = (NoNomes *)malloc(sizeof(NoNomes)); n = (Nomes *)malloc(sizeof(Nomes)); if ((*inicioLista) == NULL || n == NULL){ return -1; } (*inicioLista)->numEquipas = 0; n->nome =""; n->localidade = ""; (*inicioLista)->next = NULL; (*inicioLista)->prev = NULL; *fimLista = *inicioLista; return 0; } No meu main vou criar a lista, chamar uma função que vai ler os dados de um ficheiro txt e esta função, chama uma função que adiciona cada uma das estruturas de nomes à lista. Os ficheiros estão num txt, linha a linha, com a seguinte forma nome;apelido Tenho o main assim: int main() { NoNomes *inicioNomes,*fimNomes; if(criaListaNomes(&inicioNomes,&fimNomes)){ printf("Erro. Nao alocou memoria ao criar a lista\n"); return 0; } /*Ler os dados dos ficheiros*/ leFicheiroNomes(inicioNomes,&fimNomes); /*Debug. Avança para o primeiro nome da lista e vê se está a imprimir o que deveria*/ inicioNomes = inicioNomes->next; printf("#%s\n", (inicioNomes->identificacao)->nome); return 0; } A minha função para ler o ficheiro é a seguinte: int leFicheiroNomes(NoNomes *inicioLista, NoNomes **fimLista){ char buffer[100], *nome,*apelido; Nome *n; FILE *ficheiro; ficheiro = fopen("ficheiro.txt","r"); /*Abre o ficheiro para escrita*/ if (ficheiro == NULL){ printf("Erro\n"); } else{ while(fgets(buffer, 100, ficheiro)!= NULL){ n = (Nome*) malloc(sizeof(Nome)); nome = (char*)malloc(sizeof(char*)); apelido = (char*)malloc(sizeof(char*)); if (n == NULL){ printf("Erro. Nao alocou memoria\n"); return -1; } nome = strtok(buffer,";\n"); apelido = strtok(NULL,";\n"); n->nome = nome; n->apelido = apelido; /*Debug para ver se a leitura do ficheiro está a ser bem efectuada*/ printf("####%s\n",n->nome); addNomes(inicioLista,fimLista,n); } } fclose(ficheiro); return 0; } a minha função para adicionar nomes na lista é a seguinte: /*Cria um nó na lista*/ int addNomes(NoNomes *inicio, NoNomes **fim, Nomes **nomes){ NoNomes *no1, *no2; no1 = (NoNomes*) malloc(sizeof(NoNomes)); if (no1 == NULL){ return -1; } no2 = (NoNomes*) malloc(sizeof(NoNomes)) if (no2 == NULL){ return -1; } no1->identificacao = nomes; no1->next = inicio->next; inicio->next = no1; no2 = no1->next; if (no2!= NULL){ no2->prev = no1; no1->prev = inicio; } else{ no1->prev = inicio; *fim = no1; } inicio->numNomes++; return 0; } O meu problema é o seguinte. Ao ler o ficheiro, quando faço o debug na função leFicheiroNomes verifico que com a leitura está tudo ok. Os nomes são impressos no ecrã. O problema é que quando envio esses dados para a função addNomes laguma coisa está mal. Na função main, quando faço o debug, é impresso o último nome da minha lista de ficheiros e além disso, o nome não é completo, isto é, se o nome for Manel, é impresso Mane. Alguém sabe o que estou a fazer mal? Obrigado, kodiak
pmg Posted May 25, 2012 at 01:33 PM Report #458081 Posted May 25, 2012 at 01:33 PM Repara na tua função leFicheiroNomes int leFicheiroNomes(NoNomes *inicioLista, NoNomes **fimLista){ char buffer[100], *nome,*apelido; Nome *n; FILE *ficheiro; ficheiro = fopen("ficheiro.txt","r"); /*Abre o ficheiro para escrita*/ if (ficheiro == NULL){ printf("Erro\n"); } else{ while(fgets(buffer, 100, ficheiro)!= NULL){ n = (Nome*) malloc(sizeof(Nome)); nome = (char*)malloc(sizeof(char*)); apelido = (char*)malloc(sizeof(char*)); if (n == NULL){ printf("Erro. Nao alocou memoria\n"); return -1; } nome = strtok(buffer,";\n"); apelido = strtok(NULL,";\n"); n->nome = nome; n->apelido = apelido; /*Debug para ver se a leitura do ficheiro está a ser bem efectuada*/ printf("####%s\n",n->nome); addNomes(inicioLista,fimLista,n); } } fclose(ficheiro); return 0; } As linha assinaladas não "jogam bem" umas com as outras. Primeiro metes um valor vindo do ficheiro em buffer; depois reservas uns pedaços de memória (os mallocs); depois deitas fora essa memória quando metes ponteiros para o buffer nas variaveis; e a seguir, na proxima leitura, alteras o conteudo para o qual os ponteiros apontam. Tens de copiar os caracteres para uma zona de memória reservada anteriormente. What have you tried? Não respondo a dúvidas por PM A minha bola de cristal está para compor; deve ficar pronta para a semana. Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!
kodiak Posted May 25, 2012 at 02:04 PM Author Report #458088 Posted May 25, 2012 at 02:04 PM As linha assinaladas não "jogam bem" umas com as outras. Primeiro metes um valor vindo do ficheiro em buffer; depois reservas uns pedaços de memória (os mallocs); depois deitas fora essa memória quando metes ponteiros para o buffer nas variaveis; e a seguir, na proxima leitura, alteras o conteudo para o qual os ponteiros apontam. Tens de copiar os caracteres para uma zona de memória reservada anteriormente. Olá pmg. Obrigado pela resposta. A minha ideia era colocar no buffer o que é lido pelo ficheiro, depois trabalhar o conteúdo do buffer para retirar o nome e o apelido e finalmente, pegar nesse conteúdo e colocar na memória que criei com os mallocs. O que estás a dizer é que o strtok não está a devolver os caracteres mas sim um ponteiro? E é esse ponteiro que eu estou a colocar nos meus chars? Como posso copiar os caracteres devolvidos? Desculpa mas não estou a dar com isto. Desde já obrigado, kodiak
pmg Posted May 25, 2012 at 02:15 PM Report #458094 Posted May 25, 2012 at 02:15 PM Para copiar uma string usa a função strcpy(). Mas verifica que tens espaço suficiente no destino! Como vais fazer isto em loop, certifica-te que cada linha é copiada para um sítio diferente da linha anterior ... senão ficas sempre só com a última linha. What have you tried? Não respondo a dúvidas por PM A minha bola de cristal está para compor; deve ficar pronta para a semana. Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!
kodiak Posted May 25, 2012 at 02:27 PM Author Report #458099 Posted May 25, 2012 at 02:27 PM Para copiar uma string usa a função strcpy(). Mas verifica que tens espaço suficiente no destino! Como vais fazer isto em loop, certifica-te que cada linha é copiada para um sítio diferente da linha anterior ... senão ficas sempre só com a última linha. Tinha tentado anteriormente com o strcpy() mas não tinha dado. Quando disseste Mas verifica que tens espaço suficiente no destino! Vi que os mallocs não estavam a allocar memória suficiente. Acho que já está direito. Pelo menos está a mostrar como devia. Por favor vê se é isto. Alterei para /*...........*/ nome = (char*)malloc(31*sizeof(char*)); apelido = (char*)malloc(31*sizeof(char*)); /*.............*/ strcpy(nome,strtok(buffer,";\n")); strcpy(apelido,strtok(NULL,";\n")); n->nome = nome; n->apelido= apelido; Assumindo que é isto que deva fazer, imagino que o próximo passo será fazer a alocação de memória apenas depois de fazer o strtok. Assim atribuo apenas a memória necessária. É isto? kodiak
pmg Posted May 25, 2012 at 02:36 PM Report #458104 Posted May 25, 2012 at 02:36 PM (edited) O malloc(31 * sizeof (char *)) reserva 124 bytes (suficiente para strings com 123 caracteres). Isso nao é necessariamente o suficiente para os dados "estapafurdios". Assumindo que é isto que deva fazer, imagino que o próximo passo será fazer a alocação de memória apenas depois de fazer o strtok. Assim atribuo apenas a memória necessária. Exacto! tmpnome = strtok(buffer, ";\n"); if (tmpnome == NULL) abort(); /* erro */ nome = malloc(strlen(tmpnome) + 1); strcpy(nome, tmpnome); O cast ao valor devolvido pelo malloc é, quando muito, redundante; e pode esconder um erro para o qual o compilador te avisaria se não tiveese o tal cast. Edited May 25, 2012 at 02:37 PM by pmg 1 Report What have you tried? Não respondo a dúvidas por PM A minha bola de cristal está para compor; deve ficar pronta para a semana. Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!
kodiak Posted May 25, 2012 at 02:40 PM Author Report #458106 Posted May 25, 2012 at 02:40 PM Obrigado pmg. Está a tentar não usar uma variável temporária para guardar os dados do strtok mas estava a dar barracada. Muito obrigado pela ajuda 🙂 kodiak
Happening Posted May 26, 2012 at 03:00 PM Report #458221 Posted May 26, 2012 at 03:00 PM Apesar de o tópico já estar resolvido deixo aqui uma sugestão. Tal como o pmg te disse os teus mallocs não estávam a alocar espaço suficiente. Quando fizeres o malloc em vez de um malloc(número*sizeof(qualquercoisa)); deves utilizar no casa de strings (char*) malloc((strlen(str)+1)*sizeof(char)); deste modo evitas erros (o +1 deve-se às strings terem o caracter especial \0 que conta como um caracter, nunca te esqueças dele caso contrário vai-te dar erro de memória e passas horas à procura daquilo [experiencia própria])).
pmg Posted May 26, 2012 at 04:13 PM Report #458231 Posted May 26, 2012 at 04:13 PM deves utilizar no casa de strings (char*) malloc((strlen(str)+1)*sizeof(char)); Excepto que o cast ao valor de retorno do malloc é, quando muito, redundante; e pode esconder um erro para o qual o compilador te avisaria se não tiveese o tal cast e portanto nao deve ser usado. Alem disso, por definicao, o valor de sizeof (char) é 1, sendo por isso perfeitamente desnecessario, ficando assim ponteiro = malloc(strlen(str) + 1); Se queres mesmo usar o sizeof no calculo do numero de bytes a reservar, usa o obecto propriamente dito char *ponteiro; ponteiro = malloc(nelementos * sizeof *ponteiro); Assim, se o ponteiro deixar de ser um char * e passar a ser, por exemplo, um wchar_t * a instrucao que faz a reserva de memoria nao precisa de nenhuma alteracao wchar_t *ponteiro; ponteiro = malloc(nelementos * sizeof *ponteiro); What have you tried? Não respondo a dúvidas por PM A minha bola de cristal está para compor; deve ficar pronta para a semana. Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!
Happening Posted May 26, 2012 at 04:34 PM Report #458232 Posted May 26, 2012 at 04:34 PM (edited) Apenas utilizei o *sizeof(char) para se perceber que podia ser int, double, etc. Claro que o tamanho de char é 1 logo não é necessário por lá 🙂 Diz-me uma coisa, o facto de utilizarmos o sizeof(something) faz com que o programa seja mais lento? Se queres mesmo usar o sizeof no calculo do numero de bytes a reservar, usa o obecto propriamente ditoCódigo : char *ponteiro; ponteiro = malloc(nelementos * sizeof *ponteiro); Assim, se o ponteiro deixar de ser um char * e passar a ser, por exemplo, um wchar_t * a instrucao que faz a reserva de memoria nao precisa de nenhuma alteracao I saw what you did there 🙂 Vou passar a implementar como disseste. Com pointers é realmente a melhor maneira para fazer as alocações, um gajo está sempre a aprender 🙂 Edited May 26, 2012 at 04:39 PM by Happening
pmg Posted May 26, 2012 at 05:54 PM Report #458243 Posted May 26, 2012 at 05:54 PM (edited) Diz-me uma coisa, o facto de utilizarmos o sizeof(something) faz com que o programa seja mais lento? Nao, o sizeof (something) (excepto num caso especial (*)) é uma constante de compilacao. Ter no codigo sizeof (something) ou 42 (quando o something ocupar 42 bytes!) é igual. (*) O caso especial é quando o (something) é um VLA ("Variable Length Array"). Neste caso o valor de sizeof (something) nao é uma constante, mas é extremamente rapido a calcular ... nao faz o programa mais lento. Edited May 26, 2012 at 05:56 PM by pmg What have you tried? Não respondo a dúvidas por PM A minha bola de cristal está para compor; deve ficar pronta para a semana. Torna os teus tópicos mais atractivos e legíveis usando a tag CODE para colorir o código!
Happening Posted May 26, 2012 at 09:04 PM Report #458259 Posted May 26, 2012 at 09:04 PM Ok, esclarecido!
kodiak Posted May 31, 2012 at 09:42 AM Author Report #459348 Posted May 31, 2012 at 09:42 AM Viva pessoal. Não sei porquê mas não fui notificado dos novos posts à minha questão... Venho só aqui agradecer ao pmg e ao Happening por terem esclarecido ainda mais o problema. Obrigado. kodiak
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now