When my file pointer hits it's second rewind, it causes a seg fault. I have no clue why. I'll include the main that is problematic at the top and all the code below it.
int main(void){
// creating the file pointer
FILE *fptr = fopen("input-machine-problem-1.txt", "r");
if (fptr == NULL) {
printf("Error! opening file");
return 0;
}
int edges;
int vertices;
int* edgesPtr = &edges;
int* verticesPtr = &vertices;
getNumberOfVerticesAndEdges(fptr, verticesPtr, edgesPtr);
LinkedList arrayOfLinkedLists[vertices];
int x, y;
for(int i = 0; i < vertices; i++){
if(fptr == NULL){
return 0;
}
rewind(fptr);
for(int j = 0; j < edges; j++){
printf("%d: ", j);
fscanf (fptr, "%d %d", &x, &y);
printf ("%d %d ", x, y);
if(i == x){
push(arrayOfLinkedLists[i], y);
} else if(i == y){
push(arrayOfLinkedLists[i], x);
}
printf("**\n");
}
}
// printAdjacencyLists(arrayOfLinkedLists, vertices);
fclose (fptr);
}
The whole file in case you want to copy and paste:
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int vertexNumber;
struct node *next;
} Node;
typedef struct linkedList{
Node* head;
int size;
} LinkedList;
void getNumberOfVerticesAndEdges(FILE* fp, int* vertices, int* edges);
void push(LinkedList linkedList, int vertex);
Node* createNode(int vertexNumber);
void printAdjacencyLists(LinkedList* arrayOfLinkedLists, int vertices);
int main(void){
// creating the file pointer
FILE *fptr = fopen("input-machine-problem-1.txt", "r");
if (fptr == NULL) {
printf("Error! opening file");
return 0;
}
int edges;
int vertices;
int* edgesPtr = &edges;
int* verticesPtr = &vertices;
getNumberOfVerticesAndEdges(fptr, verticesPtr, edgesPtr);
LinkedList arrayOfLinkedLists[vertices];
int x, y;
for(int i = 0; i < vertices; i++){
if(fptr == NULL){
return 0;
}
rewind(fptr);
for(int j = 0; j < edges; j++){
printf("%d: ", j);
fscanf (fptr, "%d %d", &x, &y);
printf ("%d %d ", x, y);
if(i == x){
push(arrayOfLinkedLists[i], y);
} else if(i == y){
push(arrayOfLinkedLists[i], x);
}
printf("**\n");
}
}
// printAdjacencyLists(arrayOfLinkedLists, vertices);
fclose (fptr);
}
void push(LinkedList linkedList, int vertex){
Node* newNode = createNode(vertex);
Node* cur = linkedList.head;
Node* prev = cur;
if(cur == NULL){
linkedList.head = newNode;
return;
}
while(newNode->vertexNumber > cur->vertexNumber){
prev = cur;
cur = cur->next;
}
newNode->next = cur;
prev->next = newNode;
}
Node* createNode(int vertexNumber){
Node* newNode = malloc(sizeof(Node));
if(!newNode){
return NULL;
}
newNode->vertexNumber = vertexNumber;
newNode->next = NULL;
return newNode;
}
void getNumberOfVerticesAndEdges(FILE* fp, int* vertices, int* edges){
if (fp == NULL) {
printf("Error! opening file");
return;
}
*vertices = 0;
*edges = 0;
while(1){
int x, y;
fscanf(fp, "%d %d^\n", &x, &y);
if(x > *vertices){
*vertices = x;
} if (y > *vertices){
*vertices = y;
}
*edges = (*edges) + 1;
if(feof(fp)) {
return;
}
}
}
void printAdjacencyLists(LinkedList* arrayOfLinkedLists, int vertices){
for(int i = 0; i < vertices; i++){
printf("\n%d: ", i);
if(arrayOfLinkedLists[i].head == NULL){
return;
}
Node* cur = arrayOfLinkedLists[i].head;
while(cur != NULL){
printf("%d --> ", cur->vertexNumber);
cur = cur->next;
}
}
}
You need to control your read loop with the return of
fscanf()
, e.g.(note: there is no need for
^\n
in your format string)This ensures that you only use the values in
x
andy
when they hold a valid value. As you have written it, eitherx
ory
or both can fail the conversion (with a matching or input failure) and you still use those values in comparison and depending on the result, assign the values to*verticies
without any guarantee thatx
ory
are valid.Further, as you have it written,
*edges = (*edges) + 1;
is executed afterfscanf()
fails and before you check the stream state leading toedges
being off-by-one too many.You can't use any input function correctly unless you check the return. Let me know if you have further questions. Your code may have other issues, but once the read failed -- that is your likely first major problem.
Next SegFault
Your next SegFault is in
push()
here:You don't check for end-of-list by checking if
cur == NULL
before dereferencingcur->vertexNumber
. That will do it every time. You can fix it with:Where Does The '*' Go?
Throughout your code you are attaching the indirection reference to the type instead of the variable. The can be misleading. Why?
Above you are certainly not declaring three pointers to
int
. Instead, you declarea
as a pointer toint
andb
andc
as simple integers.Makes that clear.
Obviously, the compiler doesn't care, it ignores whitespace between
'*'
and the variable name, so what you have is not wrong -- this is more a human factors/readability issue.Other Issues
If you are not using
size
, remove it from:Further, since
edges
andvertices
cannot be negative, nor cansize
orx
ory
, make themsize_t
instead ofint
. You match thetype
to the variable use, and on x86_64 you get an additional 4-bytes of range.Taking Another Approach To Your Code
Ideally, you want to only read your data file once. You can do so if you dynamically allocate pointers instead of using a VLA for
LinkedList arrayOfLinkedLists[vertices];
I'll leave the implementation of that to you. Addressing the issues above and cleaning up yourpush()
function a bit, you could do something like the following:Also included above is a
freelists()
function tofree()
all the memory you allocate for your lists. Always ensure you are tracking and freeing the memory you allocate. That way when allocating in other thanmain()
you are not creating memory-leaks.Example Made Up Input/Output
Exercising the code with example vertex would result in the following output:
(note: the filename can now be passed as the first argument to the program)