Exited error, segmentation fault in C

I am trying to make a function that returns me a date according to an integer and always the error appears:

Exited, segmentation fault

The code I created is basically this:

#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;


}
Author: Maniero, 2020-07-19

2 answers

The biggest problem is that it is not allocating memory to the array called teste in the secondary function, so it bursts the memory.

And of course, I released that memory and the other allocated. For one exercise does not cause problem, but in other Code can cause, so get used to do right.

But the function return is also wrong and a good compiler with the right settings wouldn't even let it compile. You want to return a array , so you have to return a pointer and not the simple structure.

Has another problem, this new array will have a smaller size and you can't try to print it whole. I put one more parameter to have this information returned. To tell the truth I would do it very differently, but I don't know what the exercise actually asks for.

And of course, I organized the code.

#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);
}

See working on ideone. E no repl.it. also put in the GitHub for future reference.

I suggest taking simpler exercises until you can solve on your own. Do not skip concepts, do not try to do something with mechanisms that you do not yet master.

 1
Author: Maniero, 2020-07-20 11:42:44

I still have a doubt I need my test to keep in memory more than one date, you know how I can do that? since even using it as a vector it is still not saving

I tried to guess what you intend to do with this code and I really think you could have posted more information.

However for what is there and for what asked There are some things that I can add

What did you want

  • declare a vector of structures date
  • read a value n that will be the total structures to read
  • allocate space for these structures all
  • read the Data one by one and write to the vector
  • Call imprime_data(), a type of filter that will extract k from these n structures according to a criterion that is dia, mes and ano modulus 10 less than or equal to k, and return as a vector of Data that can have from 0 to n elements. This is because it may be that none or all n elements read satisfy this criterion

Because it didn't work out

  • when you declare

Data* datas;

Is not in fact declaring a vector. It's not even allocating space for a Data. It is only declaring a pointer to Data, although it has even called datas and then declared datas = malloc(n * sizeof(Data));

But datas is Data*. C does not understand plural. malloc() will instead allocate space for the n dates, but you won't be able to for a hand in that space.

If you need a vector with 30 Data declare

Data data[30];

And can access data[0] up to data[29]. Note that using the plural is no longer but less readable because it will only use one date at a time.

  • you actually want n structures and then you might want to declare

Data data[n];

Just can't. It has to be a constant number, like 30 in the example above, or else dynamically allocate space for n structures Data.

  • another problem is imprime_data(): it will separate k Data structures that meet that folkloric criterion of module 10. Only the value of k will be forever buried inside the function, since the only thing that returns from it is a pointer to a structure Data
  • and Data* teste; declare a pointer to a Data Structure. Just one. And it does not even allocate memory for her. And you need more than one because k values can meet your criteria, maybe none, maybe all n
  • imprime_data() is a silly name, because it does not print anything. It could be filtra_datas()
  • and you could have a imprime_data() that would do that and you could use it to test your program, calling at first with the n structures read and then with the k filtered
  • you did not allocate memory right and did not even try to free up after
  • you should not read the n Data of a file because it is much easier and safer to test and play

How could it work

I will explain a way to do this and you can tell me if it was what you intended. And I'm going to leave an example program because it's one of the most common things to get wrong on structure vectors, so it can help others

The changes

The simple way to use a structure vector is the one that the system prepares for every C program for example. See the prototype of main() int main(argc, char** argv)

In the case of main() is created a vector of structures char*, strings, with argc strings corresponding to the parameters entered on the command line that activated the program. In your case a vector of structures Data, with n structures will be read at the beginning, and then a vector of Data with k values will be created by the function imprime_data()

  • why does argc exist? It's the same problem as k in your function imprime_data(): it's one thing to return a vector with k structures, but it's another thing to say how many it has inside the such a vector
  • the type for the date vector is date** Data** data;
  • print_data () will be Data** imprime_data(int n, Data** data, int* ext); the third value is passed by a pointer and thus can return the total values extracted from the original vector. The vector itself will be at the address that will be returned by the function. A more elegant solution would be to write the program around a structure like this:
typedef struct
{
    int N;
    Data** data;
}   Datas;

And I think I've already figured out why: this is the unit: a vector of N structures. No news, already that's what we have: n * Data on date and k* Data in teste

An example program after all

Test input file: "data.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 

The output of the program for this file

  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
----------

The program

#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: %d\n", 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:\n\n",N);
    for (int i = 0; i < N; i += 1)
    {
        printf("%4d: %d %d %d\n", 1 + i,
            V[i]->dia, V[i]->mes, V[i]->ano
        );
    };  // for()
    printf("----------\n");
    return N;
}; 

Of course the file name should be passed on the command line as a parameter and not be buried in the program...

 0
Author: arfneto, 2020-08-18 03:49:48