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;
}
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.
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 extractk
from thesen
structures according to a criterion that isdia
,mes
andano
modulus 10 less than or equal tok
, and return as a vector ofData
that can have from 0 ton
elements. This is because it may be that none or alln
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 separatek
Data
structures that meet that folkloric criterion of module 10. Only the value ofk
will be forever buried inside the function, since the only thing that returns from it is a pointer to a structureData
- 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 becausek
values can meet your criteria, maybe none, maybe alln
-
imprime_data()
is a silly name, because it does not print anything. It could befiltra_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 then
structures read and then with thek
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 ask
in your functionimprime_data()
: it's one thing to return a vector withk
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...