OK..so here's the problem...

I'm supposed to create a program that reads a text file containing 5 lines, each composed of a name, a colon, and three integers. For example:

Bill Gates: 10 20 30
Shalla Booger: 80 70 84
Hagar Joe Plinty: 70 90 80
Darth Vader: 60 50 80
Mace Windu: 50 60 80

Now, what i'm supposed to do is take the average value of the three numbers for each name and then sort them so that the names are in ascending order based on the average. So far, I've only come up with this:

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

#define ROW			5
#define COLUMN		100
#define FILENAME	"file1.txt"

int main(void)
{
	FILE *fp1;
	char array[ROW][COLUMN], test_array[COLUMN], *ptr;
	int cnt = 0;
	
	fp1 = fopen(FILENAME, "r");  // open a file for reading

	while (fgets(array[cnt], COLUMN, fp1) != NULL)
	{
		strcpy(test_array, array[cnt]); // copy each string into an array
		printf("%s", test_array);
		ptr = test_array;
			while (*ptr != '\0')
			{
				if (isdigit(*ptr))
				// something goes here 	
				ptr++;
			}
		cnt++;
	}

	

	return 0;
}

Basically, I want to use fgets in a while loop to read in every line from the file and store each line in a 2-D array (dunno if strcpy should be there to place each line in a single dimension array for searching). Then, using some kind of search loop, extract each set of numbers, average them, and then put them into another array so that I can sort them later.

The difficult part that I've run into is extracting the numbers. I can't think of a way to get a 2 digit number from a string out.

Any help you guys can offer would be helpful.

Recommended Answers

All 10 Replies

Look at following code, ExtractNumbers has a out parameter that is int* ExtractedNumbers, this contains extracted numbers, and this function returns total number of numbers found in the string.
i have tryied to keep code as simple as possible(sorry for not documenting it, due to lack of time), if u feel problem in understanding it, let me knwow.

#include <math.h>
#include<iostream>
using namespace std ;
int ExtractNumbers(char *szString, int* ExtractedNumbers) ;
int _tmain(int argc, _TCHAR* argv[])
{
	int *Num = new int [100] ;
	char *szString = "Shalla Booger: 80 70 84";
	int iTotalNoOfIntegers=-1;
	iTotalNoOfIntegers = ExtractNumbers(szString,Num);
	for(int i=0; i<iTotalNoOfIntegers; ++i)
		cout<<*(Num+i)<<endl;
	return 0;
}

int ExtractNumbers(char *szString, int* ExtractedNumbers) 
{
	char *p = NULL;
	char *q = NULL;
	int iCount=-1;
	int iNum = 0;
	int i = 0;
	p=szString ;
	while(*p) {
		if(*p>='0' && *p<='9') {
			q=p;
			while(*q>='0' && *q<='9') {
				++iCount ;
				++q ;
			}
			q=p;
			while(*q>='0' && *q<='9') {
				iNum = iNum + (*q-48) * pow(10,iCount);
				--iCount;
				++q ;
				++p;
			}
			ExtractedNumbers[i] = iNum ;
			++i;
			iNum = 0 ;
		}
		else {
			++p ;
		}
	}
	return i;
}
Member Avatar for iamthwee

@ dubeyprateek

That's just wrong for reasons I have neither the time or inclination to explain.

@ iamthwee

>>That's just wrong for reasons I have neither the time or inclination to explain.

Ok, pointers are not deleted in the program, what else you find wrong?
It will be a great favor if u can state one or two, i have successfully compiled and running the code..

Member Avatar for iamthwee

>i have successfully compiled and running the code

So...

>Ok, pointers are not deleted in the program, what else you find wrong?

It's just plain wrong. Besides from the fact it's just a horrible hybrid mess of C and C++, it's also a piss poor way to convert a two digit char to an integer. Truth hurts kiddo, so skip along now, get out your favourite book on C or C++ and learn sumthing. That way we don't have to correct your silly mistakes. Tee he he.

ThanQ

That way we don't have to correct your silly mistakes.

dubeyprateek: Please don't consider iamthwee's style of response to be representative of anybody else's attitudes here.

Member Avatar for iamthwee

dubeyprateek: Please don't consider iamthwee's style of response to be representative of anybody else's attitudes here.

I sorrie, yes I am not like everyone else. :o
I hope I didn't scare you away dubeyprateek.

:cool:

>Any help you guys can offer would be helpful.
My first bit of help would be to tell you to use code tags, not inlinecode tags.

>sort them so that the names are in ascending order based on the average
"Them" being the 3 numbers for each name or the entire record? The actual sort can be done with qsort, but we'll put that on the backburner for now because you seem to have trouble with parsing the string.

>The difficult part that I've run into is extracting the numbers.
The first thing you need to do is find a semicolon. That's where the numbers begin. Then you can simply use sscanf to read them just as you would from the command prompt:

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

