TransWikia.com

Erro de exited, segmentation fault em C

Stack Overflow em Português Asked on November 5, 2021

Estou tentando fazer uma função que me retorne uma data de acordo com um inteiro e sempre a aparece o erro:

exited, segmentation fault

O código que criei é basicamente este:

#ifndef DATA_H
#define DATA_H

 typedef struct{
   int dia;
   int mes;
   int ano;
 }Data;

 Data imprime_data(Data *datas, int n, int k);




#endif



#include <stdio.h>
#include <stdlib.h>
#include "data.h"

int main (void){
Data * datas;

int n;
scanf ("%d", &n);

datas = malloc(n * sizeof(Data));

for(int i = 0; i < n; i++){
    scanf("%d %d %d", &datas[i].dia, &datas[i].mes, &datas[i].ano); 
}



int k;

scanf("%d", &k);

Data  * teste;

* teste = imprime_data(datas, n, k);


for(int i = 0; i < n; i++){
    
    printf("%d %d %d", teste[i].dia, teste[i].mes, teste[i].ano);

}   

    


return 0;
}


#include "data.h"


Data imprime_data(Data *datas, int n, int k){

Data  * teste;




for(int i = 0; i < n; i++){
    
    if(datas[i].dia % 10 <= k && datas[i].mes % 10 <= k && datas[i].ano % 10 <= k){
        
        teste[i] = datas[i];
        
    

    } 
    
}
    




return *teste;


}

2 Answers

ainda tenho uma dúvida preciso que o meu teste guarde na memoria mais de uma data, sabe como posso fazer isso? já que mesmo usando ele como vetor ele ainda não está guardando

Tentei adivinhar o que pretende fazer com esse código e eu acho mesmo que você podia ter postado mais informação.

No entanto pelo que está lá e pelo que perguntou tem umas coisas que posso acrescentar

O que você queria

  • declarar um vetor de estruturas Data
  • ler um valor n que vai ser o total de estruturas a ler
  • alocar espaço para essas estruturas todas
  • ler as Data uma a uma e gravar no vetor
  • chamar imprime_data(), um tipo de filtro que vai extrair k dessas n estruturas de acordo com um critério que é dia, mes e ano módulo 10 menores ou iguais a k, e retornar como um vetor de Data que pode ter de 0 a n elementos. Isso porque pode ser que nenhum ou todos os n elementos lidos satisfaçam a esse critério

Porque não deu certo

  • quando você declara

Data* datas;

não está de fato declarando um vetor. Sequer está alocando espaço para uma Data. Só está declarando um ponteiro para Data, muito embora tenha até chamado de datas e depois declarado datas = malloc(n * sizeof(Data));

Mas datas é Data*. C não entende plural. malloc() vai sim alocar espaço para as n datas, mas você não vai poder por a mão nesse espaço.

Se você precisa de um vetor com 30 Data declara

Data data[30];

e pode acessar data[0] até data[29]. Note que usar o plural não é mais e sim menos legível porque vai usar uma data por vez apenas.

  • você quer de fato n estruturas e então podia querer declarar

Data data[n];

Só que não pode. Tem que ser um número constante, como o 30 no exemplo acima, ou então alocar dinamicamente espaço para n estruturas Data.

  • um outro problema é imprime_data(): ela vai separar k estruturas Data que atendam àquele critério folclórico do módulo 10. Só que o valor de k vai ficar para sempre enterrado dentro da função, já que a única coisa que retorna dela é um ponteiro para uma estrutura Data
  • e Data* teste; declara um ponteiro para uma estrutura Data. Só uma. E sequer aloca memória para ela. E você precisa de mais de uma porque k valores podem atender ao seu critério, talvez nenhum, talvez todos os n
  • imprime_data() é um nome bobinho, porque ela não imprime nada. Podia ser filtra_datas()
  • e podia ter uma imprime_data() mesmo, que fizesse isso e você podia usar pra testar seu programa, chamando no início com as n estruturas lidas e depois com as k filtradas
  • você não alocou memória direito e nem tentou liberar depois
  • você não devia ler as n Data do teclado e sim de um arquivo porque é muito mais fácil e seguro de testar e reproduzir

