But how would you even see if it worked ? :|
But how would you even see if it worked ? :|
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); }
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.
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 %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.
@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.
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?
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.
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ão recalcula as coordenadas originais /* e escreve um ficheiro de saí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, "%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í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ç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.
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.
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 %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ç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.
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.
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; }
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:
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.Code:#define LINE_MAX (1000) ... int main(...) ... char line[LINE_MAX]; ...
--
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.
For extra points, go with
For maximum points, use strtod() in place of sscanf(), because the former will also detect overflow and underflow.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 }
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.