Click here to Skip to main content
15,912,897 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Ive written two functions that read lines from a .txt document with posts like the one below. "Number of loans" is only written once.

C++
Number of loans: 1
Loan number:      1
	Sum:          200.000000
	year:         2011
	Interest:     20.000000
	Installment:  1000.000000
	Payed off:    2012
	Description:  12  


What the program reads:
Loan number:      1
	Sum:          200.000000
	year:         2011000000
	Interest:     20.000000
	Installment:  1000.000000
	Payed off:    
	Description:  12  


'Payed off' doesnt work because it's calculated based on the 'year' value

The code i have written is:

C++
void readFile( int * nLoans, loan ** memory, FILE * streamPointer ){
    int i, k, d;
    char buf[MAXLINELENGTH+1];

    *nLoans = readLine( STARTNUMBEROFLOANES, MAXLINELENGTH, streamPointer );
    (*memory) = calloc(*nLoans, sizeof(loan));

    for( i = 0; i < *nLoans; i++ ){
	// loanID
		(*memory)[i].loanID = (int)readLine( STARTLOANID, MAXLINELENGTH, streamPointer );
	// values
        (*memory)[i].sum = readLine( STARTOFVALUES, MAXLINELENGTH, streamPointer );
        (*memory)[i].year = (int)readLine( STARTOFVALUES, MAXLINELENGTH, streamPointer );
        (*memory)[i].interest = readLine( STARTOFVALUES, MAXLINELENGTH, streamPointer );
        (*memory)[i].installment =  readLine( STARTOFVALUES, MAXLINELENGTH, streamPointer );
	// yearPayedOff
        fgets( buf, MAXLINELENGTH, streamPointer);
        d = strlen(buf);
        for( k = 0; k < (d - 1 - STARTOFVALUES ); k++ ){
            ((*memory)[i].yearPayedOff)[k] = buf[k + STARTOFVALUES];
        }
        ((*memory)[i].yearPayedOff)[d] = '\0';
	// description
        fgets( buf, MAXLINELENGTH, streamPointer );
        d = strlen(buf);
        for( k = 0; k < (d - STARTOFVALUES - 1) ; k++ ){
            ((*memory)[i].description)[k] = buf[k+ STARTOFVALUES ];
        }
        ((*memory)[i].description)[d] = '\0';
     // just to loose a line
        fgets( buf, 2, streamPointer );
    }
}


and:
C++
double readLine( int indexFirstNumber, int alowedLineLength, FILE * streamPointer ){
    char line[alowedLineLength + 1], numberString[ (int)log(MAXALOWEDLOANSUM) ];
    double returnNumber = 0;
    int i = indexFirstNumber;

    fgets( line, (alowedLineLength+1), streamPointer );
printf("\n%s", line);
    while( line[i] != '\n' && line[i] != ' ' && line[i] != '\0'){
        numberString[i-indexFirstNumber] = line[i];
        i++;
    }
    numberString[i] = '\0';
printf("\n%s", numberString);
	if( !(sscanf(numberString, "%lf", &returnNumber) == 1) ){ printf("\nError reading from file\n"); }
    return returnNumber;
}


The error, that the program adds lots of zeros to the value in the file, occurs between the two printf() statements in readLine()
Posted
Updated 2-Jan-12 13:53pm
v2
Comments
Richard MacCutchan 2-Jan-12 12:02pm    
Well you may like to tell us what the error is.
elroi92 2-Jan-12 19:49pm    
If I didnt make it clear the error is that the program adds a lot of zeros to the value read from the document.

This all assumes that the line ("Payed Out") is padded with enough blanks to get you to the column where the number *would have been*. If the line is truncated to be just long enouh to contain "Payed Out", then your index "i" is pointing to garbage (aka, unitialized crap).

PS, would it just be easier to use _atoi() on line[i] and be done with all that character fondling?
 
Share this answer
 
Comments
elroi92 2-Jan-12 19:51pm    
would atoi() line[i] on start with the char on the position line[i] and go to the right untill it finds '\0' ?
If the program was able to read the 'year' value it would always print something to 'payed off'.
Chuck O'Toole 2-Jan-12 20:11pm    
it would keep moving right until it hit a character that was "not a number". '\0' is "not a number". Also, I noticed you return a double so _atof() is more appropriate than _atoi(). Sorry for missing that.
Hello elroi92,

your readLine function is vulnerable on several aspects.
Since you do not check the lable of the lines, I would would not rely on any text position, but rather search for the ':' and then scan from there, e.g. (not compiled nor tested):

C
double readLine(FILE *fp)
{
   char line[MAXLINELEN];
   if (fgets(line, MAXLINELEN, fp))
   {
      line[MAXLINELEN-1] = '\0';
      const char *sep = ":";
      char *pos;
      if (strtok_r(line, sep, &pos))
      {
         char *val = strtok_r(line, sep, &pos);
         if (val)
         {
            double d;
            if (sscanf("%lf", val, &d) == 1) return d;
         }
      }
   }
   return 0.0;
}


Does that solve your problem?

Cheers

Andi
 
Share this answer
 
Comments
elroi92 2-Jan-12 19:50pm    
I do see how your code would be better with the strtok_r() function.

But i cant compile it, i have '#include <string.h>' but the compiler says "undefined reference to 'strtok_r'. I use codeblocks 10.05 .
Andreas Gieriet 3-Jan-12 3:39am    
Codeblocks is just an IDE. The relevant information is, what compiler and what (cross platform?) libraries do you use.
I assume from your statement that you have added #include <string.h>.
If your target platform libc does not provide a strtok_r function, you can easily implement a simplified version for your needs:
double readLine(FILE *fp)
{
char line[MAXLINELEN];
if (fgets(line, MAXLINELEN, fp))
{
line[MAXLINELEN-1] = '\0';
char *c = line;
while(*c && (*c!=':')) c++;
if (*c) c++;
if (*c)
{
double d;
if (sscanf("%lf", c, &d) == 1) return d;
}
}
return 0.0;
}
elroi92 3-Jan-12 7:50am    
yes, i must have erased <pre><string.h></pre> form the commment somehow

Isnt char *c a whole line? Shouldnt it be something like

<pre lang="c++">while(*c && (c[someIndexNuimber] !=':')) someIndexNumber++;</pre>
Andreas Gieriet 3-Jan-12 8:20am    
The c-pointer sweeps over the line (see the while loop with the c++ statement which increments the address by one, pointing to the next character of the line buffer).

I prefer to increment the pointer (c++) over indexed access.*c de-references the c-pointer, resulting in the value that c points to.
Thanks to a guy called r.stiltskin at dreamincode.

There are two main problems with the code as posted in the question.

1: the '\0' is added at the wrong place
numberString[i] = '\0';

it should be:
numberString[i - indexFirstNumber] = '\0';


2: numberString should be:
numberString[ (int)log10(MAXALOWEDLOANSUM) + 8]

and not:
numberString[ (int)log(MAXALOWEDLOANSUM) ]

Because the math.h function log is actually ln, and if MAXALOWEDLOANSUM equals something like 1 000 000 it still would only return 6, with no room for decimals or the decimal sign.

I guess the functionality could be improved with one of the tecniques described in this thread.
 
Share this answer
 
Comments
Richard MacCutchan 3-Jan-12 9:04am    
I agree, especially lines like

for( k = 0; k < (d - STARTOFVALUES - 1) ; k++ ){
((*memory)[i].description)[k] = buf[k+ STARTOFVALUES ];
}

You may understand what it means now but I would hate to have the job of maintaining this. You should learn and use proper pointers (and common functions) to access the data that you are trying to process.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900