Thread: C Structures and Strings

  1. #1
    Registered User
    Join Date
    Nov 2011
    Posts
    46

    C Structures and Strings

    So I have a program that reads in pairs of words from a text file, a word and its antonym. As it reads in the strings, it also sorts the pairs alphabetically depending on the first word in the pair. So far this works just fine.

    However, when I create a function to find the length of the longest string read in, the data gets messed up and there are repeats of some words while some are completely ignored.

    Code:
    /*********************************************************************************
    ** CIS 15BG                                                              Fall, 2011
    ***************
    **
    ** Homework 6:  
    **        Pointers, Structures, Arrays, Strings, and Dynamic Allocation of Memory
    **
    **********************************************************************************
    
      This program provides antonyms to common words. An antonym is a word with 
      the opposite meaning. For example, the antonym of happy is sad. The program is to 
      look for a word and if found, report its antonym. If the word is not found, the 
      program is to display an appropriate message.  
    
      The input text file has a word and its antonym on each line, as it is shown below:
    
            happy sad
            ugly  attractive
            nice  rude
            cold  warmth
    
    ****************************************
    **
    **  Written By: 
    **              // <-- 
    **  
    **  Date        // <-- write the date here
    ***************************************************************************/
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <crtdbg.h> 
    
    #define FILENAME "antonyms_0.txt"
    
    typedef struct
    {    
        char *word;
        char *antonym;
    } PAIR;
    
    typedef struct
    {    
        int   size;
        int   max_len; // the length of the longest word
        PAIR *pair;
    } LIST;
    
    
    LIST *createList(int num);
    LIST *getWords( char *fileName );
    char *allocateString( char *inString );
    void  readPair(FILE *fpWord, PAIR *pair, PAIR *revPair);
    void  insertPair(LIST *list, PAIR pair);
    void  printList (LIST *list, int num);
    int findMaxSize (LIST* list, char* temp1, char* temp2, char** longest, PAIR pair);
    
    void printInfo (void);
    void printEnd (void);
    
    int main (void)
    {
        LIST *list;
        int i;
    
        printInfo ();
    
        list = getWords(FILENAME);
        
        printf( _CrtDumpMemoryLeaks() ? "\nSorry, Memory Leak\n" : "\nCongratulations! No Memory Leak\n");
        printEnd ();
        system("pause");
        return 0;
    
    }// main 
    /* =================================================================================
    STUDENT - write your code below
    ================================================================================= */
    
    
    
    
    
    
    
    
    /* =================================================================================
    INSTRUCTOR
    ================================================================================= */
    /* ============================================================
        Prints information about the project.
           PRE  : nothing
           POST : info printed
    */
    void printInfo (void)
    {
        printf("\n\n\t\tPointers, \n\n\t\tStructures, \n\n\t\tArrays, "
               "\n\n\t\tStrings, and\n\n\t\tDynamic Allocation of Memory\n\n");
        printf("\tThis program provides antonyms to common words.\n");           
        putchar('\n');
    
        return;
    
    } // printInfo 
    
    /* ============================================================
        Prints a farewell message.
           PRE  : nothing.
           POST : farewell message printed
    */
    void printEnd (void)
    {
        printf("\n\t\tThank you for using the program,"
               "\n\t\tHave a great day!\n");
    
        return;
    
    } // printEnd 
    /* ============================================================
        Creates a sorted list of structures containing pointers 
        to words and their antonyms.
        Pre:  fileName - the name of the input file
        Post: pointer to the list of structures
    */
    LIST *getWords( char *fileName )
    {
        FILE *fpWord;
        LIST *list;
        PAIR  pair, revPair;
        int   i, num;
        char *temp1, *temp2, *longest;
        
        // open the input file
        fpWord = fopen (fileName, "r");
        if (!fpWord)
            printf ("Error opening %s!\n", fileName), exit (101);
        else
            printf("\t%s was read succesfully!\n", fileName);
    
        // read the number of pairs
        fscanf(fpWord, "%d", &num);
        printf("\tthere are %d pairs\n\n", num);
        list = createList(num);
    
        // read the first pair 
        readPair(fpWord, &pair, &revPair);
    
        // insert the first pair
        if( strcmp(pair.word, pair.antonym) < 0 ){
            list->pair[0] = pair;
            list->pair[1] = revPair;
        }
        else{
            list->pair[0] = revPair;
            list->pair[1] = pair;
        }
        list->size = 2;  // the first pair inserted: list has two words
        temp1 = pair.word;
        temp2 = pair.antonym;
    
        // read and insert the rest of the pairs
        for( i = 1; i < num; i++ ){
            readPair(fpWord, &pair, &revPair);
            insertPair(list, pair);
            insertPair(list, revPair);
            list->max_len = findMaxSize(list, temp1, temp2, &longest, pair);
        }
        printList(list, num);
        
        fclose(fpWord);
        return list;
    
    } // getWords
    
    /* ============================================================
        Allocates the header of the list and the list of pointers
        to words and their antonyms.
        Pre:  num - number of pairs           
        Post: list - empty
    */
    LIST *createList(int num)
    {    
        LIST *list;
    
        // allocate the header of the list
        list = (LIST *)malloc(sizeof(LIST));
        if (!list)
            printf ("Error allocating the header of the list!\n"), exit (102);
    
        // allocate the list of pointers to words and their antonyms
        list->pair = (PAIR *) calloc(2 * num, sizeof(PAIR));
        if (!list)
            printf ("Error allocating the list of words and their antonyms!\n"), exit (103);
        list->size = 0; // empty list
        
        return list;
    }// createList
    
    
    /* ============================================================
        Reads a pair of words and prepares them for insetions
        Pre:  fpWord           
        Post: pair, revPair
    */
    void  readPair(FILE *fpWord, PAIR *pair, PAIR *revPair)
    {    
        char  tempWord [100];
        char  tempAntonym [100];
    
        fscanf(fpWord, "%s %s", tempWord, tempAntonym);
        pair->word = allocateString(tempWord);
        pair->antonym = allocateString(tempAntonym);
        revPair->word = pair->antonym;
          revPair->antonym = pair->word;
        
        return;
    }// readPair
    
    /* ============================================================
        Inserts a word into a sorded list of words
        Pre:  list
              word
        Post: list updated
    */
    void  insertPair(LIST *list, PAIR pair)
    {    
        int curr = list->size;
        int i;
    
        i = curr - 1;
        while ( i >= 0 && strcmp(pair.word, list->pair[i].word) < 0 ){
            list->pair[i+1] = list->pair[i];
            i--;
        }
        list->pair[i+1] = pair;
        list->size++;
    
        return;
    }// insertPair
    
    /* ============================================================
        Creates a dynamically allocated string with the same contents
        as the input string
        Pre:  inString - input string
        Post: outString - dynamically allocated
    */
    char *allocateString( char *inString )
    {
                
        char *outString;
        int   stringSize;
    
        stringSize = strlen( inString ) + 1;
        outString = (char *) calloc (stringSize, sizeof (char));
        if ( outString == NULL)
            printf ("ERROR, not enough memory!!!\a\n"), exit (103);
        strcpy (outString, inString);
    
        return outString;
    
    }// allocateString 
    
    void printList (LIST* list, int num)
    {
        int i;
        for(i = 0; i < num; i++)
            printf("\t%s %s\n", list->pair[i]);
    
        return;
    } //printList
    
    /* ============================================================
        Finds length of longest string from file
        Pre:  inString - input string
        Post: outString - dynamically allocated
    */
    int findMaxSize (LIST* list, char* temp1, char* temp2, char** longest, PAIR pair)
    {
        int maxsize;
    
            if((strlen(pair.word) > strlen(temp1)))
                strcpy(temp1, pair.word);
            if((strlen(pair.antonym) > strlen(temp2)))
                strcpy(temp2, pair.antonym);
    
            if(strlen(temp1) > strlen(temp2))
            {
                maxsize = strlen(temp1);
                *longest = temp1;
            }
            else
            {
                maxsize = strlen(temp2);
                *longest = temp2;
            }
    
        return maxsize;
    } //findMaxSize
    The function that messes up the data is findMaxSize. It does what it's supposed to do, but I need to keep the data the way it is.
    Any ideas on how to change it so that I don't modify the data?
    All feedback is appreciated.

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    OK, I haven't exactly pinpointed the error, but my recommendation is to refactor some of this code.

    GetWords() for example, has too many responsibilities. And you make a structure called LIST which is, ostensibly, useless since it isn't a data structure. If you are going to go through the trouble of calling something a list, you might as well exploit it. After you read all the words and put them into an array, walk through it once and play king of the hill.

    Code:
    assume the first word is the longest
    while there are more words in the list
        compare the longest word with the current word
        if the current word is longer, make it the longest one
        next word
    return the longest word
    Now findMaxSize is a cohesive unit, unlike your code. Your findMaxSize is a poorly named comparison function, or a "best guess" function that has to be called in a loop somewhere else to actually work on the entire list. That makes things unnecessarily confusing.

    If there are mistakes with this part of the code, the mistakes should be around this function. Even if you don't get it right the first time (who would?), a design like this is easier to debug.

  3. #3
    Registered User
    Join Date
    Nov 2011
    Posts
    46
    Some of the code was given to us by our professor, including the structure definitions and most of getWords, and we were instructed to leave it as such.

    I put findMaxSize in a loop in getWords since that is the loop in which the pairs of words are being inserted into the "list".
    I have my first temp pointer pointing to the first word in the pair under the name "pair.word" and the second temp pointing to the other word in the first pair, "pair.antonym".

    In findMaxSize, what I am trying to do is have it so that as each word is read in, it compares the string length to the first word, (the word being pointed to) and then if the string length is larger to have it point to that word and so on until the longest strings from each pair are found and then compared to each other, then the longest of the two is assigned to *longest and the string length is assigned to list->max_len and returned from the function.

    I know that this function is what is messing up the data, but I can't seem to get it to leave the data they way they are without getting the wrong value for longest string.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I still think you should read in all the data before you try to find the longest strings. Especially since the longest strings can be in different pairs (for example, "splendid" is longer than "sad", and "rancorous" is longer than "like"). You will have to traverse all the pairs you have in order to find the longest word, and the longest antonym.

  5. #5
    Registered User
    Join Date
    Nov 2011
    Posts
    46
    So after the for loop ends in getWords:
    Code:
    for( i = 1; i < num; i++ ){        readPair(fpWord, &pair, &revPair);
            insertPair(list, pair);
            insertPair(list, revPair);
            //list->max_len = findMaxSize(list, temp1, temp2, &longest, pair);
    
        }
    that's when I should traverse the list for the longest string.

  6. #6
    Registered User
    Join Date
    Nov 2011
    Posts
    46

    Getting better?

    So I made an additional loop after the initial reading, and so far it works perfectly.

    Code:
    temp1 = &list->pair[0].word;
        temp2 = &list->pair[0].antonym;
        for(i = 0; i < num; i++)
        {
            if(strlen(list->pair[i].word) > strlen(*temp1))
                temp1 = &list->pair[i].word;
            if(strlen(list->pair[i].antonym) > strlen(*temp2))
                temp2 = &list->pair[i].antonym;
    
            if(strlen(*temp1) > strlen(*temp2))
            {
                list->max_len = strlen(*temp1);
                longest = *temp1;
            }
            else
            {
                list->max_len = strlen(*temp2);
                longest = *temp2;
            }
        }
    I made the temp variables double level pointers. I figure that makes more sense since I only want to change the data to which they point and not the data itself.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C Strings in Structures.
    By SlyMaelstrom in forum C++ Programming
    Replies: 15
    Last Post: 10-12-2005, 04:29 PM
  2. Replies: 2
    Last Post: 04-13-2003, 08:40 PM
  3. Strings and Structures
    By Kinasz in forum C Programming
    Replies: 3
    Last Post: 02-23-2003, 03:46 AM
  4. Structures Arrays and Char Strings
    By Crocksmyworld in forum C Programming
    Replies: 5
    Last Post: 01-19-2002, 11:56 PM
  5. Comparing strings w/in structures
    By vehl in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2001, 10:59 AM

Tags for this Thread