Not allocated pointers
The problem is that you do:
// list points to null after that line
studentList* list = NULL;
// allocate memory for the list struct
list = (studentList*) malloc(sizeof(studentList));
// set field inside list struct
list->numberOfStudents =1;
// list->students is a pointer, but pointers should point to something valid
// So the question is: Was list->students set to NULL?
// Or was it mallocated?
list->students->matrikelNummer = 1;
So you access list->students
that is a pointer.
List itself was allocated via malloc so its fine.
But malloc reserves space for only the list object you want.
It does not mallocate anything else.
So list->students
is a pointer that is not mallocated - that's why we get the segmentation fault error.
Solution to this problem is pretty straightforward - we have to allocate not only a list but all pointers we use (in this case its students
member):
// That was earlier there:
studentList* list = NULL;
list = (studentList*) malloc(sizeof(studentList));
// After allocating place for list also allocate place for list->students:
list->students = (student*) malloc(sizeof(student));
Detection of invalid memory usage
In a case when you get segmentation faults or memory leaks it's good to know that there are plenty of tools to help programmers detect such a nasty errors.
One of them is Valgrind
Valgrind is available for Linux (and probably for Windows but buggy and untested).
It's awesome tools that can traverse your program and notify you about any leaks, invalid frees and usage of forbidden memory addresses.
Example usage of Valgrind:
# Compile your code
gcc list.c -o list
# Use Valgrind
valgrind --tool=memcheck ./list
And what valgrind shows:
==26761== Memcheck, a memory error detector
==26761== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==26761== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==26761== Command: ./list
==26761==
==26761== Use of uninitialised value of size 8
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761==
==26761== Invalid write of size 4
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761== Address 0x40 is not stack'd, malloc'd or (recently) free'd
==26761==
==26761==
==26761== Process terminating with default action of signal 11 (SIGSEGV)
==26761== Access not within mapped region at address 0x40
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761== If you believe this happened as a result of a stack
==26761== overflow in your program's main thread (unlikely but
==26761== possible), you can try to increase the size of the
==26761== main thread stack using the --main-stacksize= flag.
==26761== The main thread stack size used in this run was 8388608.
==26761==
==26761== HEAP SUMMARY:
==26761== in use at exit: 16 bytes in 1 blocks
==26761== total heap usage: 1 allocs, 0 frees, 16 bytes allocated
==26761==
==26761== LEAK SUMMARY:
==26761== definitely lost: 0 bytes in 0 blocks
==26761== indirectly lost: 0 bytes in 0 blocks
==26761== possibly lost: 0 bytes in 0 blocks
==26761== still reachable: 16 bytes in 1 blocks
==26761== suppressed: 0 bytes in 0 blocks
==26761== Rerun with --leak-check=full to see details of leaked memory
==26761==
==26761== For counts of detected and suppressed errors, rerun with: -v
==26761== Use --track-origins=yes to see where uninitialised values come from
==26761== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
So it shows that you access invalid address in function main:
==26761== Invalid write of size 4
==26761== at 0x4006A1: main (in /home/students/inf/p/ps386038/stack/list)
==26761== Address 0x40 is not stack'd, malloc'd or (recently) free'd
And says the address (pointer is not even allocated)!
Correct C list implementation
If you want to implement a pointers structure that holds list of students
then one common approach is to put a pointer to the next student (next on the list) into the s_student structure.
And pointers to the first and last student into the student list.
One working example is the following I wrote myself:
#include <stdio.h>
#include <stdlib.h>
typedef struct s_student student;
struct s_student
{
char name[64];
int matrikelNummer;
// This will point to the next student on the list
student* nextStudent;
};
typedef struct s_studentList
{
student* student;
// This will point to the last available student
student* lastStudent;
// This will point to the first available student
student* firstStudent;
int numberOfStudents;
} studentList;
// Allocates the list
void allocStudentsList(studentList** list) {
if(list == NULL) return;
*list = (studentList*) malloc(sizeof(studentList));
(*list)->lastStudent = NULL;
(*list)->firstStudent = NULL;
}
// To add the student to the list
void addStudentToList(studentList* list, student studentData) {
if(list == NULL) return;
// Allocate a place for the next student
student* st = (student*) malloc(sizeof(student));
// If it's first student in the list
if(list->lastStudent == NULL) {
list->lastStudent = st;
list->firstStudent = st;
} else {
// The next student after the current last student will be the newly created one
list->lastStudent->nextStudent = st;
}
// Fill the student data
*st = studentData;
st->nextStudent = NULL;
// Set the last available student to the one created
list->lastStudent = st;
}
// To recurisvely free the students
void freeStudent(student* stud) {
if(stud->nextStudent != NULL) {
// Free next student recursively
freeStudent(stud->nextStudent);
}
free(stud);
}
// To free the students list
void freeStudentsList(studentList* list) {
if(list != NULL) {
freeStudent(list->firstStudent);
free(list);
}
}
// Function that prints single student and returns next one (after him on the list)
student* printStudent(student* stud) {
if(stud == NULL) return NULL;
printf(" * Student { matrikelNummer = %d }\n", stud->matrikelNummer);
// Return next student
return stud->nextStudent;
}
// Function that prints students list
void printStudentsList(studentList* list) {
if(list == NULL) return;
printf("StudentsList [\n");
student* current_student = list->firstStudent;
while(current_student != NULL) {
current_student = printStudent(current_student);
}
printf("]\n");
}
int main(int argc, char** argv) {
studentList* list = NULL;
allocStudentsList(&list);
// Create some student data
student st1;
st1.matrikelNummer = 1;
// Another student...
student st2;
st2.matrikelNummer = 2;
// Put them into the list (allocates students and take care of everything)
addStudentToList(list, st1);
addStudentToList(list, st2);
// Print the list
printStudentsList(list);
// Free the list (recursively free's all students and take care of all the nasty stuff)
freeStudentsList(list);
return 0;
}
There are plenty of tutorials how to write C-style lists structures on the web.
You can find one yourself.
One of the tutorial is there: Learn-c linked list tutorial