Read/write linked nodes from binary file - c

I have a problem reading a binary file which contains linked nodes.
This is the code:
lib1.c
struct my_stack_node {
void *data;
struct my_stack_node *next;
};
struct my_stack {
int size;
struct my_stack_node *first;
};
int my_stack_write(struct my_stack *stack, char *filename){
int count = 0;
struct my_stack_node *aux;
FILE *file = fopen(filename, "wb");
if(stack->first != NULL){
aux = stack->first;
count++;
while(aux->next != NULL){
fwrite(&aux ,sizeof(aux), 1, file);
aux = aux->next;
count++;
}
}
fwrite(&stack, sizeof(stack), 1, file); //Escriure stack
fclose(file);
return count;
}
struct my_stack *my_stack_read(char *filename){
struct my_stack *stackRead;
struct my_stack_node *stackNode;
FILE *file = fopen(filename, "rb");
if(!file){
puts("Impossible obrir el fitxer");
return NULL;
}else{
int primerInici = 0;
while(!feof(file)){
if(primerInici == 0){
stackRead = (struct my_stack*) malloc(sizeof(struct my_stack));
fread(stackRead, sizeof(stackRead), 1, file);
primerInici = 1;
}else{
//Crear nou node i llegir-lo del fitxer
stackNode = (struct my_stack_node*) malloc(sizeof(struct my_stack_node));
fread(stackNode, sizeof(stackNode), 1, file);
//Afegir node a la pila
stackNode->next = stackRead->first;
stackRead->first = stackNode;
}
}
fclose(file);
return stackRead;
}
}
main.c
struct my_data {
int val;
char name[60];
};
int main() {
struct my_stack *s, *t, *u;
struct my_data *data, *data1, *data2;
//...more code
u = my_stack_read("/tmp/my_stack.data");
if (! u) {
puts("Error in my_stack_read (u)");
exit(1);
}
if (my_stack_len(s) != my_stack_len(u)) {
puts("Stacks s and u don't have the same len");
exit(1);
}
// Test we can free the data and compare stacks s and u
while((data1 = my_stack_pop(s))) {
data2 = my_stack_pop(u);
if (! data2 || data1->val != data2->val || my_strcmp(data1->name, data2->name)) {
printf("Data in s and u are not the same: %d <> %d\n", data1->val, data2->val);
exit(1);
}
free(data1);
free(data2);
}
//...more code
puts("All tests passed");
return 0;
}
The result of the execution is:
Stack len: 100
Data in s and u are not the same: 22145808 <> 22134800
The correct result should be:
All tests passed

