Getopt and Optarg - c

Hi I am working on a Program in a book. The Program is working almost as it is supposed to, except for one mistake. Every time I try to use the "-l" case I get a Segmentation Fault. Any Ideas?
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char *lieferung = "";
int knusprig = 0;
int zahl = 0;
char ch;
while ((ch = getopt(argc, argv, "l : k")) != EOF){
switch (ch) {
case 'l':
lieferung = optarg;
break;
case 'k':
knusprig = 1;
break;
default:
fprintf(stderr, "Unbekannte Option: '%s'\n", optarg);
return 1;
}
}
argc -= optind;
argv += optind;
if (knusprig)
puts("Knuspriger Rand.");
if (lieferung[0])
printf("Zu liefern: %s.\n", lieferung);
puts("Zutaten:");
for (zahl = 0; zahl < argc; zahl++)
puts(argv[zahl]);
return 0;
}
Thanks in advance.

The third argument get getopt shouldn't contain any spaces. Because there are spaces, it reads this argument as "-l takes no argument, -(space) takes an argument, -(space) takes no argument, and -k takes no argument.
Since getopt doesn't expect -l to pass an argument, optarg is set to NULL, which you then subsequently assign to lieferung. You then dereference that variable, resulting in the segfault.
Git rid of the spaces in the format string:
while ((ch = getopt(argc, argv, "l:k")) != EOF){

I think the format is incorrect. Replace "l : k" with "l:k".

Related

Getopt not grabbing and storing my input in C

This is my first post on this site so please forgive any formatting errors.
I am coding a small program to get simple information from a file like amount of words, sorting it etc. However I started simply by using getopt since I want to use the command line to parse my commands. This is what I have so far.
#include <stdio.h>
#include <stdlib.h>
int value = 0;
int main(int argc, char **argv) {
extern char *optarg;
extern int optind;
int c, err = 0;
int cflag = 0, sflag = 0, fflag = 0;
char *substring;
// usage from instructions in case of error
static char usage[] = "usage: mywords [-cs] [-f substring] filename";
// only f flag requires additional input
while ((c = getopt(argc, argv, "csf:")) != -1)
switch (c) {
case 'c':
cflag = 1;
break;
case 's':
sflag = 1;
break;
case 'f':
fflag = 1;
printf("Before assigning to substring\n");
substring = optarg;
printf("After\n");
break;
case '?':
err = 1;
break;
}
if (fflag = 1) {
printf("%c ", &substring);
}
}
I will then input something like this to the command line after I run my makefile (which runs successfully with no errors):
mywords -f test
and ideally the output would be
test
The printf statements I have in the fflag are simple test prints to see if I was even reaching there. Thank you for your help in advance.
EDIT
It was fixed. David Collins had the right answer. Thank you so much everyone
I have noticed three issues in you code. (There may be other small issues but addressing the following should get you up and running I think.)
Testing for equality
You should use if (fflag == 1) instead of if (fflag = 1).
Pointer de-referencing
If you want to retrieve the value of the character pointed to by substring, you would use *substring instead of &substring.
But you probably don't want to do this. See below.
printf() format specifiers
When printing a string / character array, use the %s specifier instead of %c. (%c is for single characters). So you should have
if (fflag == 1) {
printf("%s ", substring);
}
Or - more simply - just
if (fflag) {
puts(substring)
}
since any non-zero value evaluates to true in C (and you initialize fflag to zero at the start of your program).

C getopt does not read all the parameters

I have an assignment in C that requires options to be read in for different forms of a program. Before I start on that, though, I want to make sure that the getopt portion is working fine. However, the program keeps dropping the last parameter and I don't know why. Whenever I enter the last char, the program goes to the default value that kills the program. Any help is appreciated!
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(int argc, char **argv)
{
int sFlag = 0;
int lFlag = 0;
int dFlag = 0;
int rFlag = 0;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "slr:")) != -1)
{
switch(c)
{
case 's':
sFlag = 1;
break;
case 'l':
lFlag = 1;
break;
case 'r':
rFlag = 1;
break;
default:
printf("unknown parameter introduced");
exit(-1);
break;
}
}
printf("s = %i, l = %i, d = %i, r = %i", sFlag, lFlag, dFlag, rFlag);
return 1;
}
The colon symbol after r in "slr:" tells getopt() to wait for a mandatory argument which follows -r.
Examples:
getopt(argc, argv, "slr:") can parse ./project -s -l -r r_arg (or ./project -r r_arg -s etc.)
getopt(argc, argv, "s:lr:") can parse ./project -s s_arg -l -r r_arg
getopt(argc, argv, "s:lr:") can also parse ./project -s -l -r r_arg with no error, but the program works differently from user's expectation. This is because getopt() expects -s to be followed by its argument, however it looks like, so the next argument -l is consumed and will not hit your switch(c).

Segmentation fault when parsing command line arguments

