Thread: Sorting Records

  1. #1
    Registered User
    Join Date
    Jun 2010
    Posts
    36

    Sorting Records

    I am writing a program to sort records using a sorting algorithm of my choice. However before I can get to that I am having trouble reading in each record. Can someone provide some insight. I know that I want to do a linked list for easy insertion rather than an array, I just don't know where I am going wrong with my code. Thanks in advance!!

    Code:
    
    
    #include<stdio.h>
    #include<stdlib.h>
    
    FILE* fin;
    FILE* fout;
    
    struct record
    {
        char first[1024];
        char last[1024];
        int age;  
    };
    
    struct record* r;
    
    int main (void)
    {
        char filename[1024];
        int num_records;
        int i;
        int choice;
        
        //Ask user for the name of the file to read from
        printf("Please enter the name of the file you would like to read from \n");
        
        //Read in the file to read from
        scanf("%s", filename);
        
        //Open file for reading
        fin = fopen(filename, "r");
        
        //Check to make sure the file exists and opens correctly, if not display
        //an error message to the user
        if(fin == NULL)
        {
            printf("Unable to open the file %s\n", filename);
            system("PAUSE");
            return 0;   
        }
        
        //The first line of the input file will contain the number of records
        fscanf(fin, "%d ", &num_records);
        
        //Read in all of the records
        for (i = 0; i < num_records; i++)
        {
            fscanf(fin, "%s ", &r->first);             
            fscanf(fin, "%s ", r->last);
            fscanf(fin, "%d ", r->age);
        }
        
        while(choice != 5)
        {
            //Menu
            printf("Choose an option (1-5):\n");
            printf("1. Find the index of a person in the sorted ordering.\n");
            printf("2. Count the number of people in an age range.\n");
            printf("3. Count the number of distinct ages.\n");
            printf("4. Display frequency of each distinct age.\n");
            printf("5. Exit.\n");
            
            //Read in a choice from the user
            scanf("%d", &choice);
            
        }
        
        //Close the input file
        fclose(fin);
        
        system("PAUSE");
        return 0;
    }
    let me know if anything is unclear

  2. #2
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Your struct size is more than 2kB?

    Since you know how many records exist,

    Code:
     
       r = malloc( num_records * sizeof(*r) );          // why decl r as global ???
       if(r == NULL) {
          ...
       }
       for(i = 0; i < num_records ; i++) {
          int ret = fscanf(fin,"%s %s %d",r[i].first,r[i].last,&r[i].age);
          if(ret != 3) {
              // error
          }
       }
       // handle if there's any error in reading from file.
    Last edited by Bayint Naung; 07-09-2010 at 09:57 PM.

  3. #3
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Tha solution does use an array rather than a linked list, but with the limited info available to me I'd have to agree that an array is probably at least as good as a linked list for this.

    You should probably use %1024s in the scanf rather than just %s. Wouldn't want a slightly malformed file to crash your app right?
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  4. #4
    Registered User
    Join Date
    Jun 2010
    Posts
    36
    thanks. that helped a bunch. my program kept crashing but it's fixed now. Now I have to write a couple of functions which are really my weak point. could anyone provide me with some direction for the first one?

    Code:
    
    #include<stdio.h>
    #include<stdlib.h>
    
    FILE* fin;
    FILE* fout;
    
    struct record
    {
        char first[20];
        char last[20];
        int age;  
    };
    
    int findPerson(struct record* r, char fname[20], char lname[20], int yrsOld);
    int countPeople;    //Count the number of people in an age range
    int countAges;      //Count the number of people of a distinct age
    int frequency;       //Display the frequency of an age
    
    
    int main (void)
    {
        struct record* r;
        
        char filename[1024];
        int num_records;
        int i;
        int choice;
        
        //Ask user for the name of the file to read from
        printf("Please enter the name of the file you would like to read from \n");
        
        //Read in the file to read from
        scanf("%s", filename);
        
        //Open file for reading
        fin = fopen(filename, "r");
        
        //Check to make sure the file exists and opens correctly, if not display
        //an error message to the user
        if(fin == NULL)
        {
            printf("Unable to open the file %s\n", filename);
            system("PAUSE");
            return 0;   
        }
    
        //The first line of the input file will contain the number of records
        fscanf(fin, "%d ", &num_records);
        
        r = malloc(num_records * sizeof(*r));
              
        //Read in all of the records
        for (i = 0; i < num_records; i++)
        {
            int ret = fscanf(fin, "%s %s %d", r[i].first, r[i].last, &r[i].age);
        }
        
        //Interactive portion that allows the user to do different things with the data
        //Menu
        printf("Choose an option (1-5):\n");
        printf("1. Find the index of a person in the sorted ordering.\n");
        printf("2. Count the number of people in an age range.\n");
        printf("3. Count the number of distinct ages.\n");
        printf("4. Display frequency of each distinct age.\n");
        printf("5. Exit.\n");
        
        //Read in a choice from the user
        scanf("%d", &choice);
            
        while(choice != 5)
        {    
            if (choice == 1)
            {
                //findPerson(struct record* r, r[i].first, r[i].last, &r[i].age);
            }
            else if (choice == 2)
            {
            }
            else if (choice == 3)
            {
            }
            else if (choice == 4)
            {
            }
            else        //If the user enters something other than (1-5)
            {
                printf("You have selected an invalid option\n");
                system("PAUSE");
                return 0;
            }        
        }
        
        //Close the input file
        fclose(fin);
        printf("Exiting program...Goodbye!\n");
        system("PAUSE");
        return 0;
    }
    
    int findPerson(struct record* r, char fname[20], char lname[20], int yrsOld)
    {
        printf("Enter a first name: \n");
        scanf("%s", fname);
        
        printf("Enter a last name: \n");
        scanf("%s", lname);
        
        printf("Enter an age: \n");
        scanf("%d", &yrsOld);   
        
    }

  5. #5
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Well, it looks like an odd duck to me - it's like an array of pointers, but I've never seen an array just malloc'd, and not declared as an array, but just as a struct pointer - and that's all.

    On the find person function, are you looking for a binary search algorithm, or a simpler sequential search?

    Either way, an if statement or two is all you need to confirm names and age, and see if the person has been found.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Adak
    Well, it looks like an odd duck to me - it's like an array of pointers, but I've never seen an array just malloc'd, and not declared as an array, but just as a struct pointer - and that's all.
    You might have misread it. It looks like normal use of malloc to create a dynamic array of objects of struct type, except that there is a missing free.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Quote Originally Posted by laserlight View Post
    You might have misread it. It looks like normal use of malloc to create a dynamic array of objects of struct type, except that there is a missing free.
    I'm used to seeing an array of structs, (dynamic or static makes no diff), but this:

    Code:
        struct record* r;
        
        r = malloc(num_records * sizeof(*r));
    looks like an organized block of memory, only. An array wanna be.

    No square brackets, no array!

    I've seen (and rarely used) arrays like this, but never for structs.

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Adak
    I'm used to seeing an array of structs, (dynamic or static makes no diff)
    (...)
    looks like an organized block of memory, only. An array wanna be.
    hmm... how would you create a "dynamic array" in C then? (Exclude variable length arrays, since they are a somewhat different sort of creature, and partial use of a huge fixed size array.)

    EDIT:
    To be honest, I am shocked by your reply. I have never met another C programmer with what I presume is the considerable experience that you have, who would be surprised by that line of code in itself.
    Last edited by laserlight; 07-15-2010 at 01:15 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Jun 2010
    Posts
    36
    This keeps causing an error:
    Code:
    if (choice == 1)
    {
                int d = findPerson(int struct record* r, r[i].first, r[i].last, &r[i].age);
                printf("This person is at index %d \n", d);
    }
    Here is the corresponding function:

    Code:
    int findPerson(struct record* r, int num_records, char firstsearch[20], char lastsearch[20], int agesearch)
    {
        printf("Enter a first name: \n");
        scanf("%s", firstsearch);
        
        printf("Enter a last name: \n");
        scanf("%s", lastsearch);
        
        printf("Enter an age: \n");
        scanf("%d", &agesearch);   
        
        //Start at the first record and stop once you get to a record that has an
        //age larger than the one that we are looking for. Then search by last name.
        //Then search by first name to see if we have a match. Return the index 
        //location of that record.
        
        for (i = 0; i < num_records; i++)
        {
            while (agesearch < r[i].age) //Don't look past the age the user entered
            {
                if(agesearch == r[i].age)
                {
                    while (strcmp(lastsearch, r[i].last) < 0)
                    {
                        if(strcmp(lastsearch, r[i].last) == 0)
                        {
                            while (strcmp(firstsearch, r[i].first) < 0)
                            {
                                if(strcmp(firstsearch, r[i].first) == 0)
                                {
                                    return i;
                                }
                            }
                        }
                    }  
                }
                else
                {
                    printf("No such person is present"); //This may need to be moved
                    i++;
                }
            }
        }
        return;
    }
    Last edited by lostandconfused; 07-15-2010 at 04:39 PM.

  10. #10
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    if (choice == 1)
                int d = findPerson(int struct record* r, r[i].first, r[i].last, &r[i].age);
                printf("This person is at index %d \n", d);
    Are those two lines supposed to be part of the if statement there? If so, you need to wrap them up in a pair of braces.
    Code:
    if (choice == 1) {
                int d = findPerson(int struct record* r, r[i].first, r[i].last, &r[i].age);
                printf("This person is at index %d \n", d);
    }
    Also, you have this problem:
    Code:
    findPerson(int struct record* r, r[i].first, r[i].last, &r[i].age);
    Neither of those are probably supposed to be there.

    Quzah.
    Hope is the first step on the road to disappointment.

  11. #11
    Registered User
    Join Date
    Jun 2010
    Posts
    36
    sorry bout that. i fixed it. But the error I am getting is not related to that. It says syntax error before 'int'. It is referring to the int after 'findPerson('

  12. #12
    Registered User
    Join Date
    Jun 2010
    Posts
    36
    I've changed the part that you colored and I tried deleting
    Code:
     int struct record*
    and it still won't compile???

  13. #13
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    So how about posting the complete latest version of your code, along with the errors and warnings you're getting?


    Quzah.
    Hope is the first step on the road to disappointment.

  14. #14
    Registered User
    Join Date
    Jun 2010
    Posts
    36
    It messes up in the while loop when I am trying to mergeSort the data. The error message is:
    Code:
    86  [Warning] passing arg 2 of `findPerson' makes integer from pointer without a cast
    Here is the full code:
    Code:
    #include<stdio.h>
    #include<stdlib.h>
    
    FILE* fin;
    FILE* fout;
    int i;
    
    struct record
    {
        char first[20];
        char last[20];
        int age;  
    };
    
    int findPerson(struct record* r, int num_records, char firstsearch[20], char lastsearch[20], int agesearch);
    void mergeSort(struct record* r, int temp[], int array_size);
    void m_sort(struct record* r, int temp[], int left, int right);
    void merge(int numbers[], int temp[], int left, int mid, int right);
    
    int countPeople;    //Count the number of people in an age range
    int countAges;      //Count the number of people of a distinct age
    int frequency;       //Display the frequency of an age
    
    int main (void)
    {
        struct record* r;
        
        char filename[1024];
        int num_records;
        int choice;
        
        //Ask user for the name of the file to read from
        printf("Please enter the name of the file you would like to read from \n");
        
        //Read in the file to read from
        scanf("%s", filename);
        
        //Open file for reading
        fin = fopen(filename, "r");
        
        //Check to make sure the file exists and opens correctly, if not display
        //an error message to the user
        if(fin == NULL)
        {
            printf("Unable to open the file %s\n", filename);
            system("PAUSE");
            return 0;   
        }
        
        /*****************READ IN FROM THE FILE************************************/
        //The first line of the input file will contain the number of records
        fscanf(fin, "%d ", &num_records);
        
        r = malloc(num_records * sizeof(*r));
              
        //Read in all of the records
        for (i = 0; i < num_records; i++)
        {
            int ret = fscanf(fin, "%s %s %d", r[i].first, r[i].last, &r[i].age);
            printf("%s %s %d \n", r[i].first, r[i].last, r[i].age);
        }
        printf("\n");
        
        /**************************MERGE SORT THE DAT..........***************************/
        //Interactive portion that allows the user to do different things with the data
        //Menu
        printf("Choose an option (1-5):\n");
        printf("1. Find the index of a person in the sorted ordering.\n");
        printf("2. Count the number of people in an age range.\n");
        printf("3. Count the number of distinct ages.\n");
        printf("4. Display frequency of each distinct age.\n");
        printf("5. Exit.\n");
        
        //Read in a choice from the user
        scanf("%d", &choice);
            
        while(choice != 5)
        {    
            if (choice == 1)
            {
                int d = findPerson(r, num_records, r[i].first, r[i].last, r[i].age);
                printf("This person is at index %d \n", d);  
                
            }
            else if (choice == 2)
            {
            }
            else if (choice == 3)
            {
            }
            else if (choice == 4)
            {
            }
            else        //If the user enters something other than (1-5)
            {
                printf("You have selected an invalid option\n");
                system("PAUSE");
                return 0;
            }        
        }
        
        //Close the input file
        fclose(fin);
        
        free(r);
        
        printf("Exiting program...Goodbye!\n");
        system("PAUSE");
        return 0;
    }
    
    
    /*****************************FUNCTIONS****************************************/
    int findPerson(struct record* r, int num_records, char firstsearch[20], char lastsearch[20], int agesearch)
    {
        printf("Enter a first name: \n");
        scanf("%s", firstsearch);
        
        printf("Enter a last name: \n");
        scanf("%s", lastsearch);
        
        printf("Enter an age: \n");
        scanf("%d", &agesearch);   
        
        //Start at the first record and stop once you get to a record that has an
        //age larger than the one that we are looking for. Then search by last name.
        //Then search by first name to see if we have a match. Return the index 
        //location of that record.
        
        for (i = 0; i < num_records; i++)
        {
            while (agesearch < r[i].age) //Don't look past the age the user entered
            {
                if(agesearch == r[i].age)
                {
                    while (strcmp(lastsearch, r[i].last) < 0)
                    {
                        if(strcmp(lastsearch, r[i].last) == 0)
                        {
                            while (strcmp(firstsearch, r[i].first) < 0)
                            {
                                if(strcmp(firstsearch, r[i].first) == 0)
                                {
                                    return i;
                                }
                            }
                        }
                    }  
                }
                else
                {
                    printf("No such person is present"); //This may need to be moved
                    i++;
                }
            }
        }
        return;
    }
    Last edited by lostandconfused; 07-15-2010 at 07:24 PM. Reason: shortened warning message; got the code to compile...updated version is posted

  15. #15
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Quote Originally Posted by laserlight View Post
    hmm... how would you create a "dynamic array" in C then? (Exclude variable length arrays, since they are a somewhat different sort of creature, and partial use of a huge fixed size array.)

    EDIT:
    To be honest, I am shocked by your reply. I have never met another C programmer with what I presume is the considerable experience that you have, who would be surprised by that line of code in itself.
    I use dynamic arrays, but I've never used them for structs.

    This is a "full on" array:
    int myInts[][];
    You have the "cereal" [] and the "bowl" [] for your breakfast.

    This is a "half and half" array of pointers to an array:
    int *myInts[];
    You have the bowl [] and the pointer will provide the cereal. Not related in any way to manna from heaven!

    And this is an "odd duck", where we're fully "under the hood" of the surface "shine" of an array, pointer to pointer:

    int **myInts;

    You have twice the cereal, but no bowl. Good luck with that breakfast << just kidding >>

    Back to the program thread:

    You aren't "merging" anything here - this should say: "Display the Menu", not "Merge Sort".

    Code:
        
        /**************************MERGE SORT THE DAT..........***************************/
        //Interactive portion that allows the user to do different things with the data
        //Menu
        printf("Choose an option (1-5):\n");
        printf("1. Find the index of a person in the sorted ordering.\n");
        printf("2. Count the number of people in an age range.\n");
        printf("3. Count the number of distinct ages.\n");
        printf("4. Display frequency of each distinct age.\n");
        printf("5. Exit.\n");
        
        //Read in a choice from the user
        scanf("%d", &choice);
            
        while(choice != 5)
        {    
            if (choice == 1)
            {
                int d = findPerson(r, num_records, r[i].first, r[i].last, r[i].age);
                printf("This person is at index %d \n", d);  
                
            }
            else if (choice == 2)
            {
            }
            else if (choice == 3)
            {
            }
            else if (choice == 4)
            {
            }
            else        //If the user enters something other than (1-5)
            {
                printf("You have selected an invalid option\n");
                system("PAUSE");
                return 0;
            }        
        }
    Well done on the indentation. Really makes the code easy to read.

    I think you know the right way to do this search, but this description is wrong:
    //Start at the first record and stop once you get to a record that has an
    //age larger than the one that we are looking for. Then search by last name.
    //Then search by first name to see if we have a match. Return the index
    //location of that record.
    Because once you get to a record that has an age larger than the one that you are looking for, the search is over - that record has not been found, and no further searching is necessary.

    When you have a while loop, and there is no logic to increment or decrement the loop counter, you can expect an endless loop. Now look at your search loops. Since the while loops are INSIDE the for loop. Once entered, they will loop endlessly. i will not increment any further, as you might expect.

    Where the records are sorted by:age, last name, first name.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 26
    Last Post: 07-05-2010, 10:43 AM
  2. Replies: 10
    Last Post: 03-03-2010, 01:33 AM
  3. reading a file into a block
    By mickey0 in forum C++ Programming
    Replies: 19
    Last Post: 05-03-2008, 05:53 AM
  4. Counting number from a random file
    By kamisama in forum C Programming
    Replies: 42
    Last Post: 02-22-2005, 05:16 PM
  5. sorting records on a file by more than one field
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 09-27-2001, 05:54 PM