Here lies the problem (inside my_stack_write) :
aux = stack->first;
count++;
while(aux->next != NULL){
fwrite(&aux ,sizeof(aux), 1, file);
aux = aux->next;
count++;
}
You are writting the pointer aux. Not the struct which is being pointed by aux. Neither the data pointed by data, which is the important part.
So. Imagine you have something like this :
my_stack { first=0x100 }
at memoryPosition 0x100 we have : my_stack_node { data=0x200; next=0x300 }
at memoryPosition 0x300 we have : my_stack_node { data=0x500; next=0x600 }
at memoryPosition 0x600 we have : my_stack_node { data=0x700; next=NULL }
For that structure your program is writting : 0x100, 0x300
You are writting the memory addresses of the nodes making up your linked list. And you are missing the last node, which is a different kind of error.
But that is useless. Next time you run your program your nodes may be in different memory addresses so there is no point in saving them. It is dynamic memory, it may reside at different places each time you run your program.
What you should be writting instead is the data your linked list is listing.
This same mistake is repeated in pretty much the whole program.
How to properly write the data contained in the linked list :
void writeStack(struct my_stack *stack, const char *filename)
{
struct my_stack_node *aux;
FILE *file = fopen(filename, "wb");
if ( file==NULL )
{
fprintf( stderr, "Could not open %s for writting.\n", filename );
exit(1);
}
if (stack != NULL)
{
aux = stack->first;
while(aux != NULL)
{
// aux->data is of type void*
// Assuming that aux->data contains a struct my_data
// Most likely it would be better to redefine data as having
// type struct my_data*
fwrite(aux->data ,sizeof(struct my_data), 1, file);
aux = aux->next;
}
}
fclose(file);
}
Here we traverse all the nodes in the list.
And for each we write the data in them contained.
Notice how fwrite( aux->data, writes the data pointed at by aux->data, which is correct.
While fwrite( &aux, would write the memory address contained at aux, which is unlikely to be correct.
And fwrite( &aux->data, would write the memory address contained at aux->data, which is also unlikely to be correct.
It is up to you to add code for counting and to write the reading function.

You only read and write the stack itself, not the payload of its nodes, which is stored voa a void * pointer.
The nodes themselves carry no meaningful information. Or information that is meaningful across sessions, rather: The data and next pointers are valid only in the session that writes the data.
Your stack is essentially a linear data structure. Instead of storing the nodes, store the stack data as array of data members. When you read them in, construct a list with freshly allocated nodes and the read data fields.
Your stack uses void * pointers to allow for various data types. You must therefore find a way to tell the read and write methods how the data should be written or read.
You could provide a callback function where you pass the opened file. Such callbacks could deal with complex data structures as payload, if needed.
Edit: The code below shows an example of how to serialise a stack with custom functions for reading and writng. The symmetric callbacks should write the data to the file and read the data. The read function can allocate memory, which is owned by the stack. The user must make sure to free it.
The callbacks can return a negative number to indicate an error. The stack to read need not be empty. Read data ist just pushed to the stack.
#include <stdlib.h>
#include <stdio.h>
#define die(...) exit((printf(__VA_ARGS__), putchar('\n'), 1));
typedef struct Stack Stack;
typedef struct SNode SNode;
struct SNode {
void *data;
SNode *next;
};
struct Stack {
SNode *head;
};
/*
* Core stack functions
*/
void stack_push(Stack *st, void *data)
{
SNode *sn = malloc(sizeof(*sn));
sn->data = data;
sn->next = st->head;
st->head = sn;
}
void *stack_pop(Stack *st)
{
void *data;
SNode *sn;
if (st->head == NULL) die("Undeflow");
sn = st->head;
data = sn->data;
st->head = sn->next;
free(sn);
return data;
}
int stack_empty(const Stack *st)
{
return (st->head == NULL);
}
/*
* Stack write function with custom callback
*/
int stack_write(const Stack *st, const char *filename,
int (*func)(FILE *f, const void *data))
{
const SNode *sn = st->head;
size_t count = 0;
FILE *f = fopen(filename, "wb");
if (f == NULL) return -1;
fwrite(&count, 1, sizeof(count), f);
while (sn) {
if (func(f, sn->data) < 0) {
fclose(f);
return -1;
}
count++;
sn = sn->next;
}
fseek(f, SEEK_SET, 0);
fwrite(&count, 1, sizeof(count), f);
fclose(f);
return count;
}
/*
* Stack read function with custom callback
*/
int stack_read(Stack *st, const char *filename,
int (*func)(FILE *f, void **data))
{
size_t count = 0;
size_t i;
FILE *f = fopen(filename, "rb");
if (f == NULL) return -1;
fread(&count, 1, sizeof(count), f);
for (i = 0; i < count; i++) {
void *p;
if (func(f, &p) < 0) {
fclose(f);
return -1;
}
stack_push(st, p);
}
fclose(f);
return count;
}
/*
* Custom data struct with read/write functions
*/
struct my_data {
int val;
char name[60];
};
int my_data_write(FILE *f, const void *data)
{
if (fwrite(data, sizeof(struct my_data), 1, f) < 1) return -1;
return 0;
}
int my_data_read(FILE *f, void **data)
{
*data = malloc(sizeof(struct my_data));
if (*data == NULL) return -1;
if (fread(*data, sizeof(struct my_data), 1, f) < 1) {
free(data);
return -1;
}
return 0;
}
/*
* Example client code
*/
int main()
{
Stack s = {NULL};
Stack t = {NULL};
struct my_data aa = {23, "Alice Atkinson"};
struct my_data bb = {37, "Bob Bates"};
struct my_data cc = {28, "Carol Clark"};
stack_push(&s, &aa);
stack_push(&s, &bb);
stack_push(&s, &cc);
stack_write(&s, "kk", my_data_write);
while (s.head) stack_pop(&s);
stack_read(&t, "kk", my_data_read);
while (t.head) {
struct my_data *p = stack_pop(&t);
printf("%4d '%s'\n", p->val, p->name);
free(p);
}
return 0;
}

Related

How to point a double-pointer header to a linked list?

I am writing a program that takes strings from lines of a file, and passes them into a linked list of char arrays/C-style strings.
Here is the struct/typedef I am using:
struct linked_list {
char *string;
struct linked_list *next;
};
typedef struct linked_list Node;
Now, the function where I am processing the file is the following snippet:
void function(char *filename, Node **header) {
FILE *fp;
fp = fopen(filename, "r");
if (fp != NULL) {
int line_count = 0;
Node *curr = NULL;
char* line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, fp)) != -1) {
printf("File got: %s\n", line);
curr = (Node*)malloc(sizeof(*curr);
curr->name = malloc(line);
strcpy(curr->name, line);
printf("Curr added: %s\n", curr->name);
if (line_count == 0) {
*header = curr;
printf("Header assigned curr\n");
curr = curr->next;
line_count++;
}
header = &curr;
}
The prints confirm that I am successfully assigning the variables. Next, the function to print is as follows:
void print(Node *header) {
while (header != NULL) {
printf("%s\n", header->name);
header = header->next;
}
}
Which obviously doesn't work because the header doesn't properly point to the list.
How would I go about fixing this? I have tried some things like trying to point the header to the linked list "curr" before adding any values, but that didn't seem to work.
I am new to C, so some syntax may be rough/inefficient (especially the malloc() functions, but I will get to that later.
Here is the main function:
int main(int argc, char* argv[]) {
Node* header = NULL;
function(argv[i], &header);
print(header);
return 0;
}

How can I free all instances of dynamically allocated memory in this C code

I've written this C code. In the beginning, I used file handing to read a text file and insert every line as a string in a linked list. I need to free all cases of memory allocation in the program in a separate void function. How do I do that? I only included the parts of the code that are relevant because it's a pretty long program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#include <ctype.h>
/*Node of linked list*/
typedef struct node {
char *data;
struct node *next;
} node;
node *start = NULL;
node *current;
typedef enum {
not_tested, found, missed
} state;
/*Appending nodes to linked list*/
void add(char *line) {
node *temp = (node *)malloc(sizeof(node));
temp->data = strdup(line);
temp->next = NULL;
current = start;
if (start == NULL) {
start = temp;
}
else {
while (current->next != NULL) {
current = current->next;
}
current->next = temp;
}
}
/*read text file*/
void readfile(char *filename) {
FILE *file = fopen(filename, "r");
if (file == NULL) {
exit(1);
}
char buffer[512];
while (fgets(buffer, sizeof(buffer), file) != NULL) {
add(buffer);
}
fclose(file);
}
This is not exactly what you're asking for, but I show you how to build a little class that allocates chunks of memory that can bee freed in a single call. This is especially useful when you have lots of small pieces of memory to allocate and therefore to free after usage.
It could seem too many codes for your usage, but note that such a class can be saved in a independent file and reused each time it's needed :
struct Allocator {
void * buffer;
size_t capacity;
size_t usedSize;
};
struct Allocator * newAllocator(size_t initialSize) {
struct Allocator * allocator = malloc(sizeof(*allocator));
if (! allocator) return NULL;
allocator->buffer = malloc(initialSize);
if (! allocator->buffer) { free(allocator); return NULL; }
allocator->capacity = initialSize;
allocator->usedSize = 0;
return allocator;
}
void freeAllocator(struct Allocator * allocator) {
if (!allocator) return;
if (allocator->buffer) free(allocator->buffer);
free(allocator);
}
void * allocate(struct Allocator * allocator, size_t size) {
if (size + allocator->usedSize > allocator->capacity) {
while (size + allocator->usedSize > allocator->capacity) allocator->capacity *= 2;
allocator->buffer = realloc(allocator->buffer, allocator->capacity);
}
void * ptr = allocator->buffer + allocator->usedSize;
allocator->usedSize += size;
return ptr;
}
//-------- END ALLOCATOR
struct node {
//...
};
// How to replace a call to malloc to allocate a node :
void add(struct Allocator *allocator, char *line) {
struct node *temp = allocate(allocator, sizeof(*temp));
//...
}
int main()
{
FILE *file = fopen("myfileName", "r");
if (file == NULL) exit(1);
// Allocates the buffer and as many nodes as needed
struct Allocator *allocator = newAllocator(1024);
char * buffer = allocate(allocator, 512);
while (fgets(buffer, 512, file) != NULL) {
add(allocator, buffer);
}
// Free all allocated memory in a single call
freeAllocator(allocator);
return 0;
}

Loading binary file to unknown struct type

I have a problem reading from binary file and casting it to a unknown type of struct...
Should I really avoid having the save/load functions inside my
Linked List code?
Is it because the GCC compiler I'm using stacks
the struct with more data to conveniently store in memory, and since
when loading the function doesn't know about this "offsets"?
I'm writing a generic linked list in C, and it is intended to be a header file, so I can just use it anywhere. Since it's going to be a generic type list, the header will not know about the type of data on the list (I'm looking at mixed types, so structs). For saving data, I just pass the address of the data, and the length of it, extracted from sizeof(struct). The reading is the same concept, using fread(container, sizeof(struct), 1, FILE), which is passed by the calling program, again extracting se size using sizeof(struct). But in practice, it does not work...
#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED
#include <string.h>
typedef struct tagNode{
void *data;
struct tagNode *next_Node;
} Node;
typedef struct tagLinkedList{
Node *Head;
int Size;
} LinkedList;
int LinkedList_New(LinkedList *llist){
llist->Head = NULL;
llist->Size = 0;
return 1;
}
int LinkedList_Insert(LinkedList *llist, int index, void *Data, size_t s_Data){
int cur_index = 0;
if(index > llist->Size || index < 0)
index = 0;
Node *newNode = malloc(sizeof(Node));
newNode->data = malloc(s_Data);
if(newNode == NULL){return 0;}
if(newNode->data == NULL){return 0;}
newNode->data = Data;
Node *currentNode = llist->Head;
Node *lastNode = llist->Head;
if(index == 0){
newNode->next_Node = llist->Head;
llist->Head = newNode;
}else{
while(llist->Head->next_Node != NULL && cur_index != index){
if(cur_index == index){
newNode->next_Node = currentNode;
lastNode->next_Node = newNode;
}else{
lastNode = currentNode;
currentNode = currentNode->next_Node;
cur_index++;
}
}
}
llist->Size += 1;
}
int LinkedList_Save(char *Path, LinkedList *llist, size_t sData){
FILE *fp;
fp = fopen(Path, "w");
if(fp == NULL){return -1;}
Node *currentNode;
currentNode = llist->Head;
while(currentNode != NULL){
fwrite(currentNode->data, sData, 1, fp);
currentNode = currentNode->next_Node;
}
fclose(fp);
return 1;
}
int LinkedList_Load(char *Path, LinkedList *llist, size_t sData){
FILE *fp;
fp = fopen(Path, "r");
if(fp == NULL){fclose(fp);return -1;}
while(!feof(fp)){
void *Data = malloc(sData);
if(Data == NULL){fclose(fp);return -1;}
fread(Data, sData, 1, fp);
LinkedList_Insert(llist, 0, Data, sData);
}
fclose(fp);
return 1;
}
#endif // LINKEDLIST_H_INCLUDED
And my currently testing subject:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../LinkedList.h"
typedef struct{
int a;
char b[5];
} tempo;
int main(){
tempo teste = {5, "oito"};
LinkedList lista;
LinkedList_New(&lista);
LinkedList_Insert(&lista, 0, &teste, sizeof(tempo));
LinkedList_Save("data.txt", &lista, sizeof(tempo));
printf("%s", ((tempo*)lista.Head->data)->b);
LinkedList ls2;
LinkedList_New(&ls2);
LinkedList_Load("data.txt", &ls2, sizeof(tempo));
printf("%s", ((tempo*)ls2.Head->data)->b);
return 1;
}
The first printf shows me the b variable in the struct, which means the list is working like its supposed to.
But the second printf, if used to show the a variable(int), I get a random number(something like 8712382), and if used to show the b variable, I get just "L"
you have a problem in your LinkedList_load function. update it to the following
int LinkedList_Load(char *Path, LinkedList *llist, size_t sData){
FILE *fp;
fp = fopen(Path, "rb");
if(fp == NULL){fclose(fp);return -1;}
fseek(fp,0L,SEEK_SET);
while(!feof(fp)){
void *Data = malloc(sData);
if(Data == NULL){fclose(fp);return -1;}
int readed=fread(Data, sData, 1, fp);
if(readed==0){return -1;}
/*you were displaying the last reading that contains
*nothing, the previous check solves the problem.
*/
printf("readed %d items: \n",readed);
LinkedList_Insert(llist, 0, Data, sData);
}
fclose(fp);
}

Trouble with Malloc and Linked List

I have a function that reads a text file filled with a word on every line. Here is an example of a text file I'm using
and
but
five
follows
four
has
is
like
line
lines
littlest
not
once
one
only
other
six
the
three
twice
two
word
words
Code:
typedef struct node node_t;
struct node {
char data[MAX_WORD];
int term;
node_t *next;
};
node_t *head;
int
int_struct(int lines){
FILE *fp;
char ch;
int n = 0, i, switch_num=1, test_first=0, test_first_2=0;
node_t *node, *curr_add;
fp = fopen("text.txt", "r");
node = (node_t*)malloc(sizeof(node_t));
for (i=1; i<=lines; i++){
switch_num = 1;
n=0;
if (test_first != 0){
if (test_first_2){
node = (node_t*)malloc(1000000);
}
test_first_2=1;
while ((ch = getc(fp)) != '\n'){
node -> term = i;
node -> data[n] = ch;
n++;
}
curr_add -> next = node;
curr_add = node;
}
else{
test_first = 1;
head = curr_add = node;
}
}
curr_add -> next = NULL;
fclose(fp);
return num;
}
What I want to do is to read each word and add it to a linked list.
However I am having trouble with malloc (at the moment I just add in a lot of bytes) and need advice on how to properly use it inside the function I have. I've done a general search and tried my best to try and do what most examples do. But I still can't seem to get my function working. For example, every time I execute the program it will read and add all the words into the linked list. However, the program crashes on the last word, and returns NULL. If anyone is able to point me in the right direction, I'd be very grateful.
Issues
There are no checks for return values. Particularly, fopen and malloc
may return NULL. If they do, you'll catch a segmentation fault error on the
first attempt to access the returned value.
Overcomplicated logic. You don't need these switch_num, test_first and test_first_2
variables (see sample code below).
No need in getc when you're reading a text file line-by-line - use
fgets instead.
Too many memory allocations. You don't need more than sizeof(node_t) + length of the line bytes per line.
The allocated memory is not freed. The dynamic memory should be freed as
soon as it is not needed.
Example using linked list
The following reads a text file into a linked list. Memory is allocated for
each list item, and for each line in the file resulting in n * 2 memory
allocations, where n is the number of lines in the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
unsigned line;
char *data;
struct _node *next;
} node_t;
static void
destroy_list(node_t *list)
{
node_t *node;
for (node = list; node; node = node->next) {
if (node->data != NULL)
free(node->data);
free(node);
}
}
static node_t *
create_list_item(const char *data, unsigned line)
{
node_t *node = calloc(1, sizeof(node_t));
if (node == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
} else {
node->line = line;
node->data = strdup(data);
if (node->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
free(node);
node = NULL;
}
}
return node;
}
/* Returns pointer to new linked list */
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len)
{
node_t *list = NULL;
node_t *prev = NULL;
node_t *node;
unsigned i;
for (i = 0; fgets(buf, buf_len, fp); prev = node) {
if ((node = create_list_item(buf, ++i)) == NULL) {
fprintf(stderr, "calloc: %s\n", strerror(errno));
break;
}
if (list == NULL)
list = node;
if (prev != NULL)
prev->next = node;
}
return list;
}
static void
print_list(const node_t *list)
{
const node_t *node;
for (node = list; node; node = node->next)
printf("%d: %s", node->line, node->data);
}
int main(int argc, char const* argv[])
{
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
node_t *list = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
list = read_file(fp, buf, sizeof(buf));
fclose(fp);
if (list) {
print_list(list);
destroy_list(list);
}
return 0;
}
Example using dynamic array
It is inefficient to allocate memory for each line (twice) in the file,
not only because the system calls (malloc, realloc, etc.) are costly,
but also because the items are placed non-contiguously. Accessing contiguous
region of memory is usually faster.
In the following code, the linked list is replaced with dynamic array. We
initialize memory for 10 lines at once. The size is increased as necessary.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strerror, strdup */
#include <errno.h>
typedef struct _node {
size_t line;
char *data;
} node_t;
static void
destroy_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data)
free(item->data);
}
free(array);
}
static void
print_array(node_t *array, size_t size)
{
size_t i;
node_t *item;
for (i = 0; i < size; i++) {
item = &array[i];
if (item->data) {
printf("%ld: %s", item->line, item->data);
}
}
}
static node_t *
read_file(FILE *fp, char *buf, size_t buf_len,
const size_t array_step, size_t *array_size)
{
node_t *item;
node_t *array = calloc(array_step, sizeof(node_t));
size_t size = 0;
if (array == NULL) {
fprintf(stderr, "calloc:%s\n", strerror(errno));
return array;
}
while (fgets(buf, buf_len, fp)) {
if (size && size % array_step == 0) {
array = realloc(array, sizeof(node_t) * (array_step + size));
if (array == NULL) {
fprintf(stderr, "realloc:%s\n", strerror(errno));
break;
}
}
item = &array[size++];
item->line = size;
item->data = strdup(buf);
if (item->data == NULL) {
fprintf(stderr, "strdup: %s\n", strerror(errno));
break;
}
}
*array_size = size;
return array;
}
int main(int argc, char const* argv[])
{
node_t *array;
const size_t array_step = 10;
size_t array_size;
const char *filename = "text.txt";
char buf[1024] = {0};
FILE *fp = NULL;
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "failed to open file %s: %s\n",
filename, strerror(errno));
return 1;
}
array = read_file(fp, buf, sizeof(buf), array_step, &array_size);
fclose(fp);
if (array) {
print_array(array, array_size);
destroy_array(array, array_size);
}
return 0;
}
Note the changes in node_t structure.

