I have a program that should take the file's name from command line using argc and argv. Printing argv[1] and argv[2] show me the exactly names I passed, but passing argv[1] and argv[2] as parameters to open the files in another function just show the error line I put if can't open the file.
My main:
int main(int argc, char* argv[])
{
if (argc != 4)
{
puts("Incorrect number of parameters.");
return 1;
}
else
{
Image *a, *b;
a = OpenFile(argv[1]);
b = OenFile(argv[2]);
} /* else */
return 0;
} /* main */
The function OpenFile will return a struct filled with information from the file. Here's the first part of the function:
Image *OpenFile(char* name)
{
FILE* f = fopen(name, "r");
Image* imagem;
int temp, i, cont, data[MAX];
char aux[2];
if(f == NULL)
{
puts("Error opening file.");
return NULL;
} /* if */
...
}
I'm passing the correct names but I receive the "Error opening file." line for each file I try to open.
Edit: It's giving me "No such file or directory", but I copied the files to the directory where the .exe is placed. It's not the first time I use the file's name from command line, but it's the first time I pass as parameters to another function.
From fopen man page:
RETURN VALUE
Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned and
errno is set to indicate the error.
So You could change:
if(f == NULL)
{
puts("Error opening file.");
return NULL;
} /* if */
With:
if(f == NULL)
{
perror("fopen");
return NULL;
} /* if */
And you ll get a pretty descriptive message on the reason fopen failed.
You should include errno.h in order to use perror
Related
How would I be able to reset a pointer to the start of a commandline input or file. For example my function is reading in a line from a file and prints it out using getchar()
while((c=getchar())!=EOF)
{
key[i++]=c;
if(c == '\n' )
{
key[i-1] = '\0'
printf("%s",key);
}
}
After running this, the pointer is pointing to EOF im assuming? How would I get it to point to the start of the file again/or even re read the input file
im entering it as (./function < inputs.txt)
If you have a FILE* other than stdin, you can use:
rewind(fptr);
or
fseek(fptr, 0, SEEK_SET);
to reset the pointer to the start of the file.
You cannot do that for stdin.
If you need to be able to reset the pointer, pass the file as an argument to the program and use fopen to open the file and read its contents.
int main(int argc, char** argv)
{
int c;
FILE* fptr;
if ( argc < 2 )
{
fprintf(stderr, "Usage: program filename\n");
return EXIT_FAILURE;
}
fptr = fopen(argv[1], "r");
if ( fptr == NULL )
{
fprintf(stderr, "Unable to open file %s\n", argv[1]);
return EXIT_FAILURE;
}
while((c=fgetc(fptr))!=EOF)
{
// Process the input
// ....
}
// Move the file pointer to the start.
fseek(fptr, 0, SEEK_SET);
// Read the contents of the file again.
// ...
fclose(fptr);
return EXIT_SUCCESS;
}
Piped / redirected input doesn't work like that. Your options are:
Read the input into an internal buffer (which you already seem to be doing); or
Pass the file name as a command-line argument instead, and do with it as you please.
How would I be able to reset a pointer to the start of a commandline input or file. For example my function is reading in a line from a file and prints it out using getchar()
while((c=getchar())!=EOF)
{
key[i++]=c;
if(c == '\n' )
{
key[i-1] = '\0'
printf("%s",key);
}
}
After running this, the pointer is pointing to EOF im assuming? How would I get it to point to the start of the file again/or even re read the input file
im entering it as (./function < inputs.txt)
If you have a FILE* other than stdin, you can use:
rewind(fptr);
or
fseek(fptr, 0, SEEK_SET);
to reset the pointer to the start of the file.
You cannot do that for stdin.
If you need to be able to reset the pointer, pass the file as an argument to the program and use fopen to open the file and read its contents.
int main(int argc, char** argv)
{
int c;
FILE* fptr;
if ( argc < 2 )
{
fprintf(stderr, "Usage: program filename\n");
return EXIT_FAILURE;
}
fptr = fopen(argv[1], "r");
if ( fptr == NULL )
{
fprintf(stderr, "Unable to open file %s\n", argv[1]);
return EXIT_FAILURE;
}
while((c=fgetc(fptr))!=EOF)
{
// Process the input
// ....
}
// Move the file pointer to the start.
fseek(fptr, 0, SEEK_SET);
// Read the contents of the file again.
// ...
fclose(fptr);
return EXIT_SUCCESS;
}
Piped / redirected input doesn't work like that. Your options are:
Read the input into an internal buffer (which you already seem to be doing); or
Pass the file name as a command-line argument instead, and do with it as you please.
I've been looking around for like 4hours and cannot find where the problem is.
I got this function over here which is supposed to open a file.
In the function I successfully get into the != NULL condition thus returning 1, then in the main the value of my pointer test_file_1 is null (and then segfault when fclose)
I do not understand why because I am assigning the return value of fopen to my pointer !!
Here is the prototype :
/*
* Open a file and save its file pointer into file_to_load
* If it worked, returns 1
* Else, 0
*
* Prints its own error message, so you only have to use the return
* value to set the program behavior as wished
*
* filename : name of the file (+ path if needed)
* file_to_load : the file to be loaded
*
*/
int load_file(char* filename, FILE* file_to_load);
And here is the function by itself :
int load_file(char* filename, FILE* file_to_load)
{
//r is for read-only mode, we do not want to let the program edit the file
//We will only save when told (using save_file)
if( (file_to_load = fopen(filename, "r")) != NULL )
{
return 1;
}
else
{
fprintf(stderr, THE_FILE);
fprintf(stderr, filename);
fprintf(stderr, CANT_BE_OPENED);
// Should include the error number for convenience
return 0;
}
}
And .. here is the use in the main :
FILE* test_file_1 = NULL;
//Closed only if exists or else .. segfault
if ( (load_file("../bin/test", test_file_1)) == 1)
{
fclose(test_file_1);
}
C is pass-by-value, not pass-by-reference.
That means a function always gets a copy of its arguments, and changing its copy has no effect on the expression used on calling.
Use additional indirection, here the modified lines (each has exactly one * or & more):
int load_file(char* filename, FILE** file_to_load);
int load_file(char* filename, FILE** file_to_load)
if( (*file_to_load = fopen(filename, "r")) != NULL )
if ( (load_file("../bin/test", &test_file_1)) == 1)
BTW: It would be better to return the file as the return-value, unless you need the return-value for something else or there are other reasons not shown in the example.
Here is a simple program which pretty much does what you want.
int load_file(char *filename, FILE *file_to_load){
file_to_load = fopen(filename, "r");
if(file_to_load !=0)
return 1;
else
return 0;
}
int main(int argc, char *argv[]){
FILE file_to_load;
if(load_file(argv[1],&file_to_load) == 1)
printf("File exists\n");
else
printf("Error loading the given file\n");
}
I have taken the file as a command line argument and changed the error messages but you can alter it according to your requirements.
I created a function to print the contents of a file:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
where file is a global variable. GDB gives output as follows:
_IO_getc (fp=0x0) at getc.c:39
39 getc.c: No such file or directory.
(gdb) bt
#0 _IO_getc (fp=0x0) at getc.c:39
#1 0x000000000040075e in readFile ()
#2 0x00000000004006d4 in main ()
However, the file is present and I get the SEGFAULT after printing the contents of the file. It might be because the buffer here (c) is small but I am not sure. Also, I don't know how do I fix this even if that were the case. Can anyone suggest how do I proceed?
EDIT
I call the readFile function only once. Here is my calling function:
int main(int argc, char* argv[])
{
char * filename;
filename = argv[1];
readFile(filename);
printf("File Handler: %ld", (long)file);
fclose(file);
return 0;
}
You're passing in a filename that doesn't exist or for some other reason cannot be opened. Get rid of the segfault by checking for errors (you'll need to #include <errno.h> and <string.h> too for this:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file '%s' : %s\n", filename, strerror(errno));
return;
}
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
Most likely your file is NULL and you are still trying to read it.
I simulated this behaviour (SEG fault) when I deleted this file.
If file exists then your code works fine.
Check what path you are passing.. If you are using single \ try with \\ and see if this works. First \ will work as escape sequence and final path will be send as D:\temp\use.dat to fopen.
readFile("D:\\temp\\user.dat");
Before you do anything with a file, you must ensure that you opened it successfully. This is done by checking that the file pointer received by calling fopen is not NULL.
Once you do this, you read using whatever function you choose until it returns a value that indicates failure to read — a NULL pointer for fgets, 0 or EOF for fscanf, or EOF for fgetc.
In any case, you challenge these return values in two ways. The first way is to check for read errors using ferror. The other way is to check whether the end of the file was reached using feof.
A complete program that should work, based upon your code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
enum { OPEN_ERROR = 1, READ_ERROR };
enum { PARAM_EXIT = 1, OPEN_EXIT, READ_EXIT };
FILE *file = NULL;
int readFile(char* filename)
{
int c;
file = fopen(filename, "r");
if (file == NULL)
return OPEN_ERROR;
printf("The contents of file '%s' are:\n", filename);
while((c = fgetc(file)) != EOF)
printf("%c", c);
/*
* fgetc returns EOF on end of file and when an error occurs.
* feof is used to determine whether the end of the file was reached.
* Otherwise, we encountered a read error.
*/
if (feof(file))
c = 0;
else
c = READ_ERROR;
return c;
}
int main(int argc, char *argv[])
{
int status = 0;
if (argc == 1) {
fprintf(stderr, "usage: %s file\n", argv[0]);
return PARAM_ERROR;
}
/* Check that <program ""> wasn't used... */
if (argv[1][0] == '\0') {
fprintf(stderr, "error: empty filename detected, exiting. . .\n");
return PARAM_ERROR;
}
switch (readFile(argv[1])) {
case 0:
break;
case OPEN_ERROR:
fprintf(stderr, "error: file open failed - %s\n", strerror(errno));
status = OPEN_EXIT;
break;
case READ_ERROR:
fprintf(stderr, "error: file read failed - %s\n", strerror(errno));
status = READ_EXIT;
break;
default:
fprintf(stderr, "error: unknown error occurred, aborting...\n");
abort();
}
if (file != NULL)
fclose(file);
return status;
}
Of course, normally you would close the file in the same function in which it was opened (e.g. something like filep = openFile(...); readFile(filep); fclose(filep);, except error handling would be used of course).
I am completely changing my answer
Actually, the file that I was reading was open in gedit (which might explain why I was getting "NULL" even after printing the file contents. I closed the file and removed my NULL comparison code and it works perfectly fine.
Ok, from everybody's comments I got to know that you basically get a SEGFAULT when you read the contents of file that has NULL contents. I just made a simple fix in my while loop:
while((c != EOF))
{
printf("%c", c);
c = fgetc(file);
if(c == NULL)
break;
}
Problemo solved! (Although, the compiler gives me a warning of "comparison between pointer and integer".)
I wish I could i could give more information, but I genuinely have no idea what is going on here. This code opens files for appension or overwriting, depending on user arguments (appension by default). It gets as far as the fgets for user input, and then as soon as the input is entered, it segfaults and dumps core. This is strange, because before I implemented arguments (i.e. it was just ./a.out file) it worked fine, so I guess it has something to do with the new stuff about arguments...
#include <stdio.h>
#include <string.h>
int printhelp(void);
int main(int argc, char *argv[])
{
char input[256];
int loopstat = 0;
FILE *inputfile;
if (argc < 2) /* Check argc for minimum 2 arguments (i.e. cw FILE) */
{
printf("ca: missing file operand\n");
return 0;
}
else if (argc > 2) /* Check argc for more than 2 arguments (i.e. cw -o FILE) */
{
if (strncmp(argv[1], "-", 1) == 0) /* if first argument begins with "-", it must be an option, so descend into option checking */
{
if (strcmp(argv[1], "-a") == 0) /* If -a option is given, open for appending */
{
FILE *inputfile = fopen(argv[2], "a");
}
else if (strcmp(argv[1], "-o") == 0) /* If -o option is given, open for overwriting */
{
FILE *inputfile = fopen(argv[2], "w");
}
else if (strcmp(argv[1], "--help") == 0) /* If --help option is given, print help and quit */
{
printhelp();
return 0;
}
else
{
printf("cw: invalid option\n"); /* If invalid option is given, print the fact and quit*/
return 0;
}
}
}
else /* if argc is equal to 2 (i.e. "cw FILE" or "cw -o")...*/
{
if (strncmp(argv[1], "-", 1) == 0) /* Check if user has specified an option but no file (i.e. "cw -o") */
{
printf("cw: missing file operand\n"); /* If they have, print that no file is spec'd and quit */
return 0;
}
else /* If not, it's a legit file with no other arguments (e.g. "cw FILE") so open it in append mode by default */
{
FILE *inputfile = fopen(argv[2], "a");
}
}
/* Writing loop */
printf("Enter input...\n");
while (loopstat == 0) /* Get user input and write to file until they give exit command */
{
fgets(input, 256, stdin); /* Get user input */
if (strcmp(input, ":x\n") == 0) /* If input == exit command, quit */
{
printf("co: exit received, terminating...\n");
loopstat++;
}
else /* Write to file */
{
fprintf(inputfile, "%s", input);
}
}
fclose(inputfile);
}
int printhelp(void) /* Print help on --help command */
{
printf(
"Usage: ca FILE\nContinuously append input to the FILE\nca does not currently support multiple file appension.\nReport bugs to scamp#lavabit.com\n");
return 0;
}
P.S. sorry if I messed up the indentation, it's really confusing to have to add four spaces before everything in this much code.
Here you are shadowing your variable:
else /* If not, it's a legit file with no other arguments (e.g. "cw FILE") so open it in append mode by default */
{
FILE *inputfile = fopen(argv[2], "a");
}
should be
else /* If not, it's a legit file with no other arguments (e.g. "cw FILE") so open it in append mode by default */
{
inputfile = fopen(argv[2], "a");
}
You have several instances like this, so remove the declaration there as well.
You are declaring the identifier inputfile several times, but it won't be the same object at each time.
See the behavior of this program for instance (from Wikipedia):
#include <stdio.h>
int main(void)
{
char x = 'm';
printf("%c\n", x);
{
printf("%c\n", x);
char x = 'b';
printf("%c\n", x);
}
printf("%c\n", x);
}
You have to declare inputfile just once, and then assign it in if statements.
FILE *inputfile;
if (/* ... */)
inputfile = /* ... */
else if (/* ... */)
inputfile = /* ... */
else
inputfile = /* ... */
int main(int argc, char *argv[])
{
char input[256];
int loopstat = 0;
FILE *inputfile;
then you have:
if (strcmp(argv[1], "-a") == 0)
{
FILE *inputfile = fopen(argv[2], "a");
}
You should not redeclare a new object inputfile but reuse your inputfile declared at the top of your function.
Example:
inputfile = fopen(argv[2], "a");
The problem is there:
FILE *inputfile;
....
if (strcmp(argv[1], "-a") == 0)
{
FILE *inputfile = fopen(argv[2], "a");
}
By writing this way you are hiding the variable inputfile from the compiler. Thus the variable defined in the beginning stays uninitialized.
You should write it following way:
if (strcmp(argv[1], "-a") == 0)
{
inputfile = fopen(argv[2], "a");
}
So now you will use the variable defined in the top of the function.
You should read about the variable scope.