Hello all,

I'm a beginner in C, and I face the following problem. I have multiple data files, where in each file, there are 3 lines that are the same for each file, and then the fourth line in each file have the work "result" and then a value. What I want to do is to read that value only from each file, store it to a variable for further processing.

So, how can I just read that specific value from each file? In other words, how can I skip reading the first 3 lines and the word "result" in the fourth line? or is there a way to read a value after a specific string, so that I can tell it to read what is after the word "result"?

Thanks.

Aly

Well, if you knew the exact length of the 3 lines to be ignored, and you knew that this length would never change, you could use a file seek command to take you straight to the point in the file that you are interested in. However, that's making assumptions about the content of the header and may be dangerous.

The safest way is to read from the start of the file and search for the 3 newline characters you are expecting. When you've got past those you can begin your processing of 'Result' lines.
Check out fscanf(), it can be useful for file access with simple formats.

i try to avoid fscanf() because this function requires the input to be very precisely defined, and will cause you much headaches if your input (i.e., the files) ever vary from what you expect them to contain

use instead "fgets" to read each line, and something like "strstr" or similar to parse the result

Read in the first three lines and throw them away. Using fscanf, you can read in doubles with %lf, floats with %f, and you can use %s to read in Strings. %s will get rid of the first word I believe (first thing matches by the delimiter pattern, which is usually whitespace). So you can use fscanf with that in mind to help you reach the part of the file you actually want.

Also, try this advice at your own risk, I haven't programmed in C in a while!

You can try using this to get a line from a file,
and strip leading and trailing blanks, CR's etc
and detect the EOF condition

RETURNS: TRUE if EOF or file error has occurred
FALSE if not EOF

Note:
typedef char * PSZ
#define MAX_LINE_LEN to whatever value you like

int GetLine(FILE *fpFile, PSZ pszLine)
  {
  int i, iLen;
  char szBuffer[MAX_LINE_LEN+1];

  if (!fgets(szBuffer, MAX_LINE_LEN+1, fpFile))
    {
    pszLine[0] = 0;
    return(TRUE);
    }
  /* check if we are at EOF */
  iLen = strlen(szBuffer);
  if (iLen == 0)
    return(TRUE);

  /* strip Leading blanks if any */
  i = 0;
  while (szBuffer[i] == ' ' && szBuffer[i] != 0)
    i++;
  strcpy(pszLine, &szBuffer[i]);

  /* strip CRLF and trailing blanks from end if there is any */
  i = strlen(pszLine) - 1;
  while (pszLine[i] == ' ' || pszLine[i] == 0x0A || pszLine[i] == 0x0D)
    i--;
  pszLine[++i] = 0;
  if (pszLine[0] == 0 )
    strcpy(pszLine, " ");
  return(FALSE);
  }
Comments
crappy code

damn, that's a confusing mess if i ever saw one. your naming conventions are unhelpful, to say the least. are you telling us that "int GetLine()" returns TRUE if failed? really?

and, anyhow, are TRUE and FALSE part of the standard C? would you like to explain where they are defined?

why do you post something that has obscure typedefs? whats the purpose of renaming "char *" anyhow?

what's the point of having MAX_LINE_LEN+1, since you don't ever use the unmodified MAX_LINE_LEN in the first place? this will break whenever you try to read the maximum length.

and WTF is the point of the second conditional in this??

while (szBuffer[i] == ' ' && szBuffer[i] != 0)

Finally, your example does nothing to help the poster to answer their question or understand the fundamental concepts.

if you're going to throw code at someone, at least make it concise, coherent, and relevant to the problem. Giving someone a length of rope to go hang themselves with is not "help"

The naming convention is hungarian notation
names are prefixed with their type

psz is pointer to string NULL terminated
sz is a string NULL terminated
These are both industry standard


TRUE and FALSE are defined in /usr/include/stdbool.h in the UNIX environment
I am new here and I am not sure of the strictness of adhering to ANSI standards
One can always just return 0 or 1 or define TRUE FALSE in their code if this wont
compile on their machine

Defining char * as PSZ simplifies reading of code for large projects.
As mentioned PSZ is commonly used to indicate to the programmer that
this is a null terminated string they are dealing with.

This code will not break when you try to read the maximum length.
Try it.

while (szBuffer == ' ' && szBuffer != 0) i++;
will increment i to the first non space character on the line.
Zeroes can be ignored when reading an int.

Having stripped the leading characters we can
strcpy(pszLine, &szBuffer);


Similarly, unwanted chars at the end of the line are stripped with
i = strlen(pszLine) - 1;
while (pszLine == ' ' || pszLine == 0x0A || pszLine == 0x0D)
i--;
pszLine[++i] = 0;


MAX_LINE_LEN + 1 allows us to store our PSZ. +1 is for the NULL terminator.

After invoking GetLine() 4 times, one can use atoi(pszLine) to get the value of the
4th line

I know that returning TRUE for failed is unconventional.
This is a valid point, but it is appropriate in the context
in which it is being used.

I assume that given a piece of code, people are of sufficient competance to
modify it as they will for their own purpose.
I did not join this web site to teach C to beginners.
I am hopintg to pick up some insights and tricks myself.

The naming convention is hungarian notation names are prefixed with their type

These are both industry standard

in your imagination, maybe. this is an antiquated notation developed by some guy at microsoft in the 70's. even it's proponents agree it's no longer popular, and it's critics are less kind:

