Reading from files passed as command line arguements - c

I am trying to parse a given textfile, but so far, my program does not seem to be reading properly.
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fr; //file pointer
int buildingFloors = 1;
printf("sanity check\n");
fr = fopen (argv[0], "r");
fscanf(fr, "%d", &buildingFloors );
printf("%d\n", buildingFloors);
fclose(fr);
return 0;
}
I compile the program and run it on my redhat linux machine with the following command:
./sjf file.text
file.text is a text document with a "4" as the first character. So I would expect my output to be
sanity check
4
However, when I run my program I instead get
sanity check
1
Which implies that fscanf didn't properly read in the first character -- 4. Do I have some syntax error that's preventing the expected code functionality? Am I supposed to scanf for a character, and then convert that to an int somehow?

argv[0] is the name of the program (./sjf in your case), so you're trying to read in your own program's executable. Use argv[1] instead to get the first real program argument.

One thing which immediatly comes to mind is that the program args include the executable name as the first element
argv[0] is "sjf"
argv[1] is "file.text"
so you should be using
fr = fopen (argv[1], "r");
Remember when debugging to always try and narrow the problem down, if you know the location of the error the cause often becomes obvious or at least investigatable.
In this case you should check argc >= 2, print out argv[1] to ensure you are trying to open the right file, then also check that the file was opened successfully.
Finally check the fscanf error codes to see that fscanf was able to read the number.

Your code looks clear and straight-forward, but there is one important thing missing: error handling.
What happens if the file you want to open does not exist? fopen returns NULL in that case.
What happens if the file does not start with a number? fscanf returns the number of fields that have been successfully read, so you should check that the return value is at least 1.
You need to somehow handle these cases, probably by printing some error message and exiting the program. When you do that, be sure to include the relevant information in the error messages. Then you will find the bug that the other answers have already mentioned.

Related

How to make flex use a text-containing file (.txt/.c/etc.) as its input

