I am working on a school project and recently encountered a roadblock. I have tried to make date / time a pointer and to even use a dynamically allocated array but when I run this function I get a segmentation fault. When I change the code [Commented] to this, I get a Stack Smashing error instead.
Time createTime(char time[12]) {
Time tm;
// time[strcspn(time, "\r\n")] = '\0';
// char** tokens = splitString(time, 3, ":");
// tm.hour = atoi(tokens[0]);
// tm.min = atoi(tokens[1]);
// tm.sec = atoi(tokens[2]);
tm.hour = 1;
tm.min = 1;
tm.sec = 1;
// free(tokens);
return tm;
}
Full code
#include "earthquakeData.h"
Date createDate(char date[12]) {
Date dt;
date[strcspn(date, "\r\n")] = '\0';
char** tokens = splitString(date, 3, "/");
dt.month = atoi(tokens[0]);
dt.day = atoi(tokens[1]);
dt.year = atoi(tokens[2]);
free(tokens);
return dt;
}
Time createTime(char time[12]) {
Time tm;
// time[strcspn(time, "\r\n")] = '\0';
// char** tokens = splitString(time, 3, ":");
// tm.hour = atoi(tokens[0]);
// tm.min = atoi(tokens[1]);
// tm.sec = atoi(tokens[2]);
tm.hour = 1;
tm.min = 1;
tm.sec = 1;
// free(tokens);
return tm;
}
Earthquake earthquakeCreate(
int id,
char date[12], // Parametized as char in order to convert.
char time[12], // Parametized as char in order to convert.
float latitude,
float longitude,
char type[20],
float depth,
float magnitude,
char magnitudeType[3]
) {
Earthquake qk;
qk.id = id;
strcpy(qk.countryCode, "OO"); // Placeholder até se efetuarem os cálculos.
Date qkDate = createDate(date);
Time qkTime = createTime(time);
qk.latitude = latitude;
qk.longitude = longitude;
strcpy(qk.type, type);
qk.depth = depth;
qk.magnitude = magnitude;
strcpy(qk.magnitudeType, magnitudeType);
return qk;
}
PtList LOADEA(int* numImported) {
// Atributos do ficheiro e declaração do comprimento da linha de texto.
FILE* file;
char* filename = "datasets/earthquakes.csv";
char line[1024];
// Abertura do ficheiro.
file = fopen(filename, "r");
if (file == NULL) {
// Se não existir.
printf("File not found\n");
return NULL;
}
// Aloca-se a memória da lista de earthquakes.
PtList list = listCreate();
if(list == NULL) {
printf("Insuficient memory for allocation\n");
return NULL;
}
int t = 0;
while (fgets(line, sizeof(line), file)) {
line[strcspn(line, "\r\n")] = '\0';
if (strlen(line) > 0) {
char** tokens = splitString(line, 9, ";");
if (tokens != NULL) {
listAdd(list, t, earthquakeCreate(
atoi(tokens[0]),
tokens[1],
tokens[2],
atof(tokens[3]),
atof(tokens[4]),
tokens[5],
atof(tokens[6]),
atof(tokens[7]),
tokens[8]
));
t++;
// Liberta-se a memória associada aos tokens.
free(tokens);
}
}
}
// Fecha-se o ficheiro.
fclose(file);
*numImported = t - 1;
return list;
}
The struct
/**
* @brief Date struct.
*
*/
typedef struct date {
int day, month, year;
} Date;
/**
* @brief Time struct.
*
*/
typedef struct time {
int hour, min, sec;
} Time;
/**
* @brief Earthquake struct.
*
*/
typedef struct earthquake {
int id;
// Código de 2 letras do país ou território mais próximo (countryLocation)
char countryCode[3]; // Calculado a partir das localizações durante importação
Date date;
Time time;
float latitude;
float longitude;
char type[20]; // Earthquake | Explosion | Nuclear Explosion | Rock Burst
float depth;
float magnitude;
char magnitudeType[3]; // MB | MD | MH | ML | MS | MW
} Earthquake;
The splitString function
char** splitString(char *string, int nTokens, const char *delim) {
char **tokens = (char**) malloc(sizeof(char*) * nTokens);
int index = 0;
int len = strlen(string);
// Remove possible carriage return '\r' in file text lines and/or
// Replace newline with terminator character
len--;
if (string[len-1]==13)
len--;
string[len] = '\0';
tokens[index++] = &string[0];
for(int i=0; i < len; i++) {
if( string[i] == delim[0] ) {
string[i] = '\0';
if( i < len - 1 ) {
tokens[index++] = &string[i] + 1;
}
}
}
return tokens;
}
Here is an example of the CSV file:
1;01/02/1965;13:44:18;19.246;145.616;Earthquake;131.6;6;MW
listCreate(), listAdd() and ensureCapacity()
typedef struct listImpl {
ListElem* elements;
int size;
int capacity;
} ListImpl;
bool ensureCapacity(PtList list) {
if (list->size == list->capacity) {
int newCapacity = list->capacity * 2;
ListElem* newArray = (ListElem*) realloc( list->elements,
newCapacity * sizeof(ListElem) );
if(newArray == NULL) return false;
list->elements = newArray;
list->capacity = newCapacity;
}
return true;
}
PtList listCreate() {
int initialCapacity = 10;
PtList list = (PtList)malloc(sizeof(ListImpl));
if (list == NULL) return NULL;
list->elements = (ListElem*)calloc(initialCapacity,
sizeof(ListElem));
if (list->elements == NULL) {
free(list);
return NULL;
}
list->size = 0;
list->capacity = initialCapacity;
return list;
}
int listAdd(PtList list, int rank, ListElem elem) {
if (list == NULL) return LIST_NULL;
if (rank < 0 || rank > list->size) return LIST_INVALID_RANK;
if(!ensureCapacity(list)) return LIST_FULL;
/* make room for new element at index 'rank' */
for(int i = list->size; i > rank; i--) {
list->elements[i] = list->elements[i-1];
}
list->elements[rank] = elem;
list->size++;
return LIST_OK;
}
And finally, the main function
int main() {
PtMap countryStats;
CountryLocation* countries;
PtList earthquakes;
/* Command interpreter. */
char command[100];
while (true) {
readString(command, 100);
if (strcasecmp(command, "LOADCL") == 0) {
countries = LOADCL(&numImported);
sizeCL = numImported;
if (countries != NULL) {
printf("%d country location records imported\n", numImported);
}
}
else if (strcasecmp(command, "LOADEA") == 0) {
earthquakes = LOADEA(&numImported);
if (earthquakes != NULL) {
listPrint(earthquakes);
printf("%d earthquake records imported\n", numImported);
}
}
else if (strcasecmp(command, "LOADST") == 0) {
countryStats = LOADST(&numImported);
if (countryStats != NULL) {
printf("%d country records imported\n", numImported);
}
}
else {
printf("Command not found.");
}
waitForKeypress();
}
return EXIT_SUCCESS;
}
The function is called when the user inputs LOADEA to the console, it's worth noting that there are no problems in other similar functions, only when LOADEA is called, none of the other functions use list either. The teacher himself provided the listCreate() and listAdd() methods so the problem isn't there. Im pretty sure the solution is simple. I know a segmentation fault means that im trying to access memory that "doesn't exist" but I just don't understand where and why. I have tried to change the initialCapacity in listCreate() but to no avail.