Thread: Weight Change Program - Help

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    8

    Weight Change Program - Help

    The program is given input from a file in the following format:

    A 45kg 52lb 5
    B 82lb 15st 8
    C 14st 80kg 10
    etc..

    Where A is a user identifier, 45kg is the starting weight, 52lb is the ending weight, and 5 is the numbers of days that has elapsed. (In the second line st stands for stones and is equal to 14lb).

    The program must compute and output the average weight gain/loss per day in kg for each line of input. There's also a whole bunch of validation for each input but I've pretty much covered those. I know how to get the digits from each line of input and I know how to convert ASCII to int. What I don't know is how to separate the numbers from each other so I can do the conversions necessary to calculate the weight change.

    What I mean by this, taking line 1 as an example:

    How do I separate 45 from 52 from 5 and how do I know that its 45kg (as opposed to lb or st), and 52lb (as opposed to kg or st)?

    Code:
    tokenPtr = strtok( ch, "kg "" "" lb st '\t'" ); 
    
    	while ( tokenPtr != NULL ) 
    	{ 
    		printf( "%s\n", tokenPtr );
    		tokenPtr = strtok( NULL, "kg "" "" lb st '\t'" );
    	}
    That gives the separated numbers, however I still don't know how to determine the units of the weights, or even if I'm going in the right track.

    BTW 'm not permitted to use any functions other than getchar(), putchar(), printf(), and the functions from string(3).

    Any help is appreciated.
    Last edited by battousaih; 10-01-2007 at 02:31 PM.

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    Sooooo, you're calculating weight gain (or loss) for multiple users over N days, where the weights can be in varying units for each user?
    My best code is written with the delete key.

  3. #3
    Registered User
    Join Date
    Oct 2007
    Posts
    8
    Yes that's right. Each input line signifies a different user. And the various weight records can be in either pounds, kilograms, or stones. BTW 'm not permitted to use any functions other than getchar(), putchar(), printf(), and the functions from string(3).
    Last edited by battousaih; 10-01-2007 at 02:17 PM.

  4. #4
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    Okie dokie. So you want to be able to convert stones and pounds to kilos for processing. As a first attempt, go for a simple parsing scheme and see if it works. Something like this:
    Code:
    sscanf ( line, "%s%d%s%d%s%d", user, &weighta, unita, &weightb, unitb, &days );
    My best code is written with the delete key.

  5. #5
    Registered User
    Join Date
    Oct 2007
    Posts
    8
    Unfortunately, I'm not allowed to use sscanf. Only getchar(), putchar(), printf(), and the functions from string(3).

  6. #6
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Unfortunately, I'm not allowed to use sscanf.
    Stupid teachers make you do stupid things. How about this then, is it suitably horrendous?
    Code:
    /* Be sure to initialize the first character of the arrays to '\0' */
    next = strcspn ( line, " \t" );
    strncat ( user, line, next );
    
    weighta = strtol ( line + next, &nextp, 0 );
    next = strcspn ( nextp, " \t" );
    
    strncat ( unita, nextp, next );
    
    weightb = strtol ( nextp + next, &nextp, 0 );
    next = strcspn ( nextp, " \t" );
    
    strncat ( unitb, nextp, next );
    
    days = strtol ( nextp + next, &nextp, 0 );
    My best code is written with the delete key.

  7. #7
    Registered User
    Join Date
    Oct 2007
    Posts
    8
    Quote Originally Posted by Prelude View Post
    >Unfortunately, I'm not allowed to use sscanf.
    Stupid teachers make you do stupid things. How about this then, is it suitably horrendous?
    Code:
    /* Be sure to initialize the first character of the arrays to '\0' */
    next = strcspn ( line, " \t" );
    strncat ( user, line, next );
    
    weighta = strtol ( line + next, &nextp, 0 );
    next = strcspn ( nextp, " \t" );
    
    strncat ( unita, nextp, next );
    
    weightb = strtol ( nextp + next, &nextp, 0 );
    next = strcspn ( nextp, " \t" );
    
    strncat ( unitb, nextp, next );
    
    days = strtol ( nextp + next, &nextp, 0 );
    Wow, I'm completely lost on that. I'm a beginner at C, borderline incompetent even. Could you break it down explaining what each line does, please.

  8. #8
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Wow, I'm completely lost on that.
    Now now, let's skip the flattery.

    >Could you break it down explaining what each line does, please.
    Okay, let's start with line = "C 14st 80kg 10".

    >next = strcspn ( line, " \t" );
    If you print &p[next], you'll get " 14st 80kg 10". strcspn essentially finds the first occurrence of any of the characters in the second argument (ie. a tab or a space) and returns the index of that occurrence. In this case, next has a value of 1.

    >strncat ( user, line, next );
    strcat appends the first argument with N characters from the second argument, where N is specified by the third argument. It copies 1 character from "C 14st 80kg 10" into user, so user becomes "C".

    >weighta = strtol ( line + next, &nextp, 0 );
    strtol skips whitespace and tries to convert the next non-whitespace characters into an integer. It stores the point where it can't convert anymore in the second argument, and uses the third argument as a radix. Put simply, this guy will store 14 in weighta because after whitespace the string is "14st 80kg 10". It's that way because I added next to line, thus shifting line forward by one character. nextp points to the string "st 80kg 10" because the 's' was the first non-digit character that strtol found.

    The rest of the lines just repeat that process until there's nothing left to read.
    My best code is written with the delete key.

  9. #9
    Registered User
    Join Date
    Oct 2007
    Posts
    8
    Quote Originally Posted by Prelude View Post
    >Wow, I'm completely lost on that.
    Now now, let's skip the flattery.

    >Could you break it down explaining what each line does, please.
    Okay, let's start with line = "C 14st 80kg 10".

    >next = strcspn ( line, " \t" );
    If you print &p[next], you'll get " 14st 80kg 10". strcspn essentially finds the first occurrence of any of the characters in the second argument (ie. a tab or a space) and returns the index of that occurrence. In this case, next has a value of 1.

    >strncat ( user, line, next );
    strcat appends the first argument with N characters from the second argument, where N is specified by the third argument. It copies 1 character from "C 14st 80kg 10" into user, so user becomes "C".

    >weighta = strtol ( line + next, &nextp, 0 );
    strtol skips whitespace and tries to convert the next non-whitespace characters into an integer. It stores the point where it can't convert anymore in the second argument, and uses the third argument as a radix. Put simply, this guy will store 14 in weighta because after whitespace the string is "14st 80kg 10". It's that way because I added next to line, thus shifting line forward by one character. nextp points to the string "st 80kg 10" because the 's' was the first non-digit character that strtol found.

    The rest of the lines just repeat that process until there's nothing left to read.
    I had to read that a few times before getting the jist of it. Ok from what I understand, this does a good job of separating all the data I need so I can do the calculations. But how do I know that 14 is in stones and not some other weight format (ie. kg or lb), or 80 is in kg (not st or lb)? Unless I'm missing something here...

  10. #10
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >But how do I know that 14 is in stones and not some other
    >weight format (ie. kg or lb), or 80 is in kg (not st or lb)?
    You know because you saved that information. In the example previously, weighta is 14. You know it's in stones because unita is "st". You can use strcmp to test that:
    Code:
    if ( strcmp ( unita, "st" ) == 0 ) {
      /* weighta is in stones, convert it to kilos */
    }
    else if ( strcmp ( unita, "lb" ) == 0 ) {
      /* weighta is in pounds, convert it to kilos */
    }
    else {
      /* You can probably assume that weighta is in kilos, no conversion necessary */
    }
    My best code is written with the delete key.

  11. #11
    Registered User
    Join Date
    Oct 2007
    Posts
    8
    Quote Originally Posted by Prelude View Post
    >But how do I know that 14 is in stones and not some other
    >weight format (ie. kg or lb), or 80 is in kg (not st or lb)?
    You know because you saved that information. In the example previously, weighta is 14. You know it's in stones because unita is "st". You can use strcmp to test that:
    Code:
    if ( strcmp ( unita, "st" ) == 0 ) {
      /* weighta is in stones, convert it to kilos */
    }
    else if ( strcmp ( unita, "lb" ) == 0 ) {
      /* weighta is in pounds, convert it to kilos */
    }
    else {
      /* You can probably assume that weighta is in kilos, no conversion necessary */
    }
    Ok, you're awesome! I'm gonna go and try to implement this, which may take a while but at least I know what to do now. Oh, do I declare next as a char, or an array of char (string)? Thanks for your help!

  12. #12
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Oh, do I declare next as a char, or an array of char (string)? Thanks for your help!
    strcspn returns a size_t, but you can declare next as an int if you don't know about size_t, and nextp as a pointer to char.
    My best code is written with the delete key.

  13. #13
    Registered User
    Join Date
    Oct 2007
    Posts
    8
    Well, almost... I'm not allowed to use strtol as it's not in string(3). Back to square 1, I suppose.

  14. #14
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >I'm not allowed to use strtol as it's not in string(3).
    Tell your teacher to come here and explain his reasoning for such an idiotic restriction. If you're going to give an assignment on parsing, you shouldn't restrict away all of the tools for doing it properly. I mean really, you're not going to learn anything useful if you have to skip every reasonable solution that would occur in the real world.

    >Back to square 1, I suppose.
    Not really. You can use strcat and strcspn to read the numbers as well, but you'll have to manually convert them to integer values because you can't use strtol or atoi.
    My best code is written with the delete key.

  15. #15
    Registered User
    Join Date
    Oct 2007
    Posts
    8
    Ye the prof. is insanely evil. If you think that's bad, you should see the amount of validation that has to be done on each line of input. There's 6 pages of specifications! I know the source code for atoi so I can manipulate that a little.

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
    
    	int next, i, weighta, weightb, days, nextp;
    	char line[80], user, c;
    	char *unita, *unitb;
    	
    	for(i = 1; (c = getchar()) != '\n'; i++)
    	{
    		line[i] = c;
    	}
    	line[0] = '\0';
    	line[i] = '\0';
    	
    	while (next != NULL)
    	{ 
    		next = strcspn ( line, " \t" );
    		strncat ( user, line, next );
    
    		weighta = strtol ( line + next, &nextp, 0 );
    		next = strcspn ( nextp, " \t" );
    
    		strncat ( unita, nextp, next );
    
    		weightb = strtol ( nextp + next, &nextp, 0 );
    		next = strcspn ( nextp, " \t" );
    
    		strncat ( unitb, nextp, next );
    
    		days = strtol ( nextp + next, &nextp, 0 );
    	}
    	printf("%d\n", weighta);
    
    	return 0;
    }
    That's what I came up with, it compiles, but there's a slew of warnings and it doesn't work as it should. It'll be a miracle if I survive this course. Any suggestions on why it's not working?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. type casting?
    By greatonesv in forum C Programming
    Replies: 12
    Last Post: 10-22-2008, 08:21 PM
  2. Using variables in system()
    By Afro in forum C Programming
    Replies: 8
    Last Post: 07-03-2007, 12:27 PM
  3. Replies: 2
    Last Post: 09-04-2001, 02:12 PM
  4. My program, anyhelp
    By @licomb in forum C Programming
    Replies: 14
    Last Post: 08-14-2001, 10:04 PM