Thread: open file with numbers and multiply them

  1. #16
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    But how would you even see if it worked ? :|

  2. #17
    Registered User
    Join Date
    Aug 2007
    Posts
    28
    Now i just wanted to make the program read all the files in a directory and compute all of them.
    Also any sugestions to improve the code?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    double x; 
    double y;
    double z;
    double factor;
    char line[200];
    char factorin[200];
    char ficheiro[200];
    char ficheiro_mod[200];
       
    int main() {
        printf("Introduzir nome do ficheiro: ");
        fgets(ficheiro, sizeof(ficheiro), stdin);
        ficheiro[strlen(ficheiro)-1] = '\0'; /* elimina o ultimo caracter */
        
       	/* Qual o factor de multiplicacao?*/
        printf("Introduzir o factor de conversao [0,1]: ");
    	fgets(factorin, sizeof(factorin), stdin);
    	sscanf(factorin, "%lf", &factor);
        
    	FILE *in, *out; 	
        in = fopen( ficheiro, "r" ); /* abre o ficheiro de leitura */
        if( in == NULL ) {
        	printf("ERRO: nao é possível encontrar o ficheiro %s\n", ficheiro);
            exit(1);
            }
            
        /* alterar nome do ficheiro de saida */
        strcpy(ficheiro_mod, ficheiro);
        strcat(ficheiro_mod, "_mod.asc");
        
        out = fopen( ficheiro_mod, "w" ); /* abre o ficheiro de saida */
    	if( out == NULL ) {
    		printf("ERRO: nao é possivel abrir o ficheiro de saida\n");
    		exit(1);
    		}
    		
    	/* leitura e escrita */ 
    
    	while (fgets(line, sizeof(line), in) != NULL) { 
    	sscanf(line, "%lf,%lf,%lf", &x, &y, &z);
    	fprintf(out, "%lf,%lf,%lf\n", x * factor, y * factor, z * factor);
    	}
       
        /* fecha os ficheiros */
        fclose( in );
        fclose( out );
        return (0);
        }

  3. #18
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    If you are writing C (rather than C++), you should declare FILE *in, *out; before any of the code, (so before the first printf).

    You don't need to use global variables, all the variables could be moved inside of main (before the first printf).

    To be strictly correct, you should check that the character at strlen(ficheiro)-1 is really a newline before you replace it - it would fail if someone enters an EXACTLY 199 char long filename, as the last char of the filename would be overwritten by a zero.

    You should check the return value from sscanf() to ensure that the data is correctly read.

    To be strictly correct, you also should use PATH_MAX from limits.h instead of a constant of 200 for your filename strings - that way, any valid filename would be acceptable, not just ones that are shorter than 200 chars [not really a BIG problem, but if someone wants to use a file that is some very deep directory structure, then I suppose they should be allowed, yes?]

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #19
    Registered User
    Join Date
    Jun 2007
    Posts
    63
    Well the final answer i suppose to your problem is the following:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    int WriteMulToFile(char *inFile, char *outFile, const int factor)
    {
    	if(inFile == NULL || outFile == NULL)
    	{
    		fprintf(stderr, "File Error, check input or output files.\n");
    		return -1;
    	}
    	else
    	{
    		FILE *in = fopen(inFile, "r");
    		FILE *out = fopen(outFile, "w");
    		//Index.
    		int i;
    		//Variables.
    		float x,y,z;
    		if(in == NULL)
    		{
    			fprintf(stderr,"Error can not open file &#37;s in read mode.\n", inFile);
    			return -2;
    		}
    		else if(out == NULL)
    		{
    			fprintf(stderr,"Error can not open file %s in read mode.\n", outFile);
    			return -3;
    		}
    		else
    		{
    			//File opening OK!!
    			char *Buf = malloc(1024);
    			if(Buf == NULL)
    			{
    				fprintf(stderr, "Error Memory.\n");
    				return -4;
    			}
    			else
    			{
    				//Init memory block.
    				memset(Buf, 0, 1024);
    				//Init variables.
    				x = 0.0;y = 0.0;z = 0.0;
    				//Read records from file.
    				while(fgets(Buf, 1024, in) != NULL)
    				{
    					if(Buf[strlen(Buf) - 1] == '\n')
    						Buf[strlen(Buf) - 1] = '\0';
    					//Now we have in Buf the whole line lets parse it.
    					if(sscanf(Buf, "%f %f %f", &x, &y, &z) != 3)
    					{
    						printf("Error reading from buffer.\n");
    						return -5;
    					}
    					else
    						fprintf(out, "%.3f %.3f %.3f\n", factor * x, factor * y, factor * z);
    					memset(Buf, 0, strlen(Buf));
    				}
    				//Close Files.
    				fclose(in);
    				fclose(out);
    				//Free memory.
    				free(Buf);
    
    				//Return 
    				return 0;
    			}
    		}
    	}
    
    }
    
    int main(int argc, char *argv[])
    {
    	int factor = 0;
    	printf("Welcome...............\n");
    	printf("Give me the factor to multiply the values that will be read from file:");
    	scanf("%d", &factor);
    	WriteMulToFile("input.txt", "output.txt", factor);
    	return 0;
    }
    Last edited by Bokarinho; 09-07-2007 at 07:07 AM.

  5. #20
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    @Bokarinho, your use of memset doesn't achieve anything useful.
    fgets() will always append a single \0, you don't have to pre-fill the buffer to begin with.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #21
    Registered User
    Join Date
    Jun 2007
    Posts
    63
    Thanks, i dont understand what you mean the reason i do that in the while loop is to clear the buffer so to use it again in fgets().
    So what do you mean?
    Does fgets overwrite the previous data in buffer?Should we clear the whole buffer firstly so the next time the loop goes to store the new line from file?

  7. #22
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Yes, fgets() will overwrite what was there previously, from the beginning of the buffer (it's not like say strcat).

    If the first line of the file was "Hello world\n", then the buffer would contain "Hello world\n\0"
    If the second line of the file was "Hi\n", then the buffer would contain "Hi\n\0o world\n\0"

    Yes, the end of the longer lines will remain stored in memory, but they will not be accessible through normal use of the standard string API calls (strcpy etc). Thus in a correct program, you'll never see past the first \0 stored in the buffer, which marks the end of the most recently read line.

    One possible good reason for using memset() would be to ensure that no traces of sensitive information could leak into other parts of the program, or perhaps be written out to a file. But this requires a great amount of skill to do properly, if you're also going to contend with page files, hibernation files and the like.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #23
    Registered User
    Join Date
    Jun 2007
    Posts
    63
    Quote Originally Posted by Salem View Post
    Yes, fgets() will overwrite what was there previously, from the beginning of the buffer (it's not like say strcat).

    If the first line of the file was "Hello world\n", then the buffer would contain "Hello world\n\0"
    If the second line of the file was "Hi\n", then the buffer would contain "Hi\n\0o world\n\0"

    Yes, the end of the longer lines will remain stored in memory, but they will not be accessible through normal use of the standard string API calls (strcpy etc). Thus in a correct program, you'll never see past the first \0 stored in the buffer, which marks the end of the most recently read line.

    One possible good reason for using memset() would be to ensure that no traces of sensitive information could leak into other parts of the program, or perhaps be written out to a file. But this requires a great amount of skill to do properly, if you're also going to contend with page files, hibernation files and the like.

    Thanks for the correction, still i suppose it is good to clear the buffer although there is no specific need to do that. I still have to learn more about C, i am not so skilled or experienced programmer like you,
    Thanks again, Bokarinho!!!

  9. #24
    Registered User
    Join Date
    Aug 2007
    Posts
    28
    I cleaned up as sugested(thanks matsp), but i still have one last question: how can i change the code to accept: an argument such as "./fescala infile outfile" supposing that i would specify the factor before compiling?


    Code:
    /*
    /* Programa para recalcular coordenadas XYZ      
    /* Dado um ficheiro de entrada xyz e um factor   
    /* de convers&#227;o recalcula as coordenadas originais 
    /* e escreve um ficheiro de sa&#237;da
    /* 2007-09-10
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
     
    int main() {
        double x; 
        double y;
        double z;
        double factor;
        char line[PATH_MAX];
        char factorin[PATH_MAX];
        char ficheiro[PATH_MAX];
        char ficheiro_mod[PATH_MAX];
        
        FILE *in, *out; 
        
        /* inicializa o nome do ficheiro de entrada */
        printf("Introduzir nome do ficheiro: ");
        fgets(ficheiro, sizeof(ficheiro), stdin);
        ficheiro[strlen(ficheiro)-1] = '\0'; /* elimina o ultimo caracter */
        return (0); /* verifica se o numero foi lido correctamente */
        
       	/* Qual o factor de multiplicacao?*/
        printf("Introduzir o factor de conversao [0,1]: ");
    	fgets(factorin, sizeof(factorin), stdin);
    	sscanf(factorin, "&#37;lf", &factor);
    	return (0); /* verifica se o numero foi lido correctamente */
        	
        in = fopen( ficheiro, "r" ); /* abre o ficheiro de leitura */
        if( in == NULL ) {
        	printf("ERRO: nao e poss&#237;vel encontrar o ficheiro %s\n", ficheiro);
            exit(1);
            }
            
        /* alterar nome do ficheiro de saida */
        strcat(ficheiro_mod, "esc-");
        strcpy(ficheiro_mod, ficheiro);
        
        out = fopen( ficheiro_mod, "w" ); /* abre o ficheiro de saida */
    	if( out == NULL ) {
    		printf("ERRO: nao e possivel abrir o ficheiro de saida\n");
    		exit(1);
    		}
    	
    	/* leitura e escrita */ 
    	while (fgets(line, sizeof(line), in) != NULL) { 
    	sscanf(line, "%lf %lf %lf", &x, &y, &z); /* mudar de espa&#231;o para virgula se necessario */
    	fprintf(out, "%.3lf,%.3lf,%.3lf\n", x * factor, y * factor, z * factor); /* o output e escrito com 3 casas decimais */
    	}
       
        /* fecha os ficheiros */
        fclose( in );
        fclose( out );
        return (0);
        }
    Last edited by autopilot; 09-10-2007 at 06:04 AM.

  10. #25
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You need to add argc, argv to main.

    argc will contain the number of arguments (first one is normaly the applications name). These ones are in argv, and the first one is the application name, so in your example:
    argv[0] = "fescala"
    argv[1] = "input"
    argv[2] = "output"

    Make sure you check that you have the right number of arguments before you try to use them, as a common cause for errors is to "use arguments that aren't there". This is undefined behaviour, so "it may do almost anything" - but it's almost certain that it won't do what you want, that's 99.99999% certain!

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #26
    Registered User
    Join Date
    Aug 2007
    Posts
    28
    Quote Originally Posted by matsp View Post
    You need to add argc, argv to main.

    argc will contain the number of arguments (first one is normaly the applications name). These ones are in argv, and the first one is the application name, so in your example:
    argv[0] = "fescala"
    argv[1] = "input"
    argv[2] = "output"
    Mats
    I tried this out but i am doing something wrong. It reads the file, deletes the input and produces an empty output file.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
     
    int main(int argc, char **argv) {
        double x; 
        double y;
        double z;
        float factor;
        char line[PATH_MAX];
        char output[PATH_MAX];
        
        FILE *in, *out; 
        
        if ( argc != 3 ) {
        fputs ( "usage: mfescala.exe input output", stderr );
        exit ( EXIT_FAILURE );
      }       
        factor = 0.97;
        	
        in = fopen(argv[1], "r"); /* abre o ficheiro de leitura */
        if( in == NULL ) {
        	printf("ERRO: nao e possivel encontrar o ficheiro &#37;s\n", argv[1]);
            exit(1);
            }
        
        out = fopen(argv[2], "w" ); /* abre o ficheiro de saida */
    	if( out == NULL ) {
    		printf("ERRO: nao e possivel abrir o ficheiro de saida\n");
    		exit(1);
    		}
    	
    	/* leitura e escrita */ 
    	while (fgets(line, sizeof(line), in) != NULL) { 
    	sscanf(line, "%lf %lf %lf", &x, &y, &z); /* mudar de espa&#231;o para virgula se necessario */
    	fprintf(argv[2], "%.3lf,%.3lf,%.3lf\n", x * factor, y * factor, z * factor); /* o output e escrito com 3 casas decimais */
    	}
       
        /* fecha os ficheiros */
        fclose( in );
        fclose( out );
        return (0);
        }
    Last edited by autopilot; 09-10-2007 at 09:13 AM.

  12. #27
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It looks about right to me, but fprintf(argv[2]) is definitely not the right thing to do... You should have compiler warnings enabled so that you get a big fat warning message that argv[2] isn't a "FILE *".

    Also, if you use the same name for both input and output files, then you would get the result you describe. There's little you can do about that - best approach may be to compare input and output file names and see if they are the same, and exit if that's the case.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #28
    Registered User
    Join Date
    Aug 2007
    Posts
    28
    Well, sometimes it is best to start over. Followed the instructions of the faq
    Thanks for all the replys. The second version is working now, constant "factor"

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
    
    
    static FILE *open_file ( char *file, char *mode )
    {
      FILE *fp = fopen ( file, mode );
    
      if ( fp == NULL ) {
        perror ( "Unable to open file" );
        exit ( EXIT_FAILURE );
      }
    
      return fp;
    }
    
    int main ( int argc, char *argv[] )
    {
      FILE *in;
      FILE *out;
      
      char line[PATH_MAX];
      double x; 
      double y;
      double z;
      double factor;
      factor = 0.97;
    
      if ( argc != 3 ) {
        fprintf ( stderr, "Usage: %s input output\n", argv[0] );
        exit ( EXIT_FAILURE );
      }
    
      in = open_file ( argv[1], "r" );
      out = open_file ( argv[2], "w" );
      
      /* leitura e escrita */ 
      while (fgets(line, sizeof(line), in) != NULL) { 
      sscanf(line, "%lf %lf %lf", &x, &y, &z); /* mudar de espaço para virgula se necessario */
      fprintf(out, "%.3lf,%.3lf,%.3lf\n", x * factor, y * factor, z * factor); /* o output e escrito com 3 casas decimais */
    	}
      
      fclose ( in );
      fclose ( out );
    
      return EXIT_SUCCESS;
    }

  14. #29
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Looking at it briefly, it looks good.

    Some minor comments:
    - Not sure what PATH_MAX has to do with your line. Line is the data you read from the file, which, in theory could be "any lenght", but realistically should be within 100 chars (33 chars per number) - nothing wrong with making your buffer 1000 long (about 333 chars per number), or some such, tho'. But PATH_MAX is really used for filepaths and filenames, not as a "generic constant". Ideally, I'd like to see a #define constant, such as this:
    Code:
    #define LINE_MAX (1000)
    ...
    int main(...)
    ...
      char line[LINE_MAX];
    ...
    Is three decimal points what you should be doing? There's no real right or wrong answer, I'm just asking, because if you have quite small numbers, chopping at 3 decimal places is perhaps a bit low. The larger the number is, the less important the decimal places become, of course.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #30
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    For extra points, go with
    Code:
    if ( sscanf(line, "%lf %lf %lf", &x, &y, &z) == 3 ) {
      fprintf(out, "%.3lf,%.3lf,%.3lf\n", x * factor, y * factor, z * factor);
    } else {
      // complain about a badly formatted line
    }
    For maximum points, use strtod() in place of sscanf(), because the former will also detect overflow and underflow.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multiplying Huge numbers in integer arrays
    By invierno in forum C Programming
    Replies: 5
    Last Post: 04-11-2009, 08:40 PM
  2. Matrix Multiplication ( Accessing data from a file ) HELP
    By six_degreez in forum C Programming
    Replies: 2
    Last Post: 07-24-2008, 05:21 PM
  3. Help with Rational Numbers (C++)
    By cloudjc in forum C++ Programming
    Replies: 3
    Last Post: 04-28-2008, 04:03 PM
  4. How to multiply and Divide Huge int numbers
    By Dewayne in forum C++ Programming
    Replies: 3
    Last Post: 10-21-2004, 08:41 PM
  5. data in a file
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 08-05-2002, 02:23 PM