I am completely new to flex, and my experience in programming is rather little. I need to create a scanner using flex that will output a stream of tokens eventually. For the moment, I just need to get the absolute basics up and running. I want the compiled output file "a.exe" to be able to be run from the text within a SINGLE file and not user input. The output should also be to a file. The assignment asks that the program is able to run like so in a cmd/PS window:
.\a.exe inputfile.txt outputfile.txt
Where input and output files are whatever file names are added in that order.
As it stands currently, my program creates the output file I designate, but nothing is written to it. When trying to read the Flex Manual, I am very confused as I am still very new to computer sciences in general.
As per the moment, I just want to get an executable file that will adhere to the rules section and output properly. This said I am generically just counting the characters in the input file and trying to display them to an output file. I also am trying to help the others in my class have a place to begin (as none of us were formally taught in this affair) so I am taking the time to try and create this file generically (with installation and usage instructions) so that I can give them a place to start the actual assignment of making the scanner.
I installed Flex 2.5.4a from http://gnuwin32.sourceforge.net/packages.html. I edited my Path to include the bin file after installation.
I build the file using the command "flex tokenout.l" and then "gcc lex.yy.c" and it generates an a.exe file. The file does not seem to work much at all past creating the output file.
code:
int num_lines = 0;
int num_chars = 0;
FILE *yyin;
FILE *yyout;
%%
\n ++num_lines; ++num_chars;
. ++num_chars;
%%
int yywrap(void) {
return 0;
}
int main(int argc, char *argv[])
{
yyin = fopen(argv[1],"r");
yyout = fopen(argv[2],"w");
yyparse();
yylex();
fprintf(yyout,"# of lines = %d, # of chars = %d\n", num_lines, num_chars);
fclose(yyin);
fclose(yyout);
return 0;
}
The result should be that the line "# of lines = the actual # of lines, # of chars = the actual # of characters" to the file designated as the second argument.
Currently the file designated by the second argument is created but remains blank.
Lex (flex) calls (or more precisely, generates code that calls) yywrap upon reaching the end of its input stream (in yyin). The job of this function is to:
Take care of closing the input file if needed / appropriate.
Switch to the next input file, if there is a next file.
Return nonzero (1, preferably) if flex should finish up, 0 if yyin is now re-opened to the next file.
Or, as the manual puts it:
When the scanner receives an end-of-file indication from YY_INPUT, it then checks the ‘yywrap()’ function. If ‘yywrap()’ returns false (zero), then it is assumed that the function has gone ahead and set up yyin to point to another input file, and scanning continues. If it returns true (non-zero), then the scanner terminates, returning 0 to its caller. Note that in either case, the start condition remains unchanged; it does not revert to INITIAL.
If you do not supply your own version of ‘yywrap()’, then you must either use ‘%option noyywrap’ (in which case the scanner behaves as though ‘yywrap()’ returned 1), or you must link with ‘-lfl’ to obtain the default version of the routine, which always returns 1.
(Modern flex has <<EOF>> rules which are generally a better way to deal with stacked input files, since transitions between files should almost always force a token boundary.)
yyin = fopen(argv[1],"r");
yyout = fopen(argv[2],"w");
yyparse();
yylex();
As it stands currently, my program creates the output file I designate, but nothing is written to it.
You're confused because you don't know what your program is doing, and you don't know what it's doing because it's not telling you. What you need is feedback. In particular, you need to check for errors.
For example, what if the first fopen(3) fails? What if yyparse fails, or doesn't return? (It won't.) Check for errors, and have the program tell you what's happening.
#include <err.h>
if( argc < 3 ) {
errx(EXIT_FAILURE, "syntax: foo in out");
}
if( (yyin = fopen(argv[1],"r")) == NULL ) {
err(EXIT_FAILURE, "could not read '%s'", argv[1]);
}
if (yyout = fopen(argv[2],"w")) == NULL ) {
err(EXIT_FAILURE, "could not write '%s'", argv[2]);
}
printf("starting yyparse\n");
if( 0 != yyparse() ) {
errx(EXIT_FAILURE, "parse error");
}
printf("starting yylex\n");
if( 0 != yylex() ) {
errx(EXIT_FAILURE, "lex error");
}
The above ensures the program is started with sufficient arguments, ensures both files are open successfully, and checks for errors parsing and lexing. That's just an example, though. As John Bollinger advised, you don't need yyparse because you're not using bison, and yyout controls only the file used by the flex ECHO statement. You can use your own global FILE * handle, and fprintf(3) to it in your flex actions.
What i think you will find is that you never see "starting yylex" on the screen, because yyparse never returns, because -- if it is being generated somewhere -- it's not returning, because it's calling yylex, which never returns anything to it.
I would delete those lines, and set flex debugging on with
yy_flex_debug = 1;
before calling yylex. I think you'll find it makes more sense then.
You appear to be starting by adapting an example program from the Flex manual. That's fine, but maybe your very first step should be getting the exact example program working. After that, take it one step at a time. For example, the next step might be to get it to use the first argument as the name of the input file (and no other changes).
With respect to the partial program you have presented, I see two semantic issues:
When you use flex with bison (or yacc), it is the generated parser (accessed via yyparse()) that calls yylex(), and generally it will do so repeatedly until the input is exhausted. It is not useful in that case for the main program to call the lexer directly.
yyout is the file to which flex will direct the output of ECHO statements, nothing more, nothing less. It is not particularly useful to you, and I would ignore it for now.

fgetc() Creating Segmentation Fault

