0

I am new to file handling and would like some help reading a text file with records for people containing their first and last name, address, city, state, zip code, and phone numbers all separate by "\t", and copy it into another file. The file read can hold any number of records.

I would like to be able to sort these records only by city alphabetically. I am new to file handling so I am not sure how to go about this once reading the file and how to go about it in my comparing function. Also, in my code I have some code commented out that is used to display what each file contains. My issue is when it is not commented out and is part of the program the text file does not copy to the target file. Why is that?

Thank you for the help in advance! My code is here:

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

typedef struct contacts {
    char fname[1000];
    char lname[1000];
    char address[1000];
    char city[1000];
    char state[1000];
    char zip[1000];
    char num[1000];
}ContactType;

#define MaxContacts 1000
ContactType contacts[MaxContacts];
int ncontacts = 0;// update to number of records stored in contacts[] 

int CompareCity(void *pa, void *pb);

int main()
{
    char ch, copy, show, source_file[1000], target_file[1000];
    FILE *source, *target;

    printf("Enter name of file to copy\n");
    gets(source_file);

    source = fopen(source_file, "r");

    if (source == NULL)
    {
        printf("Could not open file.\n");
        exit(EXIT_FAILURE);
    }

    printf("Enter name of target file\n");
    gets(target_file);

    target = fopen(target_file, "w");

    if (target == NULL)
    {
        fclose(source);
        printf("Could not open file\n");
        exit(EXIT_FAILURE);
    }

    printf("The contents of %s file are :\n", source_file);

    /*while ((ch = fgetc(source)) != EOF)
        printf("%c", ch);
    printf("\n");*/

    qsort(contacts, ncontacts, sizeof contacts[0], CompareCity);

    while ((copy = fgetc(source)) != EOF)
        fputc(copy, target);

    printf("File copied successfully.\n");

    printf("The contents of %s file are :\n", target_file);

    /*while ((show = fgetc(target)) != EOF) 
        printf("%c", show);
    printf("\n");*/

    fclose(source);
    fclose(target);

    return 0;
}

int CompareCity(void *pa, void *pb) {

    return strcmp(((ContactType*)pa)->city, ((ContactType*)pb)->city);
}
Benny
  • 15
  • 1
  • 7
  • 1
    Who do you know who has a 1000-letter name? Etc... Those are very enthusiastic numbers for the fields in the structure. – Jonathan Leffler Oct 25 '15 at 05:46
  • 1
    Also , `fgetc` returns `int` not `char` . – ameyCU Oct 25 '15 at 05:46
  • 1
    See [Why is the `gets()` function too dangerous to use?](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) You would do better to use the standard C function [`fgets()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fgets.html) or the POSIX function [`getline()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html) to read lines. Don't forget to check whether the input function succeeded before using the data. And error messages are best printed on standard error (`stderr`); that's what it is intended for. – Jonathan Leffler Oct 25 '15 at 05:47
  • Ahh ok thank you for the advice @JonathanLeffler. Also I just wanted to keep the array sizes for all of them consistent but I can change it if needed. – Benny Oct 25 '15 at 05:53
  • Consistent and large enough for any size of each of those in my struct I should say. – Benny Oct 25 '15 at 06:00
  • 1
    It isn't necessary to change it; too big is better than too small (I'd have different words of wisdom if you'd chose 20 instead of 1000, for example). However, using 7 K of memory is a little exorbitant when pretty much any address would fit in under 1 K. But you can make the code work OK with the sizes you've got. You're going to read the lines from the source file into an array of char, then split the fields into the array of your structure. They're tab delimited fields; you can probably just use `strtok()`, though in general that's not a good routine to use (find answers on SO dissing it). – Jonathan Leffler Oct 25 '15 at 06:15
  • Well, apparently there's [this girl with a very long name](http://community.seattletimes.nwsource.com/archive/?date=19910122&slug=1262030), so better be prepared. `:-)` – M Oehm Oct 25 '15 at 06:21
  • the posted code fails to cleanly compile. (2 instances of `gets()` and two unused variables. the call to qsort() has an invalid 4th parameter ) Always compile with all warnings enabled. (for gcc, at a minimum use: `-Wall -Wextra -pedantic` ) then fix the warnings,. – user3629249 Oct 25 '15 at 14:06
  • for readability by us humans, and for ease of documentation, strongly suggest only one variable declaration per line and only one variable declaration per statement. – user3629249 Oct 25 '15 at 14:09
  • within the main() function, the `magic` number 1000 is repeatedly used. `magic` numbers make code difficult to understand and a real headache to debug/maintain. (and a proper #define already exists) Suggest using the #define name throughout the code. – user3629249 Oct 25 '15 at 14:25
  • it is probably a 'small' thing, but the source file is never read into 'contacts[]' so what is qsort expected to be sorting? And a straight read of the file into `contacts[]` will not work unless each record in the file is actually 7000 bytes long. I.E. the posted code seems to be missing a lot of the key logic – user3629249 Oct 25 '15 at 14:36
  • these lines: `while ((copy = fgetc(source)) != EOF) fputc(copy, target);` will copy the file, however, it completely skips any sorting, etc. suggest elimination of these lines and addition (earlier in code) of reading records from the input file and breaking those records into the fields of the contacttype struct into the contacts[] array – user3629249 Oct 25 '15 at 14:43

1 Answers1

0

to answer your question about the commented code:

Each open file has the concept of a file pointer that indicates the current location for read/write operations to occur.

for the first commented code:

while ((ch = fgetc(source)) != EOF)
    printf("%c", ch);
printf("\n");

after inputing all the characters from the file, the file pointer is at the end of the file.

the code following the above tries to read through the file. However, the file pointer is already at the end of the file.

Suggest using rewind() (or better) lseek() to move the file pointer back to the start of the file before reading/parsing/sorting the file.

the second commented code:

while ((show = fgetc(target)) != EOF) 
    printf("%c", show);
printf("\n");

has a similar problem in that, again, the file pointer is already at the end of the new file.

BTW: fgetc() returns an 'int' and EOF is an int, so the declaration of ch and the declaration of show must be 'int' not 'char'. And EOF does not properly compare with a 'char'. No other changes to the code are needed to handle the declarations being 'int' rather than 'char'.

user3629249
  • 16,402
  • 1
  • 16
  • 17