int main ( void )
{
  /* Assume we read a line with fgets */
  char line[] = "Bill Gates: 10 20 30\n";
  int nums[3];

  /* Separate the name and numbers */
  char *split = strchr ( line, ':' );

  if ( split != NULL ) {
    *split = '\0';

    /* Gather the numbers */
    if ( sscanf ( split + 1, "%d%d%d", &nums[0], &nums[1], &nums[2] ) == 3 ) {
       /* Find the average */
      int sum = 0, i;

      for ( i = 0; i < 3; i++ )
        sum += nums[i];

      printf ( "%s has an average of %d\n", line, sum / 3 );
    }
  }

  return 0;
}

>if u feel problem in understanding it, let me knwow
Not a problem in understanding it, but I do feel that your solution has much to be desired. The ExtractNumbers function could be simplified and improved, but there's little point in doing so because you're duplicating existing funtionality and complicating the code in the process.

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

#define ROW			5
#define COLUMN		100
#define FILENAME	"file1.txt"

char num_array[COLUMN];

int main(void)
{
	FILE *fp1;
	char array[ROW][COLUMN], test_array[COLUMN];
	char *s1, *s2, *ptr;
	int cnt = 0, size, avg[COLUMN], average, total = 0;
	
	fp1 = fopen(FILENAME, "r");
	fgets(array[0], COLUMN, fp1);
	ptr = array[0];

	while (*ptr != '\0')
	{
		if (isdigit(*ptr))
		{
			num_array[cnt] = *ptr;
			cnt++;
		}
		ptr++;
	}

	printf("%s\n", num_array);

	s1 = num_array;
	s2 = s1 + 1;

	for (cnt = 0; cnt < 3; cnt++)
	{
		test_array[0] = *s1;
		test_array[1] = *s2;

		avg[cnt] = atoi(test_array);
		
		s1 += 2;
		s2 += 2;

		total += avg[cnt];
		printf("%d", avg[cnt]);
	}

	average = total / 3;
	printf("\n%d\n", average);
	
	return 0;
}

Thanks for the help.

well i managed to come up with the junk code above yesterday (works for the first line in the text file) after hours of...nothing... and it seems to work. But i think i'm gonna look into these built-in functions you guys' mentioned. (as you can see i'm an extreme programming noob and my knowledge of the syntax is really limited :cry: )

Hehe i finally finished my program =)

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

#define ROW			5
#define COLUMN		100
#define FILENAME	"file1.txt"

void sort_avg(char **, int *);

int main(void)
{
	FILE *fp1;
	char array[ROW][COLUMN];
	char *split, *ptr[ROW];
	int nums[3], avgs[ROW];
	int sum = 0, i = 0, cnt = 0;	

	fp1 = fopen(FILENAME, "r");
	while (fgets(array[i], COLUMN, fp1) != NULL)
	{
		ptr[i] = array[i];
		split = strchr(array[i], ':');
		if (split != NULL)
		{
			*split = '\0';
			if (sscanf(split + 1, "%d%d%d", &nums[0], &nums[1], &nums[2]) == 3)
			{
				for (cnt = 0; cnt < 3; cnt++)
					sum += nums[cnt];
			}
		}
		avgs[i] = (sum / 3);
		sum = 0;
		i++;
	}
		
	sort_avg(ptr, avgs);
	return 0;
}

void sort_avg(char **strings, int *avg)
{
	int temp;
	int first, next, cnt;
	char *temps;
	
	for (first = 0; first < ROW - 1; first++)
	{
		for (next = first + 1; next < ROW; next++)
			if (avg[first] < avg[next])
			{
				temp = avg[first];
				avg[first] = avg[next];
				avg[next] = temp;
				
				temps = strings[first];
				strings[first] = strings[next];
				strings[next] = temps;
			}
	}	

	for (cnt = 0; cnt < ROW; cnt++)
	{
		printf("%s: %d\n", strings[cnt], avg[cnt]);
	}
}

Umm Narue I have a question..what does

*split = '\0'

mean in your code. And also

if (sscanf(split + 1, "%d%d%d", &nums[0], &nums[1], &nums[2]) == 3)

the split + 1 is to skip the space?

>what does
>*split = '\0'
>mean in your code.
'\0' is a sentinel at the end of every C-style string. What I did is a trick for splitting one string into two. If you have this:

"Bill Gates: 10 20 30\n"

And replace the semicolon with a null character, you get (within the same array) this:

"Bill Gates"
" 10 20 30\n"

If you won't need to use the name as a separate string, the split isn't necessary.

>the split + 1 is to skip the space?
split + 1 is to skill the null character. The %d format modifier for the scanf family will skip leading whitespace, but because '\0' isn't treated as whitespace, the sscanf call will fail unless you skip it.

Try playing around with my code and see what happens when you remove one or the other, or both. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.