For this program I am supposed to either write my name to the terminal or to the output file given by the user(case 'f').
#include <stdio.h>
int main(int argc, char **argv)
{
// no output file print to screen, print name to terminal
if (argc < 2)
{
fprintf(stdout, "name\n");
}
//print name to output file given by user
else
{
int option;
int fFlag = 0;
while ((option = getopt(argc, argv, "f:")) != -1)
{
//if case 'f' print to output file
switch (option)
{
case 'f':
fFlag = 1; // flag indicates writing name to file
break;
//case f or error
case '?':
printf("error");
break;
}
}
//write to name to output file
if (fFlag)
{
FILE *file = fopen(argv[1], "w");
fprintf(file, "name");
}
}
return 0;
}
My code works when I want to write my name to the terminal, but it doesn't work when I want to write my name to the file given by the user. The code compiles and runs, but the file just doesn't exist.
The file in the command line might not already exist. Am I supposed to create the file in the program?
I understand what I was doing wrong. Thank you to everyone!
In addition to what the commenters have said, you are using getopt for part of your parsing so should use it for the rest!
int main...
char *filename; /**1**/
...
case 'f':
fFlag = 1;
filename = optarg; /**2**/
....
FILE *file = fopen(filename , "w"); /**3**/
Explanation: the f: to getopt means that getopt is going to try to find the option that goes along with the f. In the getopt loop, case 'f', that option is put in the variable optarg. At least for GNU getopt, that is a pointer into argv, so you don't have to copy it. You can just stash its pointer value (at *2* above) into a variable you have created for the purpose (*1*). Then you can open that particular file without regard to where it is in argv (*3*). See the treatment of option c in the GNU getopt example.
Edit You haven't shown the command line you're using, but I am guessing it's something like
./foo -f my-output-file.txt
— in which case argv[1] is -f and argv[2] is my-output-file.txt. (argv[0] is the name of your executable.) Hence fopen(argv[1], ...) is not what you want ;) .
Related
this is my main class that accepts a h or H command line parsing and should print the contents of a hexidecmal header
#include "p1-check.h"
int main (int argc, char **argv)
{
FILE *file;
elf_hdr_t h;
int c;
while ((c = getopt (argc, argv, ":if:hH")) != -1)
{
switch (c)
{
case 'h':
usage_p1(argv);
break;
case 'H':
file = fopen(optarg, "rb");
read_header(file, &h);
dump_header(h);
fclose(file);
break;
default:
return EXIT_SUCCESS;
break;
}
}
}
I have a program that takes in command line arguments and a path to an elf file and displays the content of them using a struct. The elf header file is set up to have 16 bytes. Of those bytes, every two bytes describes something else about the header (version, entry point, etc) and the last four bytes hold a magic number that tells you it's the end of the file. The bytes are all in hex.
bool read_header (FILE *file, elf_hdr_t *hdr)
{
if (hdr != NULL && file != NULL && fread(hdr, sizeof(*hdr), 1, file) == 1)
{
fread(hdr, sizeof(*hdr), 1, file);
if (hdr->magic == 0x00464C45)
{
return true;
}
}
return false;
}
H option isn't followed by : so it doesn't accept an argument.
So optarg is not the elf filename you're expecting but rather a NULL or invalid pointer.
From the man page:
optstring is a string containing the legitimate option characters.
If such a character is followed by a colon, the option requires an
argument, so getopt() places a pointer to the following text in the
same argv-element
And since you're not checking the return value of fopen for NULL (which is probably is, as the file could not be opened), you're invoking undefined behaviour, when you're opening the file or when you're reading a null handle
To enable an argument for H option add a colon:
getopt (argc, argv, ":if:hH:"))
I'd also check how you're reading your elf header, as there are 2 fread calls, one in the test and one inside the condition.
I'm making a part of a bigger program, this part takes in information from a text file or a feed of standard input, the nature of this information depends on what option is added to the program. With no text file added as a non-option argument, the program should read from stdin.
For example:
fizzle.exe -a textfile.txt reads textfile.exe in the way prescriped by the option -a
fizzle.exe -a reads stdin in the way prescribed by the option a
What I havent gotten to work yet is:
fizzle.exe textfile.txt reading textfile.txt(or stdin if no proper text file) in the way prescribed by giving no option
This is my code:
while ((option = getopt(argc,argv, ":a:b:")) != -1 ) {
FILE *pointerFile = filereader(optarg);
switch(option) {
case 'a' :
optionchosen = 0;
counter(optionchosen,pointerFile,argv);
break;
case 'b' :
optionchosen = 1;
counter(optionchosen,pointerFile,argv);
break;
case ':' :
counter(optionchosen,pointerFile,argv);
break;
}
}
I cant figure out how to add a case to this switch that is activated by giving no option, but still works with or without the non-option argument(filename).
Well, you can do exactly what you want to do with getopt, and more, you just need to adjust your logic slightly. Specifically, you can setup getopt so that:
fizzle.exe /* reads from stdin */
fizzle.exe -a /* reads from stdin */
fizzle.exe -a textfile.txt /* reads textfile.txt */
fizzle.exe textfile.txt /* reads textfile.txt */
Here is a short example of implementing the above logic around the -a option. The last case also specifies that, if give, the first unhandled option after all options are given will also be taken as the filename to read.
#include <stdio.h>
#include <unistd.h> /* for getopt */
int main (int argc, char **argv) {
int opt;
char *fn = NULL;
FILE *pointerFile = stdin; /* set 'stdin' by default */
while ((opt = getopt (argc, argv, "a::b:")) != -1) {
switch (opt) {
case 'a' : /* open file if given following -a on command line */
if (!optarg) break; /* if nothing after -a, keep stdin */
fn = argv[optind - 1];
pointerFile = fopen (fn, "r");
break;
case 'b' :; /* do whatever */
break;
default : /* ? */
fprintf (stderr, "\nerror: invalid or missing option.\n");
}
}
/* handle any arguments that remain from optind -> argc
* for example if 'fizzle.exe textfile.txt' given, read from
* textfile.txt instead of stdin.
*/
if (pointerFile == stdin && argc > optind) {
fn = argv[optind++];
pointerFile = fopen (fn, "r");
}
printf ("\n fizzle.txt reads : %s\n\n", pointerFile == stdin ? "stdin" : fn);
return 0;
}
Example Use/output
$ ./bin/optfizzle
fizzle.exe reads : stdin
$ ./bin/optfizzle -a
fizzle.exe reads : stdin
$ ./bin/optfizzle -a somefile.txt
fizzle.exe reads : somefile.txt
$ ./bin/optfizzle someotherfile.txt
fizzle.exe reads : someotherfile.txt
Look it over and let me know if you have any questions.
Forget the leading : in your getopt string; just use getopt for options. After you're done with them, the remaining elements on the command line, if any, are found between argv[optind] and argv[argc].
If the caller provides no filename, use /dev/stdin as the default, or stdin from stdlib.h. No need to require the user to provide a - to stand in for standard input.
Programs using getopt should, by convention, read from stdin if you give it a - as an input parameter.
As a side note, you should always have a case for ? (or a default case).
Here is an example of reading the remaining arguments, place it below the big while loop where you process all getopt flags:
int i;
for (i = optind; i < argc; ++i)
printf("Non-option argument %s\n", argv[i]);
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]);
The title doesn't really do this topic justice. It's actually quite simple, my problem that is. I have a program (code below) written in the C language. I want this program to create an exe file that can be ran through the command prompt console window and that will also take a text file as a parameter. So, long story short; I need it to say this on the command line in CMD:
C:\Users\Username\Desktop\wrapfile.exe content.txt
My only problem is getting the code right. I want to tell Visual Studio: "The file you should open is given in the command prompt window as a parameter, there is no set location..."
How do I do that?
Here is my working code (Although you will have to change a few things in the *fp definition.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp; // declaring variable
fp = fopen("c:\\users\\*Put you're PC username here*\\Desktop\\contents.txt", "rb"); // opens the file
if (fp != NULL) // checks the return value from fopen
{
int i;
do
{
i = fgetc(fp); // scans the file
printf("%c",i);
printf(" ");
}
while(i!=-1);
fclose(fp);
}
else
{
printf("Error.\n");
}
}
Thanks everyone!
As Ken said above, the arguments of the main method are the values that you pass in from the command line. Argc is 'argument count' and argv is 'argument values'. So to open the fist argument passed in from the command line, change
fp = fopen("c:\\users\\*Put you're PC username here*\\Desktop\\contents.txt", "rb"); // opens the file
to
fp = fopen(argv[1],"rb");
Just make sure to do error checking (ie argv[1] is not null) before you try to fopen the input. Also FYI, in your case argv[0] will be the name of your executable.
I'm new to C and I'd like to ask about running a C program and supplying input at the same time.
What I would like to do is run a program (ex. fileOpener) and also state which file to open
./fileOpener < filename1
I've tried it already and it works fine, but what do I use to know what filename1 is? That way I can open the file with
fp = fopen(filename1, "r")
Thanks.
Edit: OK, I'll try to explain a bit more. If there wasn't a "<" then I could just use command line arguments as I have done before, but when I tried it with the <, it didn't work
Specifically: fileOpener code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
printf("%s", argv[1]);
}
when I use ./fileOpener < filename1 the output is ./fileOpener
I used gcc -o fileOpener fileOpener.c as the compiler
int main(int argc, char *argv[])
You can name them whatever you want, but these are the normal names.
argc is non-negative. It gives the number of useful elements in argv.
If argc is positive, argv[0] contains the program name. Then argv[1] through argv[argc - 1] point to character arrays that contain the program's command line arguments.
For example, if I run a program at the command line, such as
unzip filename.zip
argc will equal 2; and argv[0] will compare equal to "unzip"; and argv[1] will compare equal to "filename.zip".
Source
You can't do that, if you use redirection (i.e. "< filename") the file is opened by the system. You could discover the name, but it's non-portable, and anyway useless since the file is already open. Just use stdin instead of fp, and you need not use fopen() (nor fclose()):
int main()
{
char buffer[1024];
// fgets() reads at most 1024 characters unless it hits a newline first
// STDIN has been already opened by the system, and assigned to data flowing
// in from our file ( < inputFile ).
fgets(buffer, 1024, stdin);
printf("The first line of input was: %s", buffer);
}
A different approach is to use arguments:
int main(int argc, char **argv)
{
FILE *fp = NULL;
char buffer[1024];
if (argc != 2)
{
fprintf(stderr, "You need to specify one argument, and only one\n");
fprintf(stderr, "Example: %s filename\n", argv[0]);
// Except that argv[0], this program's name, counts.
// So 1 argument in command line means argc = 2.
return -1;
}
printf("I am %s. You wanted to open %s\n", argv[0], argv[1]);
fp = fopen(argv[1], "r");
fgets(buffer, 1024, stdin);
printf("The first line of input was: %s", buffer);
fclose(fp); fp = NULL; // paranoid check
return 0;
}
You need setup your program to take a command line argument. Here's a good tutorial that solves your exact question:
http://www.cprogramming.com/tutorial/c/lesson14.html
A program's main function in C has two arguments:
int main(int nArgs, char *pszArgs[]) {}
That first argument tells the program how many parameters were passed onto the program when you ran it. Usually, this will just be 1, because it includes the program's name.
The second argument is a table of strings, which can be accessed thus (the program below prints the parameters given to it):
int main(int nArgs, char *pszArgs[])
{
int i = 0;
while (i < nArgs)
{
printf("param %d: %s\n", i, pszArgs[i]);
i++;
}
return 0;
}