Why optopt is 0? C - c

I don't understand why optopt is zero in my code when an option is recognized but is right when it goes to the '?'case. This is the code:
...
int opt;
while((opt = getopt(argc, argv, OPZIONI))!= -1){
switch(opt){
case 'h':{
printOption();
break;
}
case 'f':{
if(conf->socketname[0] == '\0'){
strncpy(conf->socketname, optarg, strlen(optarg));
}
else printf("Option %c have to been used one time\n", optopt);
break;
}
...
similar code here
...
case '?':{
printf("Option %c not recognised\n", optopt);
break;
}
In else of case f optopt is 0 and it is not printed, but in the case '?' is printed right.
Thank you for your help.

getopt() only sets the optopt variable in the case of an error that makes it return a '?' or ':'. It doesn't set it when it finds an expected option. So using it when getopt() returns 'f' is pointless; it's not going to have any meaningful value in that case.

Related

Trouble getting a switch function to loop properly

I'm writing a program to 'encrypt' an inputted string of text by using a switch statement to correlate the given character with a symbol, and output that symbol in the place of the character. I put it in a while loop, the idea being that it would loop the full switch function each time until the received character is EOF. On a guess, I believe it is looping through just the first character, because I don't advance the getchar() statement, but I'm not sure how to do that so any help would be greatly appreciated. I say this because if I use return instead of break, it closes the while loop and only takes that first letter, if I use a break then it spams the first 'encrypted' char.
#include <stdlib.h>
#include <stdio.h>
/* C program to encrypt a given text message, assuming all lowercase */
int main() {
int Input, Encrypted;
printf("Please type your message\n");
Input = getchar();
while (Input != EOF) {
switch (Input) {
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'");break;
return 0;
}
}
return 0;
}
The simplest solution would be to remove the line
Input = getchar();
and to replace the line
while (Input != EOF) {
with:
while ( (Input=getchar()) != EOF && Input != '\n' ) {
Alternatively, if you find this while condition too confusing, you could also use an infinite loop, instead, like this:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
switch ( c )
{
case 'a':printf("!"); break;
case 'b':printf("#"); break;
case 'c':printf("#"); break;
case 'd':printf("$"); break;
case 'e':printf("%%"); break;
case 'f':printf("^"); break;
case 'g':printf("&"); break;
case 'h':printf("*"); break;
case 'i':printf("`"); break;
case 'j':printf("~"); break;
case 'k':printf("-"); break;
case 'l':printf("_"); break;
case 'm':printf("="); break;
case 'n':printf("+"); break;
case 'o':printf("["); break;
case 'p':printf("{"); break;
case 'q':printf("]"); break;
case 'r':printf("}"); break;
case 's':printf(";"); break;
case 't':printf(":"); break;
case 'u':printf("|"); break;
case 'v':printf(","); break;
case 'w':printf("<"); break;
case 'x':printf("."); break;
case 'y':printf(">"); break;
case 'z':printf("'"); break;
}
}
return 0;
}
Note that most character sets (such as ASCII) store the characters a to z consecutively. With these character sets, you don't need the long switch statement. Instead, you can simplify it to the following:
#include <stdlib.h>
#include <stdio.h>
int main( void )
{
printf("Please type your message\n");
for (;;) //infinite loop, equivalent to while(true)
{
const char map[] = "!##$%^&*`~-_=+[{]};:|,<.>'";
int c;
c = getchar();
if ( c == EOF || c == '\n' )
break;
if ( 'a' <= c && c <= 'z' )
putchar( map[c-'a'] );
}
return 0;
}

Is there a way I can shorten this if statment?

I have this really large if statement and it does not look pleasing to the eye as well as not being as efficient as possible.
I'm making a program that (depending on the users input) runs a certain block of code, for example if the user inputs 'a' the program runs a code that adds something to a file etc. By the way this is in a do-while statement(I don't know if this is relevant though).
else if(ansr != 'a' && ansr != 'A' && ansr != 'r' && ansr != 'R' && ansr != 's' && ansr != 'S' && ansr != 'e' && ansr != 'E')
{
printf("Invalid input!\n");
}
As you can see this is a really long if statement and I would like it to be shorter. Thank you
Um, what an example, whatever.
Why don't you use strchr? strchr returns the pointer to a character in a string (if found), NULL otherwise.
else if (strchr("aArRsSeE", ansr) == NULL)
{
printf("Invalid input!\n");
}
I would go with:
switch(tolower(ansr)) {
case 'a':
case 'r':
case 's':
case 'e':
do_stuff();
break;
/* other cases here */
}
Or you can use more library functions such as:
if (strchr("ares", tolower(ansr)) {
do_stuff();
}
strchr function is searching for a given character in the given string and returns NULL if it is not there (or pointer to first occurrence of it, but it is not the use-case which we are interested in here)
This is assuming ansr is in the range of unsigned char or EOF. Otherwise the behavior of tolower is undefined.
To answer your question, I would personally use a switch statement. It is easy to use and easy to read. Another thing which would make your code slightly more readable is using toupper.
Here is an example:
#include <stdio.h>
#include <ctype.h>
int main ()
{
char inp = 'i';
char ansr = toupper(inp);
switch(ansr) {
case 'A' :
// Do something
break;
case 'R' :
// Do something
break;
case 'S' :
// Do something
break;
case 'E' :
// Do something
break;
default :
printf("Invalid input!\n");
}
return 0;
}
It looks like you're trying to write an else if case to catch input characters that you do not support. The else case is perfect for that kind of situation:
...
char input;
//get your input
if (input == 'A' || input == 'a')
DoA();
else if (input == 'R' || input == 'r')
DoR();
else if (input == 'S' || input == 's')
DoS();
else if (input == 'E' || input == 'e')
DoE();
else
DoInvalidInput();
Or if you use tolower() you can put that in a switch statement:
char lowerChar = tolower((unsigned char)input);
switch (lowerChar)
{
case 'a': DoA(); break;
case 'r': DoR(); break;
case 's': DoS(); break;
case 'e': DoE(); break;
default: DoInvalidInput(); break;
}
Depending on if the case of the ansr is important, converting to lowercase before the if statement would half the amount of checks needed.

Problems using getopt in C

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.

switch case for parsing options

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

Using getopt for required arguments

I currently have code that looks like this:
while (( flags = getopt(argc, argv, "abc")) != -1){
switch(flags){
case 'a':
dflag = 1;
break;
case 'b':
rflag = 1;
break;
case 'c':
cflag = 1;
break;
}
}
The problem is I wanted to include something like testprogram -c -d 1
Where c is required to handle the -d, without -c, testprogram -d 1 will just run without arguments.
I tried a large variety of things and I just can't seem to get this to work.
Any help would be appreciated.
I think there are two options available to you, one of which will work and one of which may or may not work.
The 'may or may not work' option would be exemplified by:
char *opts = "abc";
char *opts_d = "abcd:";
while ((opt = getopt(argc, argv, opts)) != -1)
{
switch (opt)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cflag = 1;
opts = opts_d;
break;
case 'd':
dflag = 1;
dvalue = optarg;
break;
default:
...error handling...
break;
}
}
I'm not sure whether there's anything that prohibits you from changing the list of valid options on successive calls to [getopt()][1], but I do know it is not normally done to change the options as you go. So, treat with caution. Note that if the -c option is never found, the opt value of d will never be returned by getopt(), so that code will not be executed otherwise. Note that if the user enters a -d option before the -c, getopt() will report an invalid option when it processes the -d. You can control the error reporting; you would probably have to. (The optopt variable contains the actual option letter that was encountered as invalid.)
The 'will work' option is:
while ((opt = getopt(argc, argv, "abcd:")) != -1)
{
switch (opt)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cflag = 1;
break;
case 'd':
if (cflag == 0)
...report error about must use -c option before -d option...
dflag = 1;
dvalue = optarg;
break;
default:
...error handling...
break;
}
}

Resources