Search code examples
cfile-iolinked-listfgetc

fgetc fails to load last character of file


I am trying to load a file into my program so I can work with the bytes on an individual basis, but when I am loading the file it stops loading prematurely; always by 1 character. If there is only one character in the file it does not load it. Is the problem with how I am reading the file or is it in a different location?

#include <stdio.h>
#include <stdlib.h>

typedef struct node {//linked list structure, I use this because I am working with files of vastly varying length
    char val;
    struct node *next;
} data;

void printdata(data *head);
void freeData(data **head);
data* readFile(FILE *f);

void main(int argc, char *argv[]) {//set this up so it is easier to test
    if(argc == 2) {
        FILE *f = fopen(argv[1], "r");
        data *d = readFile(f);
        fclose(f);
        printdata(d);
        freeData(&d);
    }
}

data* readFile(FILE *f) {//This is the function containing the problem
    data *retVal = malloc(sizeof(data));
    data *cur = retVal;
    int c = fgetc(f);
    if(c != EOF) {
        retVal->val = (char) c;
        while((c = fgetc(f)) != EOF) {
            cur->next = malloc(sizeof(data));
            cur->next->val = (char) c;
            cur = cur->next;
        }
    } else return NULL;//EDIT: was in a rush and forgot to add this.
    cur->next = NULL;
    return retVal;
}

void freeData(data **head) {
    if((*head)->next != NULL) freeData(&((*head)->next));
    free(*head);
}

void printdata(data *head) {
    data *cur = head;
    do {
        printf("%c", cur->val);
        cur = cur->next;
    } while(cur->next != NULL);//EDIT: I changed this because there was a small "problem" that was not the real problem
    printf("\n");
}

Solution

  • printdata() stops too soon. @Barmar

    Do not stop when cur->next == NULL. Stop when cur == NULL

    void printdata(data *head) {
      data *cur = head;
      while (cur) {
        printf(" <%hhx>", cur->val);  // Changed format for debugging
        fflush(stdout);               // Useful for debugging
        cur = cur->next;
      }
      printf("\n");
    }
    

    Also included is a simplified readFile().

    data* readFile(FILE *f) { //This is the function containing the problem
      data head; // Only next field used
      data *cur = &head;
      int c;
      while ((c = fgetc(f)) != EOF) {
          cur->next = malloc(sizeof *(cur->next));
          cur = cur->next;
          assert(cur);
          cur->val = (char) c;
        }
      cur->next = NULL;
      return head.next;
    }