Thread: Getting variables and numbers from a text file.

  1. #16
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    You can use ,say hash table if you need to keep the names.
    Code:
    typedef struct var_t {
      char *name;
      float  value;
    } var_t;
    dict = new_hash_table( );
    var_t *var;
    tokens = parse(line);
    var = lookup( dict, tokens[0] ) ;
    if( var == NULL) {      // not found insert it
         var = insert(dict, tokens[0] , 0.0 );      
    } 
    var->value = atof( tokens[1] );
    Then you could also have:

    sparlength:4:m
    sparxsection:0.2:m2
    panellength:sparlength:m
    windowlength:windowxsection:m /* ??? */
    windowxsection:0.05:m2

  2. #17
    ... kermit's Avatar
    Join Date
    Jan 2003
    Posts
    1,534
    Code:
    char arra[128][128];
     char line[128];  /* max. line size */
     char filename;
     char return_val;
     char ch;
    
     printf("Type in the name and extension of the model file e.g. data.txt\n");
     scanf("%s",&filename);
    
     printf("Filename is %s\n",&filename);
    
     fs=fopen(&filename,"r");  /* Opens file for reading text */
     ft=fopen("deposit.c","w");
    
     for (i=0; i<128; i++)
     for (j=0; j<128; j++)
     arra[i][j]= '\0';
    
     for (i=0; i<128; i++)
      line[i] = '\0';
    As an aside from your questions, there are different ways to get those arrays zeroed out, but since all of the elements are the same (0), why not consider forgoing the loops altogether? Consider:

    Code:
    char arr[10] = {0, 1, 2, /*0, 0, 0,....*/
    With the above bit of code, we see that if you specify some of the array elements, but not all of them, the rest (i.e, the ones not explicitly initialized) will be set to 0. Therefore:

    Code:
    char arr[10] = {'\0'}; /* All elements of arr set to zero */
    But what about your two dimensional array?

    Code:
    char arr[2][3] = {
            {'\0'}
        };

  3. #18
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    Kermit - I'll definitely change that. I'll have a look over the weekend (different tasks to do first) and post my completed code in case anyone is having the same issues. Thanks everyone, you've been really helpful!

  4. #19
    ... kermit's Avatar
    Join Date
    Jan 2003
    Posts
    1,534
    I got to thinking about my previous post, and I think I should mention that 0 is not the same as '\0'. If you were counting on the '\0' without having to explicitly add it yourself, (and were, for example, going to use one of the string functions on the array later) then you would be in for a nasty surprise. In that case, I would suggest something like this:

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
    
        enum {
            ROWS = 2,
            COLS = 3
        };
    
        char arr[ROWS][COLS];
        int i, j;
    
        memset(arr, 'f', sizeof(arr));
    
        for (i = 0; i < ROWS; ++i) {
            for (j = 0; j < COLS; ++j) {
                printf("arr[%d][%d] = %c\n", i, j, arr[i][j]);
            }
        }
    
        return 0;
    }
    A couple of things to mention: First, I used the 'f' there, just for demonstration purposes. '\0' does not show up as much in the print out (but you can easily replace 'f' with '\0'). Also, this will not work properly with a pointer to an array, for example, if you are doing it in a different function, because doing sizeof(arr) will actually just be the size of a pointer on your machine. In the case of doing this operation in a function, you will need to pass in some sizes to the function, or in any case do something more explicit like this:

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
    
        enum {
            ROWS = 2,
            COLS = 3
        };
    
        char arr[ROWS][COLS];
        int i, j;
    
        memset(arr, 'd', ROWS * COLS * sizeof(char));   /* sizeof(char) is not technically necessary
                                                           in this case, as it will always be 1. */
    
        for (i = 0; i < ROWS; ++i) {
            for (j = 0; j < COLS; ++j) {
                printf("arr[%d][%d] = %c\n", i, j, arr[i][j]);
            }
        }
    
        return 0;
    }
    Note my comment about sizeof(char). If your array was holding arrays of ints, then you absolutely would need to do sizeof(int).

  5. #20
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by kermit
    I got to thinking about my previous post, and I think I should mention that 0 is not the same as '\0'. If you were counting on the '\0' without having to explicitly add it yourself, (and were, for example, going to use one of the string functions on the array later) then you would be in for a nasty surprise.
    0 and '\0' have the same value and type, so I think that one can consider them the same. A null character is defined as a byte with all bits set to 0. For unsigned, one's complement, two's complement, and sign and magnitude representations, zero is represented by all bits set to 0 (other than negative zero, but the initialisation that will happen here is explicitly defined to be with unsigned or positive zero).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #21
    ... kermit's Avatar
    Join Date
    Jan 2003
    Posts
    1,534
    I stand corrected. :P

    Edit:

    This matter got me to thinking, and so I started to experiment a little. I am not disagreeing with what laserlight wrote above. I wanted to think these things through, as I was obviously a little fuzzy in my understanding. These are some of the results of what I was doing - I post them for anyone who might be interested in the future. Consider:

    Code:
    #include <stdio.h>
    
    int main(void)
    {
        printf("0 and '\\0' are %s!\n",
               0 == '\0' ? "the same" : "not the same");
    
        return 0;
    }
    
    My output:
    
    0 and '\0' are the same!
    Then I tried this experiment:
    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
            char arr1[10] = {'J','o','e','0'};
            char arr2[10] = {'B','o','b','\0'};
    
            puts(arr1);
            puts(arr2);
    
            printf("Length of arr1: %zu\n", strlen(arr1));
            printf("Length of arr2: %zu\n", strlen(arr2));
    
            return 0;
    }
    
    
    My output:
    
    Joe0
    Bob
    Length of arr1: 4
    Length of arr2: 3
    Note that the '0' in arr1 does not terminate the string. You can see this in the string that is printed out, "Joe0", as well as by the fact that strlen(arr1) returns 4, and not 3. The reason the string terminates normally is that the remaining elements, 4-9, are filled with nul characters as explained in my second last post.

    You can see what happens without this automatic process in the following code:

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char arr1[10];
        char arr2[10];
    
        arr1[0] = 'J';
        arr1[1] = 'o';
        arr1[2] = 'e';
        arr1[3] = '0';
    
        arr2[0] = 'B';
        arr2[1] = 'o';
        arr2[2] = 'b';
        arr2[3] = '\0';
    
        puts(arr1);
        puts(arr2);
    
        printf("Length of arr1: %zu (Has 3 characters)\n", strlen(arr1));
        printf("Length of arr2: %zu (Has 3 characters)\n", strlen(arr2));
    
        return 0;
    }
    
    My output:
    
    Joe0�
    Bob
    Length of arr1: 6 (Has 3 characters)
    Length of arr2: 3 (Has 3 characters)
    By not initializing arr1 to anything, its elements initially contain junk values. By not explicitly terminating the end of the array with a nul character, it is not actually a string, but an array of chars. Thus, handing it to functions which expect a string (i.e., and array of chars terminated by a nul character) causes problems.

    Finally, if I make one little change to the initialization of the array arr1, we get the proper results:

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char arr1[10];
        char arr2[10];
    
        arr1[0] = 'J';
        arr1[1] = 'o';
        arr1[2] = 'e';
        arr1[3] = 0;
    
        arr2[0] = 'B';
        arr2[1] = 'o';
        arr2[2] = 'b';
        arr2[3] = '\0';
    
        puts(arr1);
        puts(arr2);
    
        printf("Length of arr1: %zu (Has 3 characters)\n", strlen(arr1));
        printf("Length of arr2: %zu (Has 3 characters)\n", strlen(arr2));
    
        return 0;
    }
    
    My output:
    
    Joe
    Bob
    Length of arr1: 3 (Has 3 characters)
    Length of arr2: 3 (Has 3 characters)
    Last edited by kermit; 07-07-2010 at 01:49 PM.

  7. #22
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    Hi everyone, thanks for the help.

    I have tokenized the data file for colon and '\n' delimeters and now have an output of a list of tokens in the form:

    Token is: sparlength
    Token is: 4
    Token is: m
    Token is: sparxsection
    Token is: 0.2
    Token is: m2
    ...

    but for the life of me can't figure out how to input the tokens into a structure or even a string. I've spent the whole afternoon on this and there's a lot of info about getting tokens to display but nothing (that I can find!) on how to use them once you have them!

    So my question is, how would I 'store the values in the structure' as jimblumberg suggested at the bottom of the first page? Is there any way of creating a token array, so I could call on token[1], token [2] etc. and store multiples of three for example in respective parts of the structure? Seems much easier said than done, but I'm probably missing something. The relevant bit of code is:

    Code:
    /* Tokenise by line then by colon */
    
          char delims[] = "\n"":";  /* endline and colon delimiter */
          char *token=NULL;
          token = strtok(data,delims);
    
    	while (token !=NULL)
    
    	  {
    	    printf("Token is:  %s\n", token);
    	    token=strtok(NULL,delims);
    	   
    	  }
    I've tried sprintf and strcopy after before the printf but think due to the loop it's not liking it.

    I've changed my method of clearing memory, thanks for the advice on that

    Thank you all once again for the help.
    Last edited by snoikey; 07-08-2010 at 09:40 AM.

  8. #23
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    I figured it out yay!

    For completeness and to help anyone with the same problem in future my code is:

    Code:
    /* Prints all components of a colon delimited file, first into lines then into structures for the words on each line */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    main ()
    
    {
     FILE *fs;
     char filename,*data;
     long fsize;  /* size of file */
     char* sptr;
     int i,j;
     int ch=0;
    int lineno=0;
     char line[128]={'\0'};
     char arra[128][128]={{'\0'}};
    
     /* Get file */
     printf("Type in the name and extension of the model file e.g. data.txt\n");
     scanf("%s",&filename);
     printf("Filename is %s\n",&filename);
     fs=fopen(&filename,"r"); 
    
    if (fs == NULL)
      { printf("Could not open file.\n");
          } 
    
     else
       {   
    
    /* Count number of lines and length of file */
      
         while ((ch = fgetc(fs)) != EOF)
    	{
    		if (ch == '\n')
    			++lineno;
    	}
    
    	printf("Number of lines is %d\n", lineno+1);
    
     fseek(fs, 0, SEEK_END);
     fsize = ftell(fs);
     fseek(fs, 0, SEEK_SET);
    
     printf("File size is %ld characters including end of line characters\n",fsize);
    
      
    /**********************************************************
    
      Allocate memory for file - probably not needed!
    
      char *data =(char *)calloc(fsize,sizeof(char)); 
     
          fread(data,fsize,sizeof(char),fs);
    
          if (data==NULL)     
          {printf("Could not copy into memory");}
          
          else
          {
     
          printf("Memory was allocated and file was copied into memory.\n\n");
          printf("File is:\n%s\n",data); 
    
     ***********************************************************/  
    
     /* Split into separate lines  */
    
       i=0;
     while(fgets(line,sizeof line,fs) !=NULL)
       {
    strcpy (arra[i],line);
    
    /*********************************************************
    
     Code for checking:  prints out lines
    
     printf("Line number %d:  %s\n",i+1,arra[i]);
    
    **********************************************************/
    
     i++;
      }
    
     /* Tokenise by colon delimiter and put into structure */
    
    struct part
    {
      char name[51];
      char value[5];
      char unit[5];
    } partlist[3000];  /* array of structures to store all line's worth of parts: */
       
     char delims[] = ":";  /* delimiter within line */
    
     i=0;
           while (i<=lineno)
          
    	 {
    strcpy(partlist[i+1].name, strtok(arra[i],delims));
    strcpy(partlist[i+1].value, strtok(NULL,delims));
    strcpy(partlist[i+1].unit, strtok(NULL,delims));
    
     i++;
             }
    
           for (i=1; i<=(lineno+1);)
           {
      printf("Struct %d Name: %s\n", i, partlist[i].name);
      printf("Struct %d Value: %s\n", i, partlist[i].value);
      printf("Struct %d Unit: %s\n", i, partlist[i].unit);
      
    i++;
           }
           
      fclose(fs);
    
     /* keep if calloc is kept */
     /* free(data);  */
       }
     
    
          return(0);
    }
    Which can be tested with an example data file of:
    Code:
    sparlength:4:m
    sparxsection:0.2:m2
    panellength:2:m
    panelxsection:0.03:m2
    windowlength:0.5:m
    windowxsection:0.05:m2
    enginemass:65:kg

    Thanks everyone for your help, I'm glad my first week of C ended so well.

  9. #24
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    Completed, better version which sums parts of a struct.

    Code:
    /* Calculates total mass of an aircraft based on the sum of all of its parts by printing
     all lines of a file data.txt into a structure. */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    main ()
    
    {
     FILE *fs;
     char filename,*data;
     long fsize;  /* size of file */
     char* sptr;
     int i,j;
     int ch=0;
     int lineno=0;
     char line[128]={'\0'};
     char arra[128][128]={{'\0'}};
     double totalmass=0;
    
     /* Get file */
     printf("Type in the name and extension of the model file e.g. data.txt\n");
     scanf("%s",&filename);
     printf("Filename is %s\n",&filename);
     fs=fopen(&filename,"r");
    
    if (fs == NULL)
      { printf("Could not open file.\n");
          }
    
     else
       {  
    
    /* Count number of lines and length of file */
     
         while ((ch = fgetc(fs)) != EOF)
            {
                    if (ch == '\n')
                            ++lineno;
            }
    
            printf("Number of lines is %d\n", lineno+1);
    
     fseek(fs, 0, SEEK_END);
     fsize = ftell(fs);
    fseek(fs, 0, SEEK_SET); /* Puts pointer to beginning of filespace */
    
     printf("File size is %ld characters including end of line characters\n\n",fsize);
    
     
     /* Split into separate lines  */
    
       i=0;
     while(fgets(line,sizeof line,fs) !=NULL)
       {
    strcpy (arra[i],line);
    
    i++;
      }
    
     /* Tokenise by colon delimiter and put into structure */
    
    struct part
    {
      char name[51];
      char value[10];
      char unit[12];
    } partlist[lineno+1];  /* array of structures to store all line's worth of parts: */
      
     char delims[] = ":"";";  /* delimiter within line */
    
     i=0;
    
     while (i<=lineno)
         
             {
    strcpy(partlist[i+1].name, strtok(arra[i],delims));
    strcpy(partlist[i+1].value, strtok(NULL,delims));  /* Copies value as a string of text */
    strcpy(partlist[i+1].unit, strtok(NULL,delims));
    
    
     i++;
             }
     /* Comment the following 'for' loop out if you do not wish the file to be displayed (will speed up computation) */    
      
     for (i=1; i<=(lineno+1);)
           {
      printf("Component %d:  Name: %s\n", i, partlist[i].name);
      printf("              Value: %f\n",atof(partlist[i].value));  /* Converts char 'number' to double number */
      printf("              Unit: %s\n", partlist[i].unit);
      i++;
           }
    
     /* Find sum of all values */
    
    for (i=1; i<=(lineno+1);)
    	    {
    	      totalmass=totalmass+atof(partlist[i].value);
    	    i++;
    	    }
    
     printf("\nTotal mass is %fkg\n", totalmass);
          
      fclose(fs);
    
       }
     
    
          return(0);
    }

  10. #25
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Wow, all that covered in only a week? I'm impressed! Congrats!

  11. #26
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Code:
     char filename;
     ...
     printf("Type in the name and extension of the model file e.g. data.txt\n");
     scanf("%s",&filename);
     printf("Filename is %s\n",&filename);
     fs=fopen(&filename,"r");
    You've no problem running your program???

  12. #27
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    You should get used to the idea that C arrays start at 0 and not try to force them to start from 1.

    In the following code
    Code:
    while (i<=lineno)
         
             {
    strcpy(partlist[i+1].name, strtok(arra[i],delims));
    strcpy(partlist[i+1].value, strtok(NULL,delims));  /* Copies value as a string of text */
    strcpy(partlist[i+1].unit, strtok(NULL,delims));
    
    
     i++;
             }
    I would change the while loop to a for loop
    Code:
    for(i=0; i < lineno;++i)
    {
       strcpy(partlist[i].name, strtok(arra[i],delims));
       strcpy(partlist[i].value, strtok(NULL,delims));  /* Copies value as a string of text */
       strcpy(partlist[i].unit, strtok(NULL,delims));
    }
    and for
    Code:
    /* Comment the following 'for' loop out if you do not wish the file to be displayed (will speed up computation) */    
      
     for (i=1; i<=(lineno+1);)
           {
      printf("Component %d:  Name: %s\n", i, partlist[i].name);
      printf("              Value: %f\n",atof(partlist[i].value));  /* Converts char 'number' to double number */
      printf("              Unit: %s\n", partlist[i].unit);
      i++;
           }
    I would change to:

    Code:
    /* Comment the following 'for' loop out if you do not wish the file to be displayed (will speed up computation) */    
      
    for (i=1; i< lineno; ++i)
    {
       printf("Component %d:  Name: %s\n", i+1, partlist[i].name);
       printf("              Value: %f\n",atof(partlist[i].value));  /* Converts char 'number' to double number */
       printf("              Unit: %s\n", partlist[i].unit);
    }
    There are other places in your code that I would handle the same way.

    Also your total mass calculation is incorrect for the data shown. You are adding different UNITS together. (ie: m and kg) You must first convert all the different mass values to a common type.

    Jim

  13. #28
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    @Adak - thanks that's why I thought I was so screwed to start with haha. I'm enjoying C a lot more now.

    @Bayint - program works fine, I tried it initially without the &s and with various combinations of &s and it didn't like it. From what I've seen on the internet it probably should have worked but oh well!

    @Jim - thank you for that, I'll change those loops and check for other places I've done the same thing. I'm used to Matlab which starts at 1 and it does seem a little odd, but you're right, I should get used to it. Also the units in the sample data file are just that, a sample, and in the end they'll all be kg. Thanks for the concern though!

  14. #29
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    'program works fine' does *NOT* mean it's *CORRECT*!
    s is of type character. space is allocated only for one character.
    When you use scanf %s with &s, you are overwriting(even if only 1 char is input since scanf appends null char) memory and the behavior is undefined (it may work or something bad may happen).

    Code:
    char filename[100];
       scanf("%100s",filename);    
       fs = fopen(filename,"r");
    For why & is not needed in scanf --> c-faq

  15. #30
    Registered User
    Join Date
    Jul 2010
    Location
    Liverpool
    Posts
    34
    That's useful - didn't realise a number could be used in that way. It explains a couple of problems I've had in another program. Thanks a lot!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Writing variables to a text doc?
    By Cielo in forum C++ Programming
    Replies: 3
    Last Post: 03-18-2008, 04:10 AM
  2. Backgammon
    By glo in forum Game Programming
    Replies: 5
    Last Post: 10-02-2006, 10:26 PM
  3. reading a text file printing line number
    By bazzano in forum C Programming
    Replies: 4
    Last Post: 09-16-2005, 10:31 AM
  4. i/o assigning variables
    By bballzone in forum C++ Programming
    Replies: 4
    Last Post: 07-30-2004, 10:49 AM
  5. Reading/Writing Files
    By r0ss in forum C Programming
    Replies: 2
    Last Post: 11-04-2003, 03:53 PM