Encoding the type of a function into the name (so-called "Hungarian Notation") is brain damaged - the compiler knows the types anyway and can check those, and it only confuses the programmer. No wonder Microsoft makes buggy programs.
-- Linus Torvalds
http://lxr.linux.no/linux/Documentation/CodingStyle


TRUE and FALSE are defined in /usr/include/stdbool.h in the UNIX environment

this is a new feature in C99 and is not industry standard. at the least you need to include stdbool.h. but the whole thing begs the question of how many assumptions you are making about the people who post questions on this website.

I am new here and I am not sure of the strictness of adhering to ANSI standards

since practically the entire industrialized world (except maybe India) adheres to ANSI standard I would say 100%

One can always just return 0 or 1 or define TRUE FALSE in their code if this wont compile on their machine

or you could just post compilable code.

Defining char * as PSZ simplifies reading of code

only if one is, as Linus Torvalds puts it, "brain-damaged"


while (szBuffer == ' ' && szBuffer != 0) i++;
will increment....

i know what you're trying to increment. my point is WTF does the second test in your conditional accomplish? When, exactly, will the first test pass and the second test fail? or vice versa.

this is a reason i'm saying your code is sloppy and unhelpful. you need to edit out all the B.S. before holding it up to beginners as some sort of "example".


MAX_LINE_LEN + 1 allows us to store our PSZ. +1 is for the NULL terminator.

yeah, i get what you're trying to do, but that won't help you much when you go and read MAX+1 characters from the input. once again, this is yet another reason why your code is only good as an example of what not to do.

I know that returning TRUE for failed is unconventional.

then why post unconventional code when helping beginners?


I assume that given a piece of code, people are of sufficient competance to modify it as they will for their own purpose. I did not join this web site to teach C to beginners.

then quit responding to beginners

Hello all,

I'm a beginner in C, and I face the following problem....

.

I see you have been reading Wikipedia.
Perhaps to check up on what Hungarian notation is.

There are proponents for it too, you might note
in the notable opinions section

actually i hadn't seen the wiki page. do you think the Linux Coding Style document is unheard of? .... but interesting though that you would point me to the wiki, which supports my point:

Steve McConnell ... the Hungarian naming convention is no longer in widespread use

Bjarne Stroustrup -- No I don't recommend 'Hungarian'.... [it] is completely unsuitable for a language that supports generic programming and object-oriented programming ... [it] simply complicates and minimizes abstraction

the one guy on there who attempts to support it, is merely quoted as describing what the creator of the hungarian notation was *trying* to accomplish.

ANYHOW...

take your obscure coding style to some hacker forum. don't confuse beginners with sloppy, broken code and outmoded coding practices that were discarded in the 1980s.

Well, that took me down a peg.

Perhaps you should change your moniker to Neptune
the C god

I work with programmers coding in several languages
and most use hungarian notation.
I will continue to post in it.
If you don't like it then I suggest that is your problem and you will
have to deal with it

here you go amegahed. i tried to be thorough and fault-tolerant, yet clear. see if it makes sense:

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

#define MAX_LINE_LEN    80

int parseResult(char * filename, unsigned lineNumber, double * result);


int main()
{
   double value;

   if (parseResult("myDataLog.txt", 4, &value))
      printf("found result = %3.2f\n", value);

   else
      printf("result not found\n");



   return 0;
}

////////////////////   parseResult   /////////////////////////
//
// reads file and looks for the string "result" on
// the specified line number and ignores previous lines.
// passes back result as double floating point value,
// or returns a zero if failed to find the "result" string
//
// input:  string : filename to open and read
//         unsigned int : line number where result is expected
//
// output: pointer to double : passes back value of 'result'
//
// return: int result 0 = fail, 1 = success
//
// notes:  if function fails, value pointed to by result
//         will not be modified.
//
// warns:  invalid characters (not including whitespace) located
//         between "resul7" and value will cause the function
//         to appear to pass, but pass back the value 0.00 as the
//         result.
//


int parseResult(char * filename, unsigned lineNumber, double * result)
{
   FILE   *filePtr;
   char   buffer[MAX_LINE_LEN], *buffPtr, lastChar;
   int    lineCount = 1;  // indexing first line as line #1

   filePtr = fopen(filename,"r");

   if (filePtr == NULL)
   {
      perror("parseResult");
      return 0;   // fail
   }

   // ASSUMPTION! will not look beyond specified lineNumber
   while (lineCount <= lineNumber)
   {
      buffer[0] = '\0';  // reset buffer
      fgets(buffer, MAX_LINE_LEN, filePtr);

      if (ferror(filePtr))
      {
         perror("parseResult");
         return 0;  // fail
      }

      if (lineCount < lineNumber)
      {
         //increment if last character is <CR> or <LF>
         lastChar = buffer[strlen(buffer) - 1];
         if (lastChar == '\x0D' || lastChar == '\x0A')
            lineCount++;

         //exit if End Of File <EOF>
         if (feof(filePtr))
         {
             printf("parseResult: unexpected end of file\n");
             return 0;  // fail
         }
      }

      else  // lineCount == lineNumber
      {
         // ASSUMPTION!  "result" is not capitalised"

         buffPtr = strstr(buffer,"result");
         if (buffPtr == NULL)
         {
            printf("parseResult: 'result' not found\n");
            return 0;
         }

         // ASSUMPTIONS!  the value always follows "result"
         // with no invalid characters between the string
         // "result" and the value,.  (whitespace.is okay).

         // skip to first character after "result"
         buffPtr += strlen("result");
         *result = atof(buffPtr);


         return 1; // success
      }

   }
   return 0;
}

.

This article has been dead for over six months. Start a new discussion instead.