Como podia dar certo

Vou te explicar uma maneira de fazer isso e pode me dizer se era o que pretendia. E vou deixar um programa de exemplo porque é uma das coisas mais comuns de se errar em vetores de estruturas, então pode ajudar a outros

as mudanças

A maneira simples de usar um vetor de estruturas é a que o sistema prepara para todo programa C por exemplo. Veja o protótipo de main() int main(argc, char** argv)

No caso de main() é criado um vetor de estruturas char*, strings, com argc strings correspondendo aos parâmetros digitados na linha de comando que ativou o programa. No seu caso um vetor de estruturas Data, com n estruturas será lido no início, e depois um vetor de Data com k valores será criado pela função imprime_data()

  • porque argc existe? É o mesmo problema de k em sua função imprime_data(): uma coisa é retornar um vetor com k estruturas, mas outra coisa é dizer quantas tem dentro do tal vetor
  • O tipo para o vetor data é Data** Data** data;
  • imprime_data() vai ser Data** imprime_data(int n, Data** data, int* ext); o terceiro valor é passado por um ponteiro e assim pode retornar o total de valores extraídos do vetor original. O vetor em si vai estar no endereço que será retornado pela função. Uma solução mais elegante seria escrever o programa em torno de uma estrutura assim:
typedef struct
{
    int N;
    Data** data;
}   Datas;

e acho que já deu pra entender porque: essa é a unidade: um vetor de N estruturas. Sem novidades, já que é o que temos: n * Data em data e k* Data em teste

Um programa EXEMPLO afinal

Arquivo de entrada do teste : "dados.txt"

    1 1 1
    2 2 2
    3 3 3
    4 4 4
    5 5 5
    6 6 6 
    7 7 7 
    8 8 8 
    9 9 9 

A saída do programa para esse arquivo

  Total de valores a ler do arquivo: 9
  vai ler 9 datas de '../../../src/datas.txt'

Vetor com 9 datas:

   1: 1 1 1
   2: 2 2 2
   3: 3 3 3
   4: 4 4 4
   5: 5 5 5
   6: 6 6 6
   7: 7 7 7
   8: 8 8 8
   9: 9 9 9
----------

  Valor de 'k', a constante para a selecao: 4
  o valor de k: 4

Vetor com 4 datas:

   1: 1 1 1
   2: 2 2 2
   3: 3 3 3
   4: 4 4 4
----------

O programa

#include <stdlib.h>

typedef struct
{
    int dia;
    int mes;
    int ano;
}   Data;

typedef struct
{   // exemplo mais legível
    int N;
    Data** data;
}   Datas;

Data**  imprime_data(int,Data**,int*); // filtra
int     mostra_data(int,Data**); // mostra na tela

int main(void)
{
    const char* padrao = "../../../src/datas.txt";
    FILE* entrada = fopen(padrao, "r");
    if (entrada == NULL)
    {
        printf("  nao abriu '%s'n", padrao);
        return -1;
    };
    int n;
    int res = 0;
    printf("n  Total de valores a ler do arquivo: ");
    while ((res = scanf("%d", &n)) != 1){}; // le n
    if (res != 1) return -2;
    printf("  vai ler %d datas de '%s'n", n, padrao);
    Data** data = (Data**) malloc(n * sizeof(Data*));
    for (int i = 0; i < n; i++)
    {
        data[i] = (Data*)malloc(sizeof(Data));
        res = fscanf(entrada, "%d %d %d",
            &data[i]->dia,
            &data[i]->mes,
            &data[i]->ano); // loop para ler k valido
    };  // for()
    fclose(entrada);
    mostra_data(n, data); // mostra o que leu
    int k;
    printf("n  Valor de 'k', a constante para a selecao: ");

    while ((res = scanf("%d", &k)) != 1){}; // le k
    printf("  o valor de k: %dn", k);
    Data** teste = imprime_data(n, data, &k);
    mostra_data(k, teste); // mostra o que selecionou

    // apaga os vetores
    for (int i = 0; i < n; i++) free(data[i]);
    free(data);
    for (int i = 0; i < k; i++) free(teste[i]);
    free(teste);
    return 0;
}

