Thread: I/O from .txt files.

  1. #1
    Registered User
    Join Date
    Jan 2013
    Posts
    15

    I/O from .txt files.

    Hi, I was wondering if it would be possible to get some help. I'm making a program for my chemistry course that requires a number of values to be read from a text file, a calculation done with those values, and the new numbers then printed onto the screen and saved into a file.

    So far I have the following code,
    Code:
    //A program that calculates the reduced mass of diatomic molecules.
    //The following libraries will be used.
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    using namespace std;
    
    int main()
    {
    int selection,b;//Defines the selection variable to determine the input.
    
    printf("A program that works out the reduced mass of diatomic molecules.\n\n");//Prints the introductory message.
    printf("Would you like to input the data from the keyboard or a .txt file?\n");//Allows the user to choose the input.
    printf("1. From a .txt file ");
    printf("2. From the keyboard\n");
    printf(":");
    scanf("%d",&selection);//Assigns the value of the selection int variable.
    
    FILE *FP;
    char a[100];
    printf("Please input a filename including the .txt extension:"); scanf("%s",a);
    FP = fopen(a,"r");
    
    if (FP==NULL)
    {
        printf("Error Reading File");
    }
    while (!feof(FP))
        {
            fgets(a,100,FP);
            printf("%s",a);
        }
        fclose(FP);
    
    return 0;
    }
    I tried making an integer variable b which was equal to a*2 however this didn't seem to work, and instead I got an error message.

    How can I perform a calculation on the numbers as they are read from the text file?

  2. #2
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    Let's start here:

    Code:
    while (!feof(FP))
    Don't do this. FAQ > Why it's bad to use feof() to control a loop - Cprogramming.com

    Code:
    fgets(a,100,FP);
    That gets one line, including the newline character. You need to parse what you get here with sscanf; how you do this will depend upon the format of the file.

    You also keep going blindly on in the case of failure here:

    Code:
    if (FP==NULL)
    {
        printf("Error Reading File");
    }
    while (!feof(FP))
    which will result in a crash if FP is actually NULL.

  3. #3
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    It may also improve understanding by renaming the following variables:

    a
    b

    What are the meanings of these? You are using `a' for two different purposes, the filename as well as a data buffer. Use two names for this.

    a --> char filename[100], buffer[100];
    b --> double result;

    If `result' is a double value (or int, or whatever you want), then just by considering the type difference, it is obvious that `buffer' cannot be multiplied by two nor can it be stored into `result' so you must convert it first. This is what rags_to_riches means by parsing.

  4. #4
    Registered User
    Join Date
    Jan 2013
    Posts
    15
    Thankyou very much both of you for the replies, I'll have a read through the linked tutorial and how parsing works. Sorry to ask such a simple question, but I'd literally spent a whole day on it and was getting no where and didn't know where to look.

  5. #5
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Exactly - the value read from the file is a sequence of characters, not a number. You can't multiply it by two any more than you can multiply a sentence by 2.

    sscanf is a good way to do the conversion. All it's doing is converting the string to something else, in the same way that scanf reads user input into variables.

    There's also an fscanf, which does the same thing from files. You could use fscanf directly, but I wouldn't recommend it -- , it can be pretty fiddly if unexpected input comes in (fscanf will not move the file pointer on unless it gets what it is trying to parse, so a simple while loop can easily get stuck in a tight infinite loop doing nothing). sscanf is similar in that it can fail to parse anything, but you have a lot more control with a string that you've already read than you do with a file pointer.

    Another option is to use the conversion functions in stdlib.h (<cstdlib> (stdlib.h) - C++ Reference) that convert from strings to various number types. The at* functions (e.g. atoi) are flawed - they return 0 on failure, indistinguishably from returning 0 having successfully converted the string "0". The strto* functions are fine though -- they adjust a pointer to show how much of the string they parsed, so you can tell if an error occured.

    If you're convinced there'll be no errors at all in the input data, you could use atoi and friends, but it's probably not a good habit to make.

  6. #6
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Quote Originally Posted by smokeyangel View Post
    Exactly - the value read from the file is a sequence of characters, not a number. You can't multiply it by two any more than you can multiply a sentence by 2.
    Well, this depends on the language. See Python for an example where this is well-defined. "Hello, world." * 2 is the same as "Hello, world.Hello, world."

    Quote Originally Posted by smokeyangel View Post
    sscanf is a good way to do the conversion.
    Yes, you can also check the return value to see whether conversion was successful. The return value is the number of items successfully converted.

    Code:
     if (scanf("%d", &myNumber) == 1)
       printf("Got an integer: %d\n", x);
    else
       printf("What? Couldn't find an integer there.\n");
    fscanf(stdin, ...) is the same as scanf(...)
    sscanf(buf, ...) is the same as scanf, except it reads from the character array pointed to by buf rather than stdin.
    Last edited by c99tutorial; 01-12-2013 at 04:27 AM.

  7. #7
    Registered User
    Join Date
    Jan 2013
    Posts
    15
    Quote Originally Posted by c99tutorial View Post
    It may also improve understanding by renaming the following variables:

    a
    b

    What are the meanings of these? You are using `a' for two different purposes, the filename as well as a data buffer. Use two names for this.

    a --> char filename[100], buffer[100];
    b --> double result;

    If `result' is a double value (or int, or whatever you want), then just by considering the type difference, it is obvious that `buffer' cannot be multiplied by two nor can it be stored into `result' so you must convert it first. This is what rags_to_riches means by parsing.
    Hi, I'm going to sounds really stupid but I've just had a read of the C File I/O tutorial on here, and I'm still not really understanding. What is the difference between the filename and the data buffer?

  8. #8
    Registered User
    Join Date
    Jan 2013
    Posts
    15
    Quote Originally Posted by Alex Saunders View Post
    Hi, I'm going to sounds really stupid but I've just had a read of the C File I/O tutorial on here, and I'm still not really understanding. What is the difference between the filename and the data buffer?
    Never mind, I've figured that out.
    Thanks

  9. #9
    Registered User
    Join Date
    Jan 2013
    Posts
    15
    This is what I've got so far, after having a mess around with it. No loop as of yet, but I will try to implement that later. I'm now having the problem that the string doesn't seem to print after obtaining it from the text file. The number int number does work, it's just char element_name[14] is displayed as an @ symbol on the screen rather than the text in the document. Any ideas?

    This is essentially what the text file says.
    100,Helium
    200,Hydrogen
    300,Nitrogen
    400,Oxygen
    500,Fluroine
    abc,Sodium
    def,Sulphur
    ghi,potassium
    jkl,nadonado
    Code:
    //A program that calculates the reduced mass of diatomic molecules.
    //The following libraries will be used.
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    using namespace std;
    
    int main()
    {
    int selection;//Defines the selection variable to determine the input.
    
    printf("A program that works out the reduced mass of diatomic molecules.\n\n");//Prints the introductory message.
    printf("Would you like to input the data from the keyboard or a .txt file?\n");//Allows the user to choose the input.
    printf("1. From a .txt file ");
    printf("2. Fromc the keyboard\n");
    printf(":");
    scanf("%d",&selection);//Assigns the value of the selection int variable.
    
    FILE *FP;
    int number;
    char element_name[14];
    char filename[100];
    
    do{
        printf("Please input a filename including the .txt extension:"); scanf("%s",filename);
        FP = fopen(filename,"r");
        if (FP==NULL){printf("\nError Reading File\n");}
    }while (FP==NULL);
    
    
    
    fscanf(FP, "%d[^,],%13\n", &number,&element_name);
    printf("%d %s",number,element_name);
    
    fclose(FP);
    
    return 0;
    }

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Isn't the program going to be wrecked when the number first lines end, and the letter first lines begin, "abc,sodium", etc?

    I'd prefer you used fgets() to bring the entire line into a char array of 100 elements or so, and THEN pick out the right way to sscanf() the parts from there - it makes setting it up a lot easier than working with a file, directly.

    If the first char is a letter, instead of a number, you use a different sscanf() to get it, if it IS a digit (0-9), then you get it the same way you are getting it now. Either way, I'll show you how to get the last part of that line.

    Do you have restrictions on what C functions you can use for this assignment?

  11. #11
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Quote Originally Posted by Alex Saunders View Post
    No loop as of yet, but I will try to implement that later.

    Code:
    using namespace std;
    What is the purpose of this line?


    Code:
    fscanf(FP, "%d[^,],%13\n", &number,&element_name);
    The format is not correct. Try the following instead

    Code:
    fscanf(FP, "%d,%13s\n", &number, element_name);

  12. #12
    Registered User
    Join Date
    Jan 2013
    Posts
    15
    Quote Originally Posted by Adak View Post
    Isn't the program going to be wrecked when the number first lines end, and the letter first lines begin, "abc,sodium", etc?

    I'd prefer you used fgets() to bring the entire line into a char array of 100 elements or so, and THEN pick out the right way to sscanf() the parts from there - it makes setting it up a lot easier than working with a file, directly.

    If the first char is a letter, instead of a number, you use a different sscanf() to get it, if it IS a digit (0-9), then you get it the same way you are getting it now. Either way, I'll show you how to get the last part of that line.

    Do you have restrictions on what C functions you can use for this assignment?
    We haven't been given any no.

  13. #13
    Registered User
    Join Date
    Jan 2013
    Posts
    15
    Quote Originally Posted by c99tutorial View Post
    What is the purpose of this line?
    For some reason our teacher was using a C++ compiler, but teaching us C commands from stdio.h.
    The teacher didn't mind if we used C++ or C as long as it ran in the compiler, and I think I used some C++ code in a previous program and forgot to delete it when I was being lazy and just copied the libraries to the coding for this program.

  14. #14
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    It gets a bit difficult, because it doesn't have a consistent
    number,letter

    format.

    This assumes you set up the char buffer[100], s1[100], and s2[100],
    as well as int num, and include <string.h> as well.

    Code:
       while(fgets(buff, sizeof(buff), fp)) {
          len=strlen(buff);
          if(buff[len-1]=='\n') //fgets adds a newline to the end of buff
             buff[len-1]='\0';   //which is removed, here
          printf("%s  ",buff);
          if(buff[0] >'0' && buff[0]<'9') {   //it is a digit first line of the file
             sscanf(buff, "%d,%s",&num,s1);
             printf("num: %d,  s1: %s\n",num,s1);
          }else {
             sscanf(buff, "%[^,],%s",s1,s2);   //the line has two strings
             printf("s1: %s, s2: %s\n",s1,s2); //and no numbers
          }
          printf("\n");
       }

  15. #15
    Registered User
    Join Date
    Jan 2013
    Posts
    15
    Thankyou very much for the help everyone. Problem is now solved.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 11-30-2012, 03:25 PM
  2. binary files: copying jpeg or video files
    By cfanatic in forum C Programming
    Replies: 5
    Last Post: 07-19-2012, 08:17 AM
  3. Multiple Source Files, make files, scope, include
    By thetinman in forum C++ Programming
    Replies: 13
    Last Post: 11-05-2008, 11:37 PM
  4. Packed Files (Puting multiple files in one file)
    By MrKnights in forum C++ Programming
    Replies: 17
    Last Post: 07-22-2007, 04:21 PM
  5. Linking header files, Source files and main program(Accel. C++)
    By Daniel Primed in forum C++ Programming
    Replies: 3
    Last Post: 01-17-2006, 11:46 AM