I am getting a segmentation fault I am having trouble isolating the source of the fault. I believe that for some reason argv and argc are not getting values, but I cannot figure out why.
Here is the first part of my code.
int main(int argc, char **argv)
{
int i;
int numArrays = 0;
int test = 0;
int opt = 0;
printf ("Parsing....\n"); // This line gets printed
printf(argv); // this one doesn't even if being flushed immediately after
printf(argc); // when the previous line is deleted, this line also won't print
fflush(stdout);
opt = getopt(argc, argv, optString); // defined as optString = "qmc";
while (opt != -1) {
printf (opt);
switch (opt) {
//prevents program from printing to a file
case 'q':
tofile = 1;
break;
// max size of the prime numbers
case 'm':
maxPrime = atoi(optarg);
break;
case 'c':
numProcs = atoi(optarg);
break;
default:
break;
}
}
I'm tried to figure out what is going on, but I cannot see why argc and argv are not getting values. I have used this exact same parsing code before and it has worked perfectly. Usually segmentation faults are pretty easy (accessing memory locations you shouldn't be), but there is no reason I shouldn't have access to my command line arguments.
You are confused about how to use printf. What you're currently doing is a big no-no:
printf(argv);
printf(argc);
The function expects a const char* string that specifies the format of the output and optional variable argument list. You are passing a double-pointer, which is not a string, and an integer, which is not even a pointer!
You want something like this:
printf( "Number of arguments: %d\n", argc );
for( int i = 0; i < argc; i++ ) {
printf( "Arg %d: %s\n", i, argv[i] );
}
Read up on printf here: http://en.cppreference.com/w/c/io/fprintf

Command Line Argument C

I need help to display name to command line like this (I don't know how to explain) in C
$:Enter your name: Test
$:Test>
But when you continue press enter it still showing Test>
$:Test>
$:Test>
So how do we get argv[0] and do something like this (Sorry that I cannot explain probably)
Thank you
command line arguments are stored in char **argv, and there are argc of them.
int main(int argc, char **argv)
{
int i=0;
for(i=0; i< argc; i++)
printf("argument number %d = %s\n", i, argv[i]);
return 0;
}
argv[0] is the name of the program being executed, so argc is always at least == 1 ( or more)
If you had rather shell-like program in mind, maybe the following couldbe of use:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define BUFSIZE 64
int main() {
char prompt[BUFSIZE];
char command[BUFSIZE];
char *prefix = "$:";
char *suffix = ">";
printf("%s%s%s", prefix, "Enter your name:", suffix);
fgets(prompt, BUFSIZE, stdin);
prompt[strlen(prompt)-1] = '\0'; // get rid of the \n
while (true) {
printf("%s%s%s", prefix, prompt, suffix);
fgets(command, BUFSIZE, stdin);
if (strncmp(command,"Quit",4) == 0)
break;
}
return 0;
}
Whenever possible, you should use getopt() so that the order of your parameters doesn't matter. For example, suppose you wanted to take an integer parameter for the size, an integer for the mode of execution, and a toggle to indicate whether to run in "quiet mode" or not. Further suppose that "-h" should print help and exit. Code like this will do the trick. The "s:m:hq" string indicates that "-s" and "-m" provide parameters, but the other flags don't.
int main() {
// parse the command-line options
int opt;
int size = DEFAULT_SIZE, mode = DEFAULT_MODE, quiet = 0;
while ((opt = getopt(argc, argv, "s:m:hq")) != -1) {
switch (opt) {
case 's': size = atoi(optarg); break;
case 'm': mode = atoi(optarg); break;
case 'q': quiet = 1; break;
case 'h': usage(); return 0;
}
}
// rest of code goes here
}
Of course, you should add error checking in case optarg is null.
Also, if you're using C++, "string(optarg)" is an appropriate way for your case statement to set a std::string to hold a value that is stored as a char* in argv.

Am I understanding getopt() correctly?

I'm trying to scan the command line for certain letters, symbols and values. I want to scan for "-w", a number, and "-s". I got a response in my last question, I was told to use getopt() and after a little bit of Googling, I think I might get it, but I'm not sure.
This is what I think I'm doing:
int c = 0;
int b = argv[2];
while((c = getopt(argc, argv, "-w", "-s", b))
I think I'm scanning argc for "-w", "-s" and the argv[2] value (which is the number). But I do not know if I am using it correctly?
Your while loop should be
while ((c = getopt(argc, argv, "w:s:"))
: the colon means it needs an argument. now convert optarg to an integer or whatever you wanted.
int number = 0;
int sflag = 0;
int opt;
while ((opt = getopt(argc, argv, "w:s")) != -1)
{
switch (opt)
{
case 's':
sflag = 1;
break;
case 'w':
number = atoi(optarg);
break;
default:
/* Report usage and exit? */
break;
}
}
The conversion on the number is lazy; you can do more a more careful job calling a function that calls strtol(), for instance. You might need to have a wflag variable that you set analogously to the sflag variable so that you can distinguish -w 0 from 'no -w option specified on the command line'.

Resources