Thread: Printing contents of a file...prints one extra character not present in the file.

  1. #1
    Registered User
    Join Date
    Feb 2013
    Posts
    5

    Printing contents of a file...prints one extra character not present in the file.

    Hello,
    I'm writing a program that stores records into a file and then these records can be printed out. A last name, first name, and score is stored to be exactly 36 characters long (using leading spaces to pad) making it easier to retrieve specific records. For example, three records stored in the file would like like this: (the underscores are simply to illustrate the distance, they are not in the file itself)

    _______lastname_______firstname__90__________lname __________fname_100___________last___________first __60

    When printed out, the names are formatted as follows:

    lastname, firstname: 90
    lname, fname: 100
    last, first: 60

    However, when I print them out this is what I get:

    lastname, firstname: 90
    lname, fname: 100$
    last, first: 60H

    For some reason, for any record after the first, an extra character is added to the end. These characters are not in the file, so I was thinking that the array for some reason wasn't being filled completely, (the array is initialized to size 36 and 36 characters are read from the file using fread) so it was printing out a random character assigned to the 36th array position. Except the character never changes, (always a $ for record 2, H for record 3, l for record 4 if i remember) and I've tried reducing the array size or the number of character read and it's the string that gets altered, the random character always remains. I figure the problem must be in the print_records function (appending seems to work no problem). Anyway here is my print records and appending records code.

    Code:
    /*
     - Prints a single record stored in the file pointed to by ifp.
    */
    void print_record(FILE *ifp, int record) {
        char record_array[36];
        size_t i;
        int break_count = 0;
        char cur_char;
        char prev_char = '\0';
        int file_location = 36 * (record - 1);
        if(fseek(ifp, file_location, SEEK_SET) != 0)
            perror("fseek");
        fread(record_array, 1, 36, ifp);
        for(i = 0; record_array[i] != '\0'; i++) {
            cur_char = record_array[i];
            if(cur_char != ' ')
                printf("%c", record_array[i]);
            else if(cur_char == ' ' && isalpha((int)prev_char)) {
                if(break_count == 1)
                    printf(": ");
                else if(break_count == 0) {
                    printf(", ");
                    break_count++;
                }
            }
            prev_char = cur_char;
        }
        printf("\n");
    }
    
    
    /*
     - Appends the name portion of a record to the end of the file pointed to by ifp.
    */
    void append_records_name(FILE *ifp, char name[]) {
        if(fseek(ifp, 0, SEEK_END) != 0)
            perror("fseek");
        str_lowercase(name);
        fprintf(ifp, "%15s", name);
        fprintf(ifp, " ");
    }
    
    
    /*
     - Appends the score portion of a record to the end of the file pointed to by ifp.
    */
    void append_records_score(FILE *ifp, int score) {
        if(fseek(ifp, 0, SEEK_END) != 0)
            perror("fseek");
        fprintf(ifp, "%3d", score);
        fprintf(ifp, " ");
    }
    Any help that can be provided would be much appreciated.

  2. #2
    Registered User
    Join Date
    Dec 2012
    Posts
    307
    have you, in the declairing of your arrays, accounted for the ending bit???

    ie array[30] is really an array of 29 user entered, and the last one for the end of line?

    post the beginning of your code that contains your declarations

  3. #3
    Registered User
    Join Date
    Feb 2013
    Posts
    5
    I actually have no declarations outside of the individual functions. As for the array, it should be an array of 36 user entered characters. I'm using fseek to get 36 characters and feeding it to an array of 36. I thought that since arrays start at 0 an array of 36 would actually have room for 37 characters, hence the extra character, but reducing the size of the array to 35 while still reading 36 characters messed with the rest of the string, leaving the ending char intact.

    Here is the entirety of my code for reference:

    Code:
    #include <stdio.h>
    #include <ctype.h>
    #include <string.h>
    
    
    #define LINESIZE 1024
    
    
    /*
     - Returns 1 if the string s consists entirely of alphabets; otherwise, returns 0.
    */
    int str_all_alphabets(const char s[]) {
        size_t i;
        for(i = 0; s[i] != '\0'; i++)
            if(!isalpha((int)s[i]))
                return 0;
        return 1;
    }
    
    
    /*
     - Converts all characters in the array to lowercase.
    */
    void str_lowercase(char s[]) {
        size_t i;
        for(i = 0; s[i] != '\0'; i++)
            s[i] = tolower((int)s[i]);
    }
    
    
    /*
     - Returns the length of the array.
    */
    size_t str_length(char s[]) {
        size_t length;
        length = strlen(s);
        return length;
    }
    
    
    /*
     - Counts the number of characters in the file and divides that number by 36
     - to determine the total number of records in the file.
    */
    size_t count_records(FILE *ifp) {
        int char_count = 0;
        int num_records;
        int c;
        if(fseek(ifp, 0, SEEK_SET) != 0)
            perror("fseek");
        while(1) {
            c = fgetc(ifp);
            if(c == EOF)
                break;
            char_count++;
        }
        num_records = char_count / 36;
        return num_records;
    }
        
    /*
     - Return 0 on end-of-file or if the integer -1 is read, or 1 if a name is successfully 
     - read & stored in the array word of n characters.
    */
    int get_name(const char prompt[], char word[], size_t n) {
        char line[LINESIZE];
        char holder[LINESIZE];
        int int_holder[LINESIZE];
        while(1) {
            printf("%s", prompt);
            if(!fgets(line, LINESIZE, stdin)) {
                clearerr(stdin);
                break;
            }
            if(sscanf(line, "%d", int_holder) == 1)
                if(int_holder[0] == (int)-1)
                    return 0;
            if(sscanf(line, "%s", holder) == 1) {
                if(strlen(holder) < n) {
                    if(str_all_alphabets(holder) != 0) {
                            strcpy(word, holder);
                            return 1;
                    }
                }
            }
        }
        return 0;
    }
    
    
    /*
     - Returns max + 1 on end-of-file or if the integer -1 is read, or the integer read 
     - from the user if it is between min & max inclusive.
    */
    int get_score(const char prompt[], int min, int max, int *score) {
        char line[LINESIZE];
        int n;
        while(1) {
            printf(prompt);
            if(!fgets(line, LINESIZE, stdin)) {
                clearerr(stdin);
                return max + 1;
            }
            if(sscanf(line, "%d", &n) == 1) {
                if(n == -1)
                    return max + 1;
                if(n >= min && n <= max) {
                    *score = n;
                    return n;
                }
            }
        }
    }
    
    
    /*
     - Prints a single record stored in the file pointed to by ifp.
    */
    void print_record(FILE *ifp, int record) {
        char record_array[36];
        size_t i;
        int break_count = 0;
        char cur_char;
        char prev_char = '\0';
        int file_location = 36 * (record - 1);
        if(fseek(ifp, file_location, SEEK_SET) != 0)
            perror("fseek");
        fread(record_array, 1, 36, ifp);
        for(i = 0; record_array[i] != '\0'; i++) {
            cur_char = record_array[i];
            if(cur_char != ' ')
                printf("%c", record_array[i]);
            else if(cur_char == ' ' && isalpha((int)prev_char)) {
                if(break_count == 1)
                    printf(": ");
                else if(break_count == 0) {
                    printf(", ");
                    break_count++;
                }
            }
            prev_char = cur_char;
        }
        printf("\n");
    }
    
    
    /*
     - Appends the name portion of a record to the end of the file pointed to by ifp.
    */
    void append_records_name(FILE *ifp, char name[]) {
        if(fseek(ifp, 0, SEEK_END) != 0)
            perror("fseek");
        str_lowercase(name);
        fprintf(ifp, "%15s", name);
        fprintf(ifp, " ");
    }
    
    
    /*
     - Appends the score portion of a record to the end of the file pointed to by ifp.
    */
    void append_records_score(FILE *ifp, int score) {
        if(fseek(ifp, 0, SEEK_END) != 0)
            perror("fseek");
        fprintf(ifp, "%3d", score);
        fprintf(ifp, " ");
    }
    
    
    /*
     - Prompts the user to choose one of the three options. 
     - The user can either append a record, print a single record, or print
     - all records from a certain record number. The program continuously prompts users
     - for further commands until the user quits with the end-of-file key.
    */
    void program_structure(FILE *ifp) {
        size_t i;
        int c;
        char line[LINESIZE];
        char first_name_input[15];
        char last_name_input[15];
        int score = 0;
        int first_name_success = 0;
        int last_name_success = 0;
        int score_success = 0;
        size_t num_records;
        while(1) {
            fprintf(stderr, "Enter a command: \n");
            fprintf(stderr, "Enter 0 to append a record \n");
            fprintf(stderr, "Enter a negative integer to display all records from that record number to the end \n");
            fprintf(stderr, "Enter a positive integer to display that chosen record \n");
            if(!fgets(line, LINESIZE, stdin)) {
                clearerr(stdin);
                break;
            }
            if(sscanf(line, "%d", &c) == 1) {
                num_records = count_records(ifp);
                if(c == 0) {
                    if(get_name("Please enter a last name: ", last_name_input, 15) != 0)
                        last_name_success = 1;
                    else 
                        continue;
                    if(get_name("Please enter a first name: ", first_name_input, 15) != 0)
                        first_name_success = 1;
                    else 
                        continue;
                    if(get_score("Please enter a score between 0 and 100 inclusive: ", 0, 100, &score) != 101)
                        score_success = 1;
                    else 
                        continue;
                    if(first_name_success && last_name_success && score_success) {
                        append_records_name(ifp, last_name_input);
                        append_records_name(ifp, first_name_input);
                        append_records_score(ifp, score);
                    }
                }
                if(c > 0) {
                    if(c > (int)num_records)
                        fprintf(stderr, "No records to display \n");
                    else
                        print_record(ifp, c);
                }
                if(c < 0) {
                    c = c + (-2 * c);
                    if(c > (int)num_records)
                        fprintf(stderr, "No records to display \n");
                    else
                        for(i = c; i <= num_records; i++)
                            print_record(ifp, i);
                }
            }
        }
    }
    /*
     - The driver class for this program.
    */
    int main(int argc, char* argv[]) {
        FILE *ifp;
        if(argc != 2) {
            fprintf(stderr, "usage: %s file \n", argv[0]);
            return 1;
        }    
        if((ifp = fopen(argv[1], "ab+")) == 0) {
            perror("fopen");
            return 2;
        }
        program_structure(ifp);
        if(fclose(ifp) != 0) {
            perror("fclose");
            return 3;
        }
        return 1;
    }

  4. #4
    Registered User
    Join Date
    Dec 2012
    Posts
    307
    Quote Originally Posted by Mark Ahmadi View Post
    I thought that since arrays start at 0 an array of 36 would actually have room for 37 characters
    array[36] is an array of 36, with indexes 0-35, NOT 0-36

    checking code now...

    ok what i am seeing is a few probs
    1) if the file is already there, and you try to read without appending it first, it says no records! (yeah it is screwing me up to test! lol)
    2) it seems to be reading the file, entering it into the array, and the end of the array that isnt initilized, still printing it.
    if score is 100, you have 10 spaces after it, if score is 1 you have 12 dead spaces after it, when the array is reading it, it is displaying the memory in the location of the record_array which is where i think your getting the "random" chars from

    btw when i do it, i get more then the two

    softwarez, crossfire: 100D ↑
    Last edited by Crossfire; 02-12-2013 at 04:09 PM.

  5. #5
    Registered User
    Join Date
    Feb 2013
    Posts
    5
    I apologize, but I don't quite understand what you are talking about with point 2.

  6. #6
    Registered User
    Join Date
    Dec 2012
    Posts
    307
    ok you have an array[36]
    reads the file
    at the end of the read, let say you only read in 34, the last two, never being set to anything, just diplays whatever is in that memory area.

    //edit//
    ok this is annoying me now!!!
    Last edited by Crossfire; 02-12-2013 at 07:21 PM.

  7. #7
    Registered User
    Join Date
    Feb 2013
    Posts
    5
    Ok I sidestepped the problem by breaking out of the printing loop if the next char was a space and the last char is a digit. I'll keep working on it to actually try to fix it.

    As for the other problem with it not displaying existing records without appending first. Any idea on how to fix that? I doing this in Cygwin on Windows and I can't seem to actually replicate the error because it's like Cygwin is keeping previous results in memory so I can't test fixes. If I append a record, close the Cygwin prompt, delete the record from the file, open Cygwin again and run the program and try to display a now non-existent record it just displays what was previously there. Just simply looking at the code I can't see why it would do this. It's supposed to get a fresh count of the number of records every time it executes a command.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Printing contents of a text file
    By never_lose in forum C Programming
    Replies: 10
    Last Post: 04-28-2011, 09:25 AM
  2. File I/O..Reading a file and printing contents
    By eeengenious in forum C Programming
    Replies: 2
    Last Post: 03-14-2011, 05:58 PM
  3. binary file copy has extra character
    By leonv in forum C Programming
    Replies: 2
    Last Post: 03-22-2010, 11:14 PM
  4. Printing contents of an input file to the screen
    By babe20042004 in forum C++ Programming
    Replies: 2
    Last Post: 11-24-2009, 12:57 PM
  5. Printing out contents of a file to the screen
    By Simon in forum C Programming
    Replies: 18
    Last Post: 10-21-2002, 08:05 AM

Tags for this Thread