Erro na no meio do programa [RESOLVIDO]

1. Erro na no meio do programa [RESOLVIDO]

Rafael Alves Lagisck
lagisck

(usa Debian)

Enviado em 07/02/2013 - 10:45h

Pessoal da uma olhada nesse codigo:

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

struct tpcadastro
{
char nome[30];
char tel[10];
};
void cadastro(FILE *arq)
{
struct tpcadastro r;
arq=fopen("cadastro","r+b");
printf("CADASTRO\n");
printf("\nDigite seu nome:");
gets(r.nome);
while(strcmp(r.nome,"{TTEXTO}")!=0)
{
printf("\nDigite o telefone:");
fflush(stdin);
gets(r.tel);
fwrite(&r,sizeof(tpcadastro),1,arq);
printf("\nDigite seu nome:");
fflush(stdin);
gets(r.nome);
}
fclose(arq);
}

Apos eu digita o telefone, ele nao faz o laço, e me manda uma mensagem assim:

segmentation fault

O que pode ser
Obrigado
Rafael




  


2. Re: Erro na no meio do programa [RESOLVIDO]

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 07/02/2013 - 10:52h

sobre fwrite:

http://www.cplusplus.com/reference/cstdio/fwrite/?kw=fwrite

O segundo e terceiro parametro estão invertidos.

Outro ponto, o sizeof deve ser passado sizeof(struct tpcadastro).


3. invertido?

Rafael Alves Lagisck
lagisck

(usa Debian)

Enviado em 07/02/2013 - 10:59h

Como assim parametros invertidos?



4. Re: Erro na no meio do programa [RESOLVIDO]

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 07/02/2013 - 11:27h

fwrite( &(r), sizeof(char), sizeof(struct tpcadastro), arq );