I made the file "wor.txt" in the same program and i closed its write stream. But when i try to access it in first run(I created the file) it gives segmentation fault but when i re-run this program it runs successfully.
When i delete the automatically generated file and run the program again it gives Segmentation fault and on 2nd run(Without deleting the file) it runs successfully again.
NOTE: There is data in the textfile hence it is not empty(I have seen it after the first run in the file manager)
FILE *fp1= fopen("wor.txt","r");
FILE *f1= fopen("wordsa.txt","ab+");
if((f1==NULL)||(f2==NULL)){
printf("f1 or f2 is null");
}
char c='0';
while((c)!=EOF){
printf("Here is one marker\n");
c=fgetc(fp1); //This Line gives error
printf("Here is another marker\n");
fputc(c,f1);
}
A char is no sufficient for EOF, change the type to int.
Check the man page of fgetc(), it returns an int and you should use the same datatype for storing the return value and further use.
That said, when either of f1 or fp1 is NULL, you are continuing anyways, accessing those file pointers, which may create UB. You should make some sense of that NULL check and either return or exit so that the code accessing tose pointers are not reached.
Incorrect check.
To properly detect opening of the stream, check fp1, not f2. Then code will fail gracefully when the files do not open properly rather than seg fault.
FILE *fp1= fopen("wor.txt","r");
FILE *f1= fopen("wordsa.txt","ab+");
// if((f1==NULL)||(f2==NULL)){
if((f1==NULL) || (fp1==NULL)){
printf("f1 or fp1 is null");
}
Also use int c as fgetc() typically returns 256 + 1 different values (unsigned char values and EOF) and a char is insufficient to uniquely distinguish them.

Check if files exists (given by command line arguments)

