I am implementing a music scale database via a double pointer construct, but I keep running into segfaults and overflow errors when malloc'ing space for items inside the database and I do not understand why.
This is a conceptual issue, the error is incompatible with my understanding of how pointers work and I have been unable to find a definitive answer online. The issue seems to stem from the line
db->entry[db_idx] = malloc(sizeof(struct scale_t)); // potiential overflow here??
db->entry[db_idx]->scale = circularlist_create();
But I do not understand how this can be since, db->entry[db_idx]
is type struct scale_t*
and malloc
is returning a pointer of the appropriate type. The amount malloc
'd shouldn't really matter since I am writing a pointer value to db->entry[db_idx]
Anyway,
here is a link to the #include "CircularLinkedList.h"
header and implementation files.
https://gist.github.com/jstaursky/58d4466eb232e90580e1011bf5a7e641
https://gist.github.com/jstaursky/84cf9ba2f870da0807faa454f20c36e9
the scale.list file https://gist.github.com/jstaursky/24baeaf2a922a081f0a919d31ed638df
The directory structure looks like this
src
- main.c
- CircularLinkedList.h
- CircularLinkedList.c
- conf/
- scale.list
Added the gists to try and keep the question as compact as possible.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "CircularLinkedList.h" // See linked GitHub gists.
struct scale_t {
char* name;
struct node_t* scale;
int num_notes;
};
struct database_t {
struct scale_t** entry;
int size;
};
struct database_t *build_database(FILE *);
char *fgetline(FILE *stream);
int main(int argc, char *argv[])
{
FILE *configfp = fopen("conf/scale.list", "r");
struct database_t *scaledatabase = build_database(configfp);
for (int i = 0; i < scaledatabase->size; ++i) {
circularlist_traverse(scaledatabase->entry[i]->scale, circularlist_print);
}
}
struct database_t *build_database(FILE *fp)
{
struct database_t *db = malloc(sizeof(struct database_t));
db->entry = malloc(sizeof(struct scale_t *));
int db_idx = 0;
for (char *line; (line = fgetline(fp)); ++db_idx) {
db->entry[db_idx] = malloc(sizeof(struct scale_t)); // potiential overflow here??
db->entry[db_idx]->scale = circularlist_create();
char *rest = line;
db->entry[db_idx]->name = strtok_r(line, ",", &rest);
while (isspace(*rest))
++rest;
char *interval;
int note_count = 0;
while ((interval = strtok_r(NULL, "-", &rest))) {
circularlist_insert(&db->entry[db_idx]->scale, interval);
++note_count;
}
db->entry[db_idx]->num_notes = note_count;
}
db->size = db_idx;
return db;
}
char*
fgetLine(FILE *stream)
{
const size_t chunk = 128;
size_t max = chunk;
/* Preliminary check */
if (!stream || feof(stream))
return NULL;
char *buffer = (char *)malloc(chunk * sizeof(char));
if (!buffer) {
perror("Unable to allocate space");
return NULL;
}
char *ptr = buffer;
int c; /* fgetc returns int. Comparing EOF w/ char may cause issues. */
while ( (c = fgetc(stream)) != EOF && (*ptr = c) != '\n')
{
++ptr;
size_t offset = ptr - buffer;
if (offset >= max) {
max += chunk;
char *tmp = realloc(buffer, max);
if (!tmp) {
free(buffer);
return NULL;
}
buffer = tmp;
ptr = tmp + offset;
}
}
*ptr = '\0';
return buffer;
}