Using realloc in dynamic structure array

I am trying to use realloc to dynamically create instances of a struct, filling it with data from a temporary structure as I go. The program crashes when it reaches the line to malloc a pointer of the structure a second time but I am not sure how I should structure this function. I have the following code:
#define MAX_STRING 50
struct data {
int ref;
int port;
char data[MAX_STRING+1];
}valid, invalid;
void read_file(FILE *file);
void validate(struct data* temp);
int g = 0;
int main(){
char inputfile[100];
FILE *file = fopen("file.txt" , "r");
if (file != NULL){
read_file (file);
}
else{
// Some code here..
}
return 0;
}
void read_file(FILE *file){
struct data* temp = malloc(sizeof(struct data));
char buf[1024];
while(!feof(file)){
fgets(buf, sizeof buf, file))
sscanf(buffer, "%d.%d.%s", &temp->ref, &temp->port, &temp->data);
validate(temp);
g++;
}
}
void validate(struct data* temp){
if((some condition) && (some condition))
{
create_valid(temp);
}
if((some condition) && (some condition))
{
create_invalid(temp);
}
}
I am unsure of how to structure the following function:
int create_vaild(struct data* temp){
struct data* valid = malloc(sizeof(struct data)); <<<<<<<<< Line that crashes
valid = realloc(valid, g * sizeof(struct data));
valid[g] = *temp;
if (valid[g] == NULL){
//error.
};
printf("\n%i:%i:%s\n", (valid+g)->ref, (valid+g)->port, (valid+g)->data);
return 0;
}
I see one potential problem:
You have g set to 0 i.e.
int g =0;
You are not incrementing it before the call to create_valid(). You are using this value to allocate memory inside that functions:
valid = realloc(valid, g * sizeof(struct data));
So now g is 0.
Later in the next line you dereference this pointer
valid[g] = *temp;
This is some memory which you have not allocated as realloc() didn't allocate memory for you becasue you passed 0 to it.Hence the crash.

Resources