Data** imprime_data(int n, Data** data, int* k)
{
    // para facilitar aloca com n valores
    Data** teste = (Data**)malloc(n * sizeof(Data*));
    int ext = 0; // vai contar o total de extraidos
    for (int i = 0; i < n; i++)
    {
        if (
            data[i]->dia % 10 <= *k && 
            data[i]->mes % 10 <= *k && 
            data[i]->ano % 10 <= *k)
        {
             // ok: vai copiar esse
            teste[ext] = (Data*)malloc(sizeof(Data));
            *(teste[ext]) = *(data[i]); // copia esse
            ext += 1; // avanca k ou vai escrever em cima
        };  // if()
    };  // for()
    *k = ext; // vai retornar o valor
    // copiou *k elementos, entre 0 e n inclusive
    if (ext == 0)
    {   // nao tinha nenhum
        free(teste);
        return NULL;
    };
    if (ext == n) return teste; // todos foram copiados
    // libera via realloc() o que nao foi usado e retorna
    return (Data**)realloc(teste, ext * sizeof(Data*));
};  // imprime_data()

int mostra_data(int N, Data** V)
{
    // simplesmente mostra o vetor V de N datas na tela
    printf("nVetor com %d datas:nn",N);
    for (int i = 0; i < N; i += 1)
    {
        printf("%4d: %d %d %dn", 1 + i,
            V[i]->dia, V[i]->mes, V[i]->ano
        );
    };  // for()
    printf("----------n");
    return N;
}; 

Claro que o nome do arquivo deveria ser passado na linha de comando como parâmetro e não estar enterrado no programa...

Answered by arfneto on November 5, 2021

O maior problema é que não está alocando memória para o array chamado teste na função secundária, então estoura a memória.

E claro, eu liberei essa memória e a outra alocada. Para um exercício não causa problema, mas em outros código pode causar, então acostume fazer certo.

Mas o retorno da função também está errado e um bom compilador com as configurações certas nem deixaria compilar. Você quer retornar um array, então tem que retornar um ponteiro e não a estrutura simples.

Tem um outro problema, esse novo array terá um tamanho menor e você não pode tentar imprimí-lo inteiro. Coloquei mais um parâmetro para ter essa informação retornada. Pra falar a verdade eu faria de forma muito diferente disso, mas não sei o que o exercício pede de fato.

E claro, organizei o código.

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

typedef struct {
    int dia;
    int mes;
    int ano;
} Data;
 
Data *imprime_data(Data *datas, int n, int k, int *total) {
    Data *teste = malloc(n * sizeof(Data));
    *total = 0;
    for (int i = 0; i < n; i++) {
        if (datas[i].dia % 10 <= k && datas[i].mes % 10 <= k && datas[i].ano % 10 <= k) {
            teste[i] = datas[i];
            (*total)++;
        }
    }
    return teste;
}

int main() {
    int n;
    scanf ("%d", &n);
    Data *datas = malloc(n * sizeof(Data));
    for (int i = 0; i < n; i++) scanf("%d %d %d", &datas[i].dia, &datas[i].mes, &datas[i].ano); 
    int k;
    scanf("%d", &k);
    int total = 0;
    Data *teste = imprime_data(datas, n, k, &total);
    for (int i = 0; i < total; i++) printf("%d %d %d", teste[i].dia, teste[i].mes, teste[i].ano);
    free(datas);
    free(teste);
}

Veja funcionando no ideone. E no repl.it. Também coloquei no GitHub para referência futura.

Sugiro pegar exercícios mais simples até poder resolver por conta própria. Não pule conceitos, não tente fazer algo com mecanismos que ainda não domina.

Answered by Maniero on November 5, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP