I am writing a program that reads from a file passed as an arguement, or reads from stdin if no arguements are given.
The code runs fine with a file passed, but I get a seg fault when no file is passed.
I basically call fopen on argv[1] if a file was given, but if no file was given I call:
f = fopen("stdin", "r");
Is this the correct syntax for opening stdin as a file?
When you start a program, the main() function is not the first thing that
get's called, quite a few things happen before the main() function is
called. One of those things is to open stdin, stdout and stderr. In
general you don't need to worry about the details how the OS does that, you
just can relay that when main() is executed, these streams are open and you
can use them.
So in your case, you can do this:
#include <stdio.h>
int main(int args, char **argv) {
FILE *fp;
if(args == 1) {
fp = stdin;
} else {
fp = fopen(argv[1], "r");
if(fp == NULL) {
fprintf(stderr, "Unable to open %s for writing\n", argv[1]);
return 1;
}
}
// do your read operations on fp
if(fp != stdin) {
fclose(fp);
}
return 0;
}
So when you call the program without arguments, stdin is used, otherwise a
file is used.
The reason why your code crashes is because
f = fopen("stdin", "r");
tries to open a file literally called stdin, which you most probably don't
have. fopen will return NULL and you probably don't check for that. If you
try to use a function that expects a FILE* pointer but pass NULL, then
you'll most likely will get a segfault.
USE f = stdin;
NOT f = fopen("stdin", "r");
I am trying to check if a file exists by opening it with fopen() and then checking if the function returns NULL. But when I run the code, it says a read access violation error accured, but I don't get why, since I checked and the file I am trying to read is txt and has text already written in it. Can someone explain why and how I can fix it?
int main(int argc, char** argv)
{
int quit = FALSE;
if (fopen(*(argv+2), 'r') == NULL)
{
printf("Invalid input! File does not exit.");
quit = TRUE;
}
}
First, from the fopen manual, we can see that the function signature is:
FILE *fopen(const char *pathname, const char *mode);
What this means is that it will return a pointer of type FILE, and expects two arguments, both pointers to char. The second argument you pass to fopen in your code is a char, not a char*, so we need to fix that. Also, store the returned fopen pointer, as you should use it to close the file after you're done with it.
So, your code would be something like:
FILE *fp;
if ((fp = fopen(argv[2], "r")) == NULL) {
printf("File does not exist!\n");
exit(0);
} else {
/* file exists... do stuff */
fclose(fp);
}
This is a really basic question but I can't find a definitive answer anywhere.
I understand the parameters of main, as far as what they refer to:
int main(int argc, char *argv[])
where argc refers to the number of command line arguments and argv refers to the array that holds each of the strings. I created an exe file of the source code from the .c file, but have no experience with command prompts and don't understand the syntax of the command line arguments.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *infile, *outfile;
int iochar;
if(argc != 3){
printf("Usage: filename infile outfile\n");
exit(1);
}
if((infile = fopen(argv[1], "r")) == NULL){
printf("Can't open input file.\n");
exit(1);
}
if((outfile = fopen(argv[2], "w")) == NULL){
printf("Can't open output file.\n");
exit(1);
}
while((iochar = getc(infile))!=EOF){
putc(iochar, outfile);
}
fclose(infile);
fclose(outfile);
printf("You've reached the end of the program.\n");
return;
}
The preceding code should take 3 arguments and copy the 2nd argument's contents into the 3rd argument's location. What do I have to do for this to happen?
You can set the command line arguments in the Debug properties of your VS project.
don't understand the syntax of the command line arguments.
The details of the syntax of the command line arguments depends on what program is interpreting them ... VS, a Windows shortcut, Windows cmd, bash, etc. ... but generally it's just a list of items separated by spaces. If the items themselves contain spaces, quotes, or other special characters, then you need to pay attention to the rules of the interpreter you're using.
The semantics of the command line arguments is defined by your program ... in this case, the first argument is the name of the input file and the second argument is the name of the output file.
printf("Usage: filename infile outfile\n");
This is not a good usage message ... the "filename" should be the name of your program, which is generally the value of argv[0]. Thus:
printf("Usage: %s infile outfile\n", argv[0]);
Dear respected programmers. Please could you help me (again) on how to put the following code into functions for my program.
I have read on-line and understand how functions work but when I do it myself it all goes pear shaped/wrong(I am such a noob).
Please could you help with how to for example to write the code below into functions.(like opening the input file).
My initial code looks like:
main (int argc, char **argv)
{
int bytes_read, bytes_written;
struct stat inode;
int input_fd, output_fd;
char buffer[64];
int eof = 0;
int i;
/* Check the command line arguments */
if (argc != 3)
{
printf("syntax is: %s \n", <fromfile> <tofile>\n", argv[0]);
exit (1);
}
/* Check the input file exists and is a file */
if ((stat(argv[1], &inode) == -1) || (!S_ISREG(inode.st_mode)))
{
printf("%s is not a file\n", argv[1]);
exit(2);
}
/* Check that the output file doesnt exist */
if (stat(argv[2], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[2]);
exit(2);
}
/* Open the input file for reading */
input_fd = open(argv[1], O_RDONLY, 0);
if (input_fd == -1)
{
printf("%s cannot be opened\n", argv[1]);
exit(3);
}
output_fd = open(argv[2], O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if (output_fd == -1)
{
printf("%s cannot be opened\n", argv[2]);
exit(3);
}
/* Begin processing the input file here */
while (!eof)
{
bytes_read = read(input_fd, buffer, sizeof(buffer));
if (bytes_read == -1)
{
printf("%s cannot be read\n", argv[1]);
exit(4);
}
if (bytes_read > > 0)
{
bytes_written = write(output_fd, buffer, bytes_read);
if (bytes_written == -1)
{
printf("There was an error writing to the file %s\n",argv[2]);
exit(4);
}
if (bytes_written != bytes_read)
{
printf("Devistating failure! Bytes have either magically appeared and been written or dissapeard and been skipped. Data is inconsistant!\n");
exit(101);
}
}
else
{
eof = 1;
}
}
close(input_fd);
close(output_fd);
}
My attempt at opening an output file:
void outputFile(int argc, char **argv)
{
/* Check that the output file doesnt exist */
if (stat(argv[argc-1], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]);
return -1;
}
/*Opening ouput files*/
file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if(file_desc_out == -1)
{
printf("Error: %s cannot be opened. \n",argv[i]); //insted of argv[2] have pointer i.
return -1;
}
}
Any help on how I would now reference to this in my program is appreciated thank you.
I tried:
ouputfile (but I cant figure out what goes here and why either).
Maybe the most useful function for you is:
#include <stdio.h>
#include <stdarg.h>
extern void error_exit(int rc, const char *format, ...); /* In a header */
void error_exit(int rc, const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(rc);
}
You can then write:
if (stat(argv[2], &inode) != -1)
error_exit(2, "Warning: The file %s exists. Not going to overwrite\n",
argv[2]);
Which has the merit of brevity.
You write functions to do sub-tasks. Deciding where to break up your code into functions is tricky - as much art as science. Your code is not so big that it is completely awful to leave it as it is - one function (though the error handling can be simplified as above).
If you want to practice writing functions, consider splitting it up:
open_input_file()
open_output_file()
checked_read()
checked_write()
checked_close()
These functions would allow your main code to be written as:
int main(int argc, char **argv)
{
int bytes_read;
int input_fd, output_fd;
char buffer[64];
if (argc != 3)
error_exit(1, "Usage: %s <fromfile> <tofile>\n", argv[0]);
input_fd = open_input_file(argv[1]);
output_fd = open_output_file(argv[2]);
while ((bytes_read = checked_read(input_fd, buffer, sizeof(buffer)) > 0)
check_write(output_fd, buffer, bytes_read);
checked_close(input_fd);
checked_close(output_fd);
return 0;
}
Because you've tucked the error handling out of sight, it is now much easier to see the structure of the program. If you don't have enough functions yet, you can bury the loop into a function void file_copy(int fd_in, int fd_out). That removes more clutter from main() and leaves you with very simple code.
Given an initial attempt at a function to open the output file:
void outputFile(int argc, char **argv)
{
/* Check that the output file doesnt exist */
if (stat(argv[argc-1], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]);
return -1;
}
/*Opening ouput files*/
file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if(file_desc_out == -1)
{
printf("Error: %s cannot be opened. \n",argv[i]); //insted of argv[2] have pointer i.
return -1;
}
}
Critique:
You have to define the variables used by the function in the function (you will want to avoid global variables as much as possible, and there is no call for any global variable in this code).
You have to define the return type. You are opening a file - how is the file descriptor going to be returned to the calling code? So, the return type should be int.
You pass only the information needed to the function - a simple form of 'information hiding'. In this case, you only need to pass the name of the file; the information about file modes and the like is implicit in the name of the function.
In general, you have to decide how to handle errors. Unless you have directives otherwise from your homework setter, it is reasonable to exit on error with an appropriate message. If you return an error indicator, then the calling code has to test for it, and decide what to do about the error.
Errors and warnings should be written to stderr, not to stdout. The main program output (if any) goes to stdout.
Your code is confused about whether argv[i] or argv[argc-1] is the name of the output file. In a sense, this criticism is irrelevant once you pass just the filename to the function. However, consistency is a major virtue in programming, and using the same expression to identify the same thing is usually a good idea.
Consistency of layout is also important. Don't use both if( and if ( in your programs; use the canonical if ( notation as used by the language's founding fathers, K&R.
Similarly, be consistent with no spaces before commas, a space after a comma, and be consistent with spaces around operators such as '|'. Consistency makes your code easier to read, and you'll be reading your code a lot more often than you write it (at least, once you've finished your course, you will do more reading than writing).
You cannot have return -1; inside a function that returns no value.
When you a splitting up code into functions, you need to copy/move the paragraphs of code that you are extracting, leaving behind a call to the new function. You also need to copy the relevant local variables from the calling function into the new function - possibly eliminating the variables in the calling function if they are no longer used there. You do compile with most warnings enabled, don't you? You want to know about unused variables etc.
When you create the new function, one of the most important parts is working out what the correct signature of the function is. Does it return a value? If so, which value, and what is its type? If not, how does it handle errors? In this case, you probably want the function to bail out (terminate the program) if it runs into an error. In bigger systems, you might need to consistently return an error indicator (0 implies success, negative implies failure, different negatives indicating different errors). When you work with function that return an error indicator, it is almost always crucial that you check the error indicators in the calling code. For big programs, big swathes of the code can be all about error handling. Similarly, you need to work out which values are passed into the function.
I'm omitting advice about things such as 'be const correct' as overkill for your stage in learning to program in C.
you seem to actually understand how to make a function. making a function really isnt that hard. first, you need to kind of understand that a function has a type. in otherwords, argc has type int and argv has type char *, your function (currently) has type void. void means it has no value, which means when you return, you return nothing.
however, if you look at your code, you do return -1. it looks like you want to return an interger. so you should change the top from void outputfile(...) to int outputfile(...).
next, your function must return. it wont compile if there is a circumstance where it won't return (besides infinite loops). so at the very bottom, if no errors happen, it will reach the end. since you're no longer using "void" as the return type, you must return something before the end of the function. so i suggest putting a return 1; to show that everything went great
There's several things.
The function return type isn't what you want. You either want to return a file descriptor or an error code. IIRC, the file descriptor is a nonnegative int, so you can use a return type of int rather than void. You also need to return something on either path, either -1 or file_desc_out.
You probably don't want to pass in the command-line arguments as a whole, but rather something like argv[argc - 1]. In that case, the argument should be something like char * filename rather than the argc/argv it has now. (Note that the argv[i] you've got in the last printf is almost certainly wrong.)
This means it would be called something like
int file_desc_out = outputFile(argv[argc - 1]);
You need to have all variables declared in the function, specifically inode and file_desc_out.
Finally, put an extra level of indentation on the code inside the { and } of the function itself.
I use _fsopen(path, "r+", _SH_DENYRW) for opening a file in C any parameter for protection (_SH_...) cause the same issue.
When opening an empty file, errno is set to 22 (EINVAL), not so when the file isn't empty - then all is OK. What can I do?
The documentation implies that EINVAL would the result if one of the parameters were invalid. Since "r+" has to be a valid pointer, and assuming it compiled at all _SH_DENYRW has to be a valid flag, the only remaining question is whether your variable path is not NULL, points to memory that exists and can be read, and contains a valid path name.
I just tried the following:
#include <stdio.h>
#include <share.h>
int main(int argc, char **argv)
{
FILE *f;
if (argc != 2) {
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(1);
}
f = _fsopen(argv[1], "r+", _SH_DENYRW);
if (f) {
printf("Open ok.\n");
fclose(f);
} else {
perror(argv[1]);
}
return 0;
}
On files that exist and can be written, regardless of their size, it prints "Open ok.", meaning that _fsopen() succeeded. A couple of other cases:
A read-only file:
C:>fsopen ro.txt
ro.txt: Permission denied
No file:
C:>fsopen nosuchfile
nosuchfile: No such file or directory
A device file:
C:>fsopen NUL:
Open ok.
A zero-length file:
C:>fsopen zero.txt
Open ok.