I have to a do C program that uses the unix environment. I have already purchased the "Advancing Programming in the Unix Environment" book and it has helped out a lot so far. However, some of my questions have gone unanswered and I'm looking for some help.
I'm trying to write a program that can verify if the first and second arguments entered if a copy program exist. If the first argument does not exist, then an error message and exit must occur. If the second argument does exist, then an overwrite prompt must be displayed. I'm not exactly sure how to verify if a file already exists or not basically.
I have seen a few people saying that you can do (!-e) or something like that to verify the file existing/not existing.
If anyone could help me, I'd really appreciate it.
The access() function is designed to tell you if a file exists (or is readable, writeable or executable).
#include <unistd.h>
int result;
const char *filename = "/tmp/myfile";
result = access (filename, F_OK); // F_OK tests existence also (R_OK,W_OK,X_OK).
// for readable, writeable, executable
if ( result == 0 )
{
printf("%s exists!!\n",filename);
}
else
{
printf("ERROR: %s doesn't exist!\n",filename);
}
in your int main(int argc, char** argv) { block.
if (argc == 3) {
// then there were 3 arguments, the program name, and two parameters
} else if (argc == 2) {
// then prompt for the "second" argument, as the program name and one
// parameter exists
} else {
// just print out the usage, as we have a non-handled number of arguments
}
now if you want to verify that the file exists, that's different than verifying that the program argument exists. Basically attempt to open the file and read from it, but pay close attention to catching the integer error codes and checking them for errors. This will prevent your program from progressing into bits where those critical operations are assumed to have worked.
There is a common, yet misguided conception among new programmers when dealing with files in C. Basically, one really wants to make sure that a specific block of code works (the copying block in your case), so they check, check, and double-check conditions before the block is executed. Check if the file exists, check if it has correct permissions, check that it isn't a directory, etc. My recommendation is that you not do this.
Your copying block should be able to fail properly, just as properly as it should be able to succeed. If it fails, then typically you have all the information necessary to print out a meaningful error message. Should you check first and then act there will always be a small time gap between the check and action, and that time gap will eventually see the file removed or altered after the checks have passed, yet before it is read. Under such a scenario all of the pre-checking code failed to provide any benefit.
Code without benefit is just a nesting ground for future bugs and architectural problems. Don't waste your time writing code that has dubious (or no) benefit. When you suspect that some code you have written has little benefit, you need to restructure your code to put it in the right place. When you suspect that code someone else has written has little benefit, you need to first doubt your suspicions. It is trivially easy to not see the motivations behind a piece of code, and even more so when just starting out in a new language.
Good Luck!
--- code for the weary ---
#include <errorno.h>
#include <stdio.h>
#include <stdlib.h>
extern int errno;
int main(int argc, char** argv) {
// to hold our file descriptor
FILE *fp;
// reset any possible previously captured errors
errno = 0;
// open the file for reading
fp = fopen(argv[1], "r");
// check for an error condition
if ( fp == 0 && errno != 0 ) {
// print the error condition using the system error messages, with the
// additional message "Error occurred while opening file"
perror("Error occurred while opening file.\n");
// terminate the program with a non-successful status
exit(1);
}
}

Calling executable file inside C program

I have a C program which will take one argument as input and, if the argument is matching with the string inside the executable, it will return 1 otherwise 0. The executable file name is prg1. I have some input strings in a file named inputs.txt. I want to get those strings from the input file and call the prg1 inside a C program with each string.
I have tried the following code but it's not working.There is no segmentation fault but when i am calling prg1 it executes, Because the printf() statement inside prg1 is working and i can see the output.it changes variable found to 0I cant change the prg1. Because my friend has given the executable file of that program to me, not the source code. Header files are stdio.h and string.h
int main()
{
FILE *fk;
char text[80],inp[16],test[50]={"./prg1 "};
int found=100;
fk=fopen("inputs.txt","r");
while((fscanf(fk,"%s",inp))!=EOF)
{
strcat(test,inp);
found=system(test);
if(found==1)
{
printf("\nAnswer is : %s",inp);
break;
}
strcpy(test,"./prg1 ");
}
fclose(fk);
return 0;
}
What is wrong with my code?
I am not sure of what you want to achieve but here are some comments:
1 - You should test the return value of fopen:
if (!fk) { ... }
2 - You're not cleaning the test buffer between each test, so you are effectively calling:
system("prg1 first_word");
system("prg1 first_wordsecond_word");
...
You should have something like:
strcpy(test, "prg1 ");
after entering the loop and before strcat.
3 - Do you have spaces in your input strings? You should fix your code to read until a newline in this case.
4 - You might want to use EXIT_SUCCESS and EXIT_FAILURE instead of 0 and 1.
prog1 returns 1 when finding match, but 1 stands for error (at least in linux systems). Try returning EXIT_SUCCESS and EXIT_FAILURE (defined in stdlib.h). Then, when the system() call returns 0, the match is found, when anything else, match is not found.
The fundamental flaw in your code is that you need to reset the contents of the 'test' array to be "prg1 " at the beginning of each iteration of the main loop, before you call strcat to add the next argument to the command line. Otherwise the command to be run will just continue to get longer with each iteration, as each input read is added to the existing command. I don't think that is what you intend.
For example, given two lines of input, "foo" and "bar", the first iteration of the loop will cause the command "prg1 foo" to be executed, while the second will cause "prg1 foobar" to be executed. An easy way to have checked that would be to insert a printf (or similar) before the call to system() to display what command is going to be executed.
You also should check the return code of fopen and check array bounds when assigning to an array using fscanf.

Opening a file in C through a proccess

I am trying to create a a program that does the following actions:
Open a file and read one line.
Open another file and read another line.
Compare the two lines and print a message.
This is my code:
#include <stdio.h>
#include <string.h>
int findWord(char sizeLineInput2[512]);
int main()
{
FILE*cfPtr2,*cfPtr1;
int i;
char sizeLineInput1[512],sizeLineInput2[512];
cfPtr2=fopen("mike2.txt","r");
// I open the first file
while (fgets(sizeLineInput2, 512, cfPtr2)!=NULL)
// I read from the first 1 file one line
{
if (sizeLineInput2[strlen(sizeLineInput2)-1]=='\n')
sizeLineInput2[strlen(sizeLineInput2)-1]='\0';
printf("%s \n",sizeLineInput2);
i=findWord(sizeLineInput2);
//I call the procedure that compares the two lines
}
getchar();
return 0;
}
int findWord(char sizeLineInput2[512])
{
int x;
char sizeLineInput1[512];
File *cfPtr1;
cfPtr1=fopen("mike1.txt","r");
// here I open the second file
while (fgets(sizeLineInput1, 512,cfPtr1)!=NULL)
{
if (sizeLineInput1[strlen(sizeLineInput1)-1]=='\n')
sizeLineInput1[strlen(sizeLineInput1)-1]='\0';
if (strcmp(sizeLineInput1,sizeLineInput2)==0)
//Here, I compare the two lines
printf("the words %s and %s are equal!\n",sizeLineInput1,sizeLineInput2);
else
printf("the words %s and %s are not equal!\n",sizeLineInput1,sizeLineInput2);
}
fclose(cfPtr1);
return 0;
}
It seems to have some problem with file pointers handling. Could someone check it and tell me what corrections I have to do?
Deconstruction and Reconstruction
The current code structure is, to be polite about it, cock-eyed.
You should open the files in the same function - probably main(). There should be two parallel blocks of code. In fact, ideally, you'd do your opening and error handling in a function so that main() simply contains:
FILE *cfPtr1 = file_open("mike1.txt");
FILE *cfPtr2 = file_open("mike2.txt");
If control returns to main(), the files are open, ready for use.
You then need to read a line from each file - in main() again. If either file does not contain a line, then you can bail out with an appropriate error:
if (fgets(buffer1, sizeof(buffer1), cfPtr1) == 0)
...error: failed to read file1...
if (fgets(buffer2, sizeof(buffer2), cfPtr2) == 0)
...error: failed to read file2...
Then you call you comparison code with the two lines:
findWord(buffer1, buffer2);
You need to carefully segregate the I/O operations from the actual processing of data; if you interleave them as in your first attempt, it makes everything very messy. I/O tends to be messy, simply because you have error conditions to deal with - that's why I shunted the open operation into a separate function (doubly so since you need to do it twice).
You could decide to wrap the fgets() call and error handling up in a function, too:
const char *file1 = "mike1.txt";
const char *file2 = "mike2.txt";
read_line(cfPtr1, file1, buffer1, sizeof(buffer1));
read_line(cfPtr2, file2, buffer2, sizeof(buffer2));
That function can trim the newline off the end of the string and deal with anything else that you want it to do - and report an accurate error, including the file name, if anything goes wrong. Clearly, with the variables 'file1' and 'file2' on hand, you'd use those instead of literal strings in the file_open() calls. Note, too, that making them into variables means it is trivial to take the file names from the command line; you simply set 'file1' and 'file2' to point to the argument list instead of the hard-wired defaults. (I actually wrote: const char file1[] = "mike1.txt"; briefly - but then realized that if you handle the file names via the command line, then you need pointers, not arrays.)
Also, if you open a file, you should close the file too. Granted, if your program exits, the o/s cleans up behind you, but it is a good discipline to get into. One reason is that not every program exits (think of the daemons running services on your computer). Another is that you quite often use a resource (file, in the current discussion) briefly and do not need it again. You should not hold resources in your program for longer than you need them.
Philosophy
Polya, in his 1957 book "How To Solve It", has a dictum:
Try to treat symmetrically what is symmetrical, and do not destroy wantonly any natural symmetry.
That is as valid advice in programming as it is in mathematics. And in their classic 1978 book 'The Elements of Programming Style', Kernighan and Plauger make the telling statements:
[The] subroutine call permits us to summarize the irregularities in the argument list [...]
The subroutine itself summarizes the regularities of the code.
In more modern books such as 'The Pragmatic Programmer' by Hunt & Thomas (1999), the dictum is translated into a snappy TLA:
DRY - Don't Repeat Yourself.
If you find your code doing the 'same' lines of code repeated several times, write a subroutine to do it once and call the subroutine several times.
That is what my suggested rewrite is aiming at.
In both main() and findWord() you should not use strlen(sizeLineInputX) right after reading the file with fgets() - there may be no '\0' in sizeLineInput2 and you will have strlen() read beyond the 512 bytes you have.
Instead of using fgets use fgetc to read char by char and check for a newline character (and for EOF too).
UPD to your UPD: you compare each line of mike2.txt with each line of mike1.txt - i guess that's not what you want. Open both files one outside while loop in main(), use one loop for both files and check for newline and EOF on both of them in that loop.

Resources