5. Re: Erro na no meio do programa [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 07/02/2013 - 13:19h

uilianries escreveu:

O segundo e terceiro parametro estão invertidos.


Não estão, não (a menos que o autor tenha reeditado a mensagem original). A ordem dos argumentos: é um ponteiro para os dados, o tamanho em bytes de cada elemento, a quantidade de elementos (que deve ser sempre 1, a não ser que se estejam gravando elementos consecutivos de um array, quando então se usa o número de elementos a gravar), e o ponteiro para o arquivo. O que está invertido é o exemplo que você colocou em sua segunda postagem.

Outro ponto, o sizeof deve ser passado sizeof(struct tpcadastro).


Mais ou menos. Se ele estiver usando C++, ele poderia fazer fazer sizeof(tpcadastro) -- mas nada mais além do próprio uso de sizeof dá a entender que ele tenha desejado usar C++. Mas eu acho que sempre que o ponteiro usado no primeiro argumento não for do tipo void*, o melhor é inferir o tipo a partir da aplicação de sizeof sobre o próprio dado, como mostrado abaixo.

#define N_ELEMS 10
struct tm some_timestamp;
time_t some_time;
double dbl_array[N_ELEMS];
double *middle_element;
void *void_ptr;
int saved_recs;
FILE *file_ptr;

/* ... */

/* Uso com um dado não-array */
saved_recs=fwrite(&some_timestamp, sizeof some_timestamp, 1, file_ptr);
/* bem-sucedido se saved_recs==1 */

/* Uso com um array. */
saved_recs=fwrite(dbl_array, sizeof dbl_array[0], N_ELEMS, file_ptr);
/* bem-sucedido se saved_recs==N_ELEMS */

/* Uso com um ponteiro para um dado de tipo específico. */
middle_element=dbl_array+(N_ELEMS/2); /* equivalente a ``&dbl_array[N_ELEMS/2]´´ */
saved_recs=fwrite(middle_element, sizeof *middle_element, 1, file_ptr);
/* bem-sucedido se saved_recs==1 */

/* O dado passado a fwrite por meio de uma variável "void *" não pode
ter o tamanho obtido por meio de ``sizeof *void_ptr´´, logo é preciso
obter informação de outra forma: normalmente se especifica o tipo do
dado. A quantidade de elementos também precisa ser fixada na mão. */
some_time=time(NULL);
void_ptr=localtime(&some_time); /* retorna ponteiro para struct tm */
saved_recs=fwrite(void_ptr, sizeof (struct tm), 1, file_ptr);
/* bem-sucedido se saved_recs==1 */


Aliás, pegar o tamanho a partir do próprio dado é particularmente útil em macros e, em menor medida, em templates de funções em C++, quando o mesmo esqueleto pode ser usado para tipos de dados diferentes, como nos exemplos abaixo.

/* Exemplo de macro.  Vale em C e C++ */
#define salva_array(arq, array, n_elems) fwrite(array, sizeof array[0], n_elems, arq)

#define N_ELEMS 100

FILE *fp;
double dbl_array[100];
char str[20];

/* ... */

salva_array(fp, dbl_array, N_ELEMS);
salva_array(fp, str, sizeof str);


/* Exemplo em C++ */
template <typename T> size_t salva_array(FILE *fp, const T *array, size_t n_elems){
return fwrite(array, sizeof array[0], n_elems, fp);
}



6. Re: Erro na no meio do programa [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 07/02/2013 - 19:58h

Em tempo -- e eu não sei como não vi isso antes, sem ter de compilar o programa aqui e ter o mesmo erro -- a causa do problema é que o arquivo não é aberto, logo o ponteiro arq é nulo, e a chamada a fwrite() causa falha de segmentação quando a função tenta acesso ao conteúdo do ponteiro nulo.

Na verdade, há mais problemas na função cadastro. Para começar, tudo indica que arq deveria ser uma variável local, e não um argumento da função.

A forma de abrir o arquivo para leitura com atualização ("r+b") só funciona se o arquivo já existir, não o criando caso não exista. Usar "w+b", por outro lado, faria com que qualquer conteúdo de um arquivo preexistente fosse perdido. Contudo, é possível tentar abrir para atualização primeiro, e depois tentar criar o arquivo, se a primeira tetativa falhar, mais ou menos como mostrado abaixo.

if(
(arq=fopen("arquivo", "r+b"))==NULL ||
(arq=fopen("arquivo", "w+b"))==NULL
){
fprintf(stderr, "Nao foi possivel abrir o arquivo: %s\n", strerror(errno));
}


Aliás, você deveria se acostumar a sempre testar o valor devolvido não só por fopen(), mas também por todas as outras funções de entrada e saída.

Outro problema é o uso de fflush(stdin). Embora muita implementações façam o descarte dos dados no buffer de entrada, isso não é uma regra geral (pois o padrão determina o comportamento de fflush() apenas para streams de saída de dados, não para aqueles de entrada de dados, como stdin), e mesmo em sistemas em que tal comportamento é determinado, dependendo de como os caracteres da entrada forem dispostos, pode ou não haver caracteres remanescentes depois do ponto em que se cria que o buffer estaria "limpo".

Ainda outro problema é o uso de gets(). Essa função tem um problema inato de projeto que a faz insegura para uso geral (a saber: ela não limita o tamanho da entrada fornecida pelo usuário; então, no seu caso, se alguém digitar mais do que 34 caracteres para o nome ou mais 9 caracteres para o telefone, a função vai gravar além do espaço reservado para receber a entrada). Tão ruim era a função que o padrão do C de 1999 a tornou obsoleta, e o de 2011 finalmente a removeu da biblioteca padrão. Em seu lugar, você pode usar fgets().

A forma como você fez o loop é sub-ótima, pois tem uma chamada a gets() a mais do que seria necessário. Você poderia fazer algo como vai abaixo.

while(1){
/* le nome (mas sem usar gets(), por favor! ;) ) */
if(strlen(nome)==0)
break; /* sai do loop */
/* resto do loop */
}







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts