Falha de Segmentação [RESOLVIDO]

1. Falha de Segmentação [RESOLVIDO]

Yuri Coelho Rosário
v8yuricoelho

(usa Ubuntu)

Enviado em 05/03/2017 - 16:40h

Olá a todos, necessito fazer o seguinte programa:

Seja uma estrutura para descrever os carros de uma determinada revendedora, contendo os
seguintes campos:
marca: string de tamanho dinâmico
ano: inteiro
cor: string de tamanho dinâmico
preço: real
a) Escrever a definição da estrutura carro.
b) Declarar o vetor vetcarros do tipo da estrutura definida acima, de tamanho dinâmico.
Crie um menu para:
c) Definir um bloco de programa para ler o vetor vetcarros.
d) Definir um bloco de programa que receba um preço e imprima os carros (marca, cor e ano) que
tenham preço igual ou menor ao preço recebido.
e) Defina um bloco de programa que leia a marca de um carro e imprima as informações de todos
os carros dessa marca (preço, ano e cor).
f) Defina um bloco de programa que leia uma marca, ano e cor e informe se existe ou não um carro
com essas características. Se existir, informar o preço.


Estou criando e compilando o programa por blocos, e até agora estou no bloco c. Porém, durante a execução do programa, após implementar a primeira entrada, o programa é encerrado com uma "falha de segmentação". Eis o meu código:

// Declarando bibliotecas auxiliares:

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

// Estrutura do carro:

typedef struct
{
char marca[20];
char cor[20];
int ano;
float price;
} CARROS;

CARROS *vet_carros; // Declarando "vet_carros" como variável global.

// Declarando funções auxiliares:

void alocaVetor (int quant, CARROS *vet_carros);
void lerCarros (int quant, CARROS *vet_carros);

// Início:

int main (void)
{
int quant; // Variável que irá armazenar o tamanho do vetor.

printf ("Defina a quantidade de carros a serem lidos: ");
scanf ("%d", &quant);

alocaVetor (quant, vet_carros);

lerCarros (quant, vet_carros);

return 0;
}

// Função responsável por alocar o vetor de carros:

void alocaVetor (int quant, CARROS *vet_carros)
{
vet_carros = (CARROS *) malloc (quant * sizeof (CARROS));
if (vet_carros == NULL)
{
printf ("\aERRO DE MEMORIA!!!");
exit (-1);
}
}

// Função responsável por solicitar as entradas ao usuário e as ler:

void lerCarros (int quant, CARROS *vet_carros)
{
printf ("\nEntre com a marca: ");
setbuf(stdin, NULL);
fgets (vet_carros -> marca, 20, stdin);

printf ("Entre com a cor: ");
setbuf(stdin, NULL);
fgets (vet_carros -> cor, 20, stdin);

printf ("Entre com o ano: ");
scanf ("%d", &vet_carros -> ano);

printf ("Entre com o preco: ");
scanf ("%f", &vet_carros -> price);
}



  


2. MELHOR RESPOSTA

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 05/03/2017 - 19:30h

Observe as funções alocaVetor e lerCarros. Ambas recebem um ponteiro do tipo CARROS, até aí tudo bem.
Agora observe o comportamento ao passar vet_carros para a função alocaVetor, quando o malloc é realizado, a região alocada, é atribuída a vet_carros, logo após, temos a função lerCarros, que recebe um valor da entrada e armazena nesse vetor até aí, tudo parece bem.

Na verdade, o comportamento pode não parecer tão intuitivo, mas a variável vet_carros da linha 44, não é a mesma da linha 17.
Observe a linha 33:
alocaVetor (quant, vet_carros); 

Nessa linha, vet_carros foi copiada silenciosamente pelo compilador, para um novo ponteiro temporário.

Agora, observe a linha 44:
vet_carros = (CARROS *) malloc (quant * sizeof (CARROS)); 

Este vet_carros não é o mesmo global, ele é a própria cópia, possui endereço diferente.
Você pode observar o endereço de cara um, através de:
printf("%p\n", &vet_carros); 

Coloque esse trecho nas linhas 32 e 45, observe a diferença.

E como consertar isso?
Lembre que o ponteiro é um tipo de variável que armazena um endereço, logo você pode usar um ponteiro que armazena o endereço de outro ponteiro, o vet_carros neste caso.


void alocaVetor (int quant, CARROS **vet_carros) {
*vet_carros = malloc(...);
}

int main () {
alocaVetor(quant, &vet_carros);
...
}


Novamente teremos o ponteiro copiado, mas a cópia preserva o conteúdo, logo, conseguir manter o mesmo endereço do vet_carros original, quando é realizado o acesso através do *.

Espero ter ajudado.
--
Uilian Ries
Linux Counter: 521986

3. Re: Falha de Segmentação

Paulo
paulo1205

(usa Ubuntu)

Enviado em 06/03/2017 - 12:42h

A explicação do UilianRies está correta e a sugestão dele funciona. Mesmo assim, eu gostaria de fazer uma sugestão ligeiramente diferente.

Em lugar de passar o endereço do ponteiro como argumento de uma função alocaVetor() que tem tipo de retorno void, use a forma tradicional do C para a obtenção de recursos: passe as informações para a criação do objeto como parâmetros, e faça a função retornar um ponteiro para o objeto criado.

CARROS *alocaVetor(size_t quant){
return malloc(quant*sizeof(CARROS));
}


Note que a função retorna um ponteiro nulo em caso de erros, refletindo o comportamento da própria malloc(). Também faz parte do modo tradicional de usar o C que funções de biblioteca não abortam o programa por conta própria (exceto funções que servem exatamente para isso, tais como exit(), abort() e assert()), mas sinalizam situações de erro a quem as chamou, a fim de que o chamador decida como proceder.

A forma de chamar essa função seria parecida com a seguinte.

  if(!(vet_carros=alocaVetor(quant))){
fprintf(stderr, "Erro de alocação de memória: %s.\n", strerror(errno));
return 1;
}


Por fim, note que o nome “alocaVetor” possivelmente não é o melhor do mundo, pois ele não deixa claro que se refere a um tipo de vetor específico. Ao programar, você deve ser sempre procurar ser específico. Nomes como alocaVetorCarros ou simplesmente alocaCarros seriam muito mais claros para quem quer que lesse seu programa.


4. Re: Falha de Segmentação [RESOLVIDO]

Uilian Ries
uilianries

(usa Linux Mint)

Enviado em 06/03/2017 - 13:49h

Excelente sugestão, Paulo.

Abraço.


5. Re: Falha de Segmentação [RESOLVIDO]

Yuri Coelho Rosário
v8yuricoelho

(usa Ubuntu)

Enviado em 06/03/2017 - 21:50h

Obrigado pessoal, a dica de vocês foram de grande valor. Mais explicado que isso, impossível, irei seguir o algoritmo.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts