I am writing a simple program which takes the arguments form the user and process them.
I have the arguments in the argv which is two dimensional array. But when i ran the program, i get the garbage value and the segmentation fault error. I have tried with using argc as terminating condition and it works. But i want to do it using the pointer only.
What am doing wrong with pointer here.
#include<stdio.h>
int main( int argc, char *argv[])
{
while (++(*argv))
{
if ( **argv == '-' )
{
switch (*argv[1])
{
default:
printf("Unknown option -%c\n\n", (*argv)[1]);
break;
case 'h':
printf("\n option h is found");
break;
case 'v':
printf("option V is found");
break;
case 'd':
printf("\n option d is found");
break;
}
}
printf("\n outside while : %s", *argv);
}
}
program run as:
./a.out -h -v -d
Thank you
If you want to iterate through program arguments looking for the terminating null pointer, your outer cycle should be
while (*++argv)
not the
while (++*argv) // <- incorrect!
that you have in your code.
Your switch expression is written incorrectly. While your intent is clear, your implementation ignores operator precedence.
This
switch (*argv[1]) { // <- incorrect!
should actually be
switch ((*argv)[1]) {
The previous if
if (**argv == '-')
is fine, but since it is equivalent to
if ((*argv)[0] == '-') // <- better
maybe you should rewrite it that way as well, just for consistency with switch.
Your ultimate problem is operator precedence. Don't try to be clever when it's unnecessary. The * operator does not work as you think it does. I've rewritten your code using [0] instead, and now it works:
#include <stdio.h>
int main(int argc, char *argv[])
{
while ((++argv)[0])
{
if (argv[0][0] == '-' )
{
switch (argv[0][1]) {
default:
printf("Unknown option -%c\n\n", argv[0][1]);
break;
case 'h':
printf("\n option h is found");
break;
case 'v':
printf("option V is found");
break;
case 'd':
printf("\n option d is found");
break;
}
}
printf("\n outside while : %s", argv[0]);
}
}
argv is an array of strings. argv[0] is the program name which in your case is a.out. Your options start from argv[1]. So you need to iterate argv from 1 to argc-1 to get the options.
Also see here: Parsing Program Arguments
Related
Obligatory total noob here.
I am making a simple C program that reads some variables from a file from a simple function.
What I'm trying to accomplish, however, is to allow whoever calls the program to override the values read from the file if hey so specify in the command line arguments.
I would like to have something like this:
char* filename;
int number;
...
readConfig(filename, number, ...);
if (argc > 1) {
// Check if the variables were in the args here, in some way
strcpy(filename, args[??]);
number = atoi(args[??]);
}
I would like the program to be called as
program -filename="path/to/file.txt" -number=3
I figured out I could just tokenize each argument and match it to every assignable variable and discard the others, but I'm pretty sure that there's a more elegant way to do this (perhaps with getopts?)
Thank you so much for your help.
I found this on geeksforgeeks:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int opt;
// put ':' in the starting of the
// string so that program can
//distinguish between '?' and ':'
while((opt = getopt(argc, argv, ":if:lrx")) != -1)
{
switch(opt)
{
case 'i':
case 'l':
case 'r':
printf("option: %c\n", opt);
break;
case 'f':
printf("filename: %s\n", optarg);
break;
case ':':
printf("option needs a value\n");
break;
case '?':
printf("unknown option: %c\n", optopt);
break;
}
}
// optind is for the extra arguments
// which are not parsed
for(; optind < argc; optind++){
printf("extra arguments: %s\n", argv[optind]);
}
return 0;
}
So, when you pass -f, you need to also pass filename, like: ./args -f filename it will say:
$ ./a.out -f file.txt
filename: file.txt
When you pass -i, -l, or -r, or -ilr, it will say:
$ ./a.out -ilr
option: i
option: l
option: r
If you pass -f but without a filename, it will say option needs argument. Anything else will be printed to extra arguments
So, with it, you can add options to getopts, add new case, do a thing, like:
getopts(argc, argv, ":fn:")
-f filename, -n number, pretty easy
I am currently working with the function getopt(). I am implementing a program that is similar to the 'ls' command in Unix.
Everything seems to work correctly, however, if say I have a file named "-xyz",and pass the filename as argument, getopt() doesn't treat it as a file/dir.
For example, if i type: ./myprogram -i Makefile -xyz, I expect the function to treat -xyz as a file/dir but instead it tries to treat it as options.
Here is my code:
while((choice = getopt(argc, argv, "ilR")) != -1){
switch(choice) {
case 'i':
opt->option_i = 1;
break;
case 'l':
opt->option_l = 1;
break;
case 'R':
opt->option_R = 1;
break;
default:
exit(1);
}
}
Thank you
I am attempting to parse a command line argument, which in turn will execute an associated case within a switch statement. When I parse an integer argument (as seen in the code below), the associated case executes correctly. When I attempt to parse a string such as "CPU", I do not get the correct output.
Functioning code (parsing an integer e.g. an argument of 4 gives athe correct output of hello):
#include <stdio.h>
int main(int argc, char *argv[]) {
char execution_mode = atoi (argv[1]);
switch (execution_mode)
{
case (4) :
printf("Hello");
getchar();
break;
case (8) :
printf("Goodbye");
getchar();
break;
default:
printf("Error! execution mode is not correct");
getchar();
break;
}
return 0;
}
My attempt at parsing a string e.g. the argumentCPU:
#include <stdio.h>
int main(int argc, char *argv[]) {
typedef enum MODE { CPU, OPENMP } MODE;
MODE execution_mode = (char)argv[1];
switch (execution_mode)
{
case (CPU) :
printf("Hello");
getchar();
break;
case (OPENMP) :
printf("Goodbye");
getchar();
break;
default:
printf("Error! execution mode is not correct");
getchar();
break;
}
return 0;
}
You cannot convert a string to an enumerate like this. What you're doing is just converting the pointer to the string to char. Which fails.
One alternative (besides comparing first argument with strcmp) to avoid this would be to give a character value to your enumerates:
typedef enum { CPU='C', OPENMP='O' } MODE;
and now you can pick the first letter of the first argument and convert it:
MODE execution_mode = (MODE)argv[1][0];
The letters must be of course all different. And check argc>1 to see if argv[1] is valid, of course
If you want full string match, you have no other choice than using strcmp:
const char *execution_mode = argv[1];
if (strcmp(execution_mode,"CPU")==0)
{
// do something
}
else if (strcmp(execution_mode,"OPENMP")==0)
{
// do something else
}
With the help of the users who have answered this question, I have found a working solution by using strcmp as seen below. I have also added some error checking to ensure enough arguments have been enterred on the command-line.
#include <stdio.h>
int main(int argc, char *argv[]) {
//Ensure there are enough arguments
if (argc < 2)
{
printf("Error: not enough arguments");
exit(1);
}
typedef enum MODE { CPU, OPENMP, CUDA, ALL } MODE;
MODE execution_mode = (MODE)argv[1];
//Compare string with command-line arguments
if (strcmp("CPU", execution_mode) == 0)
{
//selects CPU case
execution_mode = CPU;
}
else if (strcmp("OPENMP", execution_mode) == 0)
{
//selects OPENMP case
execution_mode = OPENMP;
}
else
{
printf("invalid arg");
}
//Switch statement
switch (execution_mode)
{
case (CPU) :
printf("CPU MODE SELECTED");
getchar();
break;
case (OPENMP) :
printf("OPENMP MODE SELECTED");
getchar();
break;
default:
printf("Error: execution mode is not correct");
getchar();
break;
}
return 0;
}
I'm trying to assign a specific value of char array (or string) through conditionals depending on the value of char.
Suppose c is a char declared before the code with a specific value of some sort.
char fruit[];
if (c == 'R') {
fruit[] = "Red";
}
else if (c == 'Y') {
fruit[] = "Yellow";
}
else if (c == 'G') {
fruit[] = "Green";
}
else if (c == "B") {
fruit[] = "Blue";
}
This code is obviously wrong but should give an idea on what I'm trying to do.
I am either planning to use a correct version of this for a simple program or have to go through around four times more conditionals to manually print the said string values which would be an immense pain.
char *color; // for modern compilers, should be const char *color
switch (c)
{
case 'R': color = "Red"; break;
case 'Y': color = "Yellow"; break;
case 'G': color = "Green"; break;
case 'B': color = "Blue"; break;
default: color = "<unknown>"; break;
}
I took exception at illogical variable names so renamed fruit to color, but this approach is one way to achieve what I think you are asking.
The best way to do this would be to use a switch statement, but you'll first need to tell the compiler how big you want fruit[] to be, if you're not going to allocate it dynamically based on the character you detect.
Unless you're going to be dealing with fruits that have colors with really long names, I'd say 16 characters is enough for a demonstration. Hence:
#include <stdio.h>
#include <string.h>
void fruity_printer(char c) {
char fruit[16] = { 0 }; // initialize your arrays!
Now, a simple switch statement on char c
switch (c) {
case 'R':
strcpy(fruit, "Red");
break;
// add more cases as needed
default: // what happens if we don't have a case for it?
strcpy(fruit, "Rainbow");
break;
}
printf("The fruitabulous color is: %s\n", fruit);
return;
}
Note that I've used strcpy() here, because I'm sure that I know that I'll be writing within bounds of the destination. You'd never just arbitrarily copy something where the length wasn't known at compile time like that, you'd use strncpy() instead, which takes another argument for length.
Things you'll also want to do is convert c in the fruity printer to either upper or lower, so you don't have to deal with both cases.
Another way would be to allocate your memory dynamically, but the semantics of figuring out what it should be are still best served by just using a simple switch.
You can use switch case to that:
#include<stdio.h>
#include<string.h>
int main (int argc, char *argv[])
{
char c;
char fruit[100];
printf("Enter the character: ");
scanf(" %c",&c);
switch(c)
{
case 'R' : strcpy(fruit,"Red"); break;
case 'Y' : strcpy(fruit,"Yellow"); break;
case 'G' : strcpy(fruit,"Green"); break;
case 'B' : strcpy(fruit,"Blue"); break;
default : puts("No color");
}
printf("%s\n",fruit);
}
I wanted to use getopt() to parse arguments supplied at the command line, but I am having trouble with very simple test cases. I have the following code (which is almost, but not entirely identical, to that supplied as an example in the POSIX standard definition).
int main(int argc, char *argv[]) {
int c;
int rmsflg = 0, saflg = 0, errflg = 0;
char *ifile;
char *ofile;
//Parse command line arguments using getopt
while (((c=getopt(argc,argv, ":i:rso:")) != 1) && (errflg == 0)) {
switch(c){
case 'i':
ifile="optarg";
break;
case 'o':
ofile="optarg";
break;
case 'r':
if (saflg)
errflg++;
else {
rmsflg++;
printf("Root Mean Square averaging selected\n");
}
break;
case 's':
if (rmsflg)
errflg++;
else {
saflg++;
printf("Standard Arithmetic averaging selected\n");
}
break;
case ':':
fprintf(stderr,"Option -%c requires an argument\n",optopt);
errflg++;
break;
case '?':
fprintf(stderr,"Option -%c is not a valid option\n",optopt);
errflg++;
break;
default:
fprintf(stderr,"The value of c is %c,\
the option that caused this error is -%c\n",c,optopt);
errflg++;
break;
}
}
if (errflg) {
fprintf(stderr, "usage: xxx\n");
exit(2);
}
return 0;
}
Firstly, when I don't have the default case in there, nothing is output. When I inserted the default case, and make it output the value that c has, I get ?. This is odd for 2 reasons. Firstly, and this is what bothers me most, why doesn't c then match the ? case which was specifically written to match this output, but rather drops through to the default case. Secondly, the output of optopt is (for my input) o. The ? character is only returned if the option supplied does not match any character in optstring.
In the while loop condition you should check the return value of getopt against -1 not 1. Then if you pass the option -? on the command line, it should be recognized.