Segmentation fault when parsing command line arguments - c

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

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).

Multiple integer arguments with getopt?

What is the best way to handle multiple integer arguments while using getopt? I have to be able to enter something like this on the command line: calc -a 100 50 and it will add up 100 and 50.
while ((opt = getopt(argc, argv, "adms")) != -1)
{
value = atoi(argv[optind + 1]);
printf("value : %d\n", value);
switch (opt)
{
case 'a': aFlag = 1; num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
break;
case 'd': dFlag = 1;
break;
case 'm': break;
case 's': break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}
if (aFlag == 1)
{
num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
}
if (dFlag == 1)
{
num2 = atoi(argv[optind]);
sub = num2 / value;
printf("%d / %d = %d\n" , num2, value, sum);
}
I think that the interface you're after is probably:
./program -a 100 50
which accepts a single option -a (alternatives -m, -s and -d), and then processes the other arguments as a list of numbers, rather than as values attached to the option. This works fine unless you planned to be able to use:
./program -a 100 50 -m 20 30
to do addition and multiplication.
What do you want to do if someone can't make their mind up and tries:
./program -am 100 50
Should it be an error, or should -a or -m win? You can argue for any of those with some degree of coherency. I'd go with an error, though.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static int op_add(int a, int b) { return a + b; }
static int op_sub(int a, int b) { return a - b; }
static int op_mul(int a, int b) { return a * b; }
static int op_div(int a, int b) { return a / b; }
int main(int argc, char **argv)
{
int (*fun)(int, int) = 0;
char op;
int opt;
while ((opt = getopt(argc, argv, "adms")) != -1)
{
if (fun != 0)
{
fprintf(stderr, "%s: you can't use two operations\n", argv[0]);
return 1;
}
switch (opt)
{
case 'a': fun = op_add; op = '+'; break;
case 'd': fun = op_div; op = '/'; break;
case 'm': fun = op_mul; op = '*'; break;
case 's': fun = op_sub; op = '-'; break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}
if (fun == 0 || optind + 2 != argc)
{
fprintf(stderr, "Usage: %s [-adms] num1 num2\n", argv[0]);
return 1;
}
int res = fun(atoi(argv[optind]), atoi(argv[optind+1]));
printf("%s %c %s = %d\n", argv[optind], op, argv[optind+1], res);
return 0;
}
The error checking on the values in the 'numeric' arguments is reprehensibly sloppy (meaning, non-existent). There's no division by zero check, either. But that at least produces plausible answers. It would probably be better to have an array of structures saving the function pointer and the operation character, but that sort of refinement is for you to deal with.
If you need a negative number, use -- to mark the end of the options:
$ ./program -m -- -39 -75
-39 * -75 = 2925
$
Just in case you're not sure about it, int (*fun)(int, int) is a pointer to a function that takes two int arguments and returns an int result. It allows the code to select which function to execute at runtime.
With getopt(), an option can take at most one argument. If you want your program to handle its command line with getopt(), and it must accept arguments such as you describe
calc -a 100 50
, and you must not repeat options, then the only viable solution is to make one or both of the integers non-option arguments instead of arguments to the -a option. I'd suggest making both (or all) non-option arguments. Thus, you might have something like this:
int result = getopt(argc, argv, "asmd");
switch (result) {
case 'a':
// careful: getopt() will be confused by negative numbers
if (getopt(argc, argv, "asmd") != -1) {
fprintf(stderr, "usage: %s -a|-s|-m|-d <operands>\n", argv[0]);
exit(1);
}
do_add(argv + optind);
break;
case 's':
// ...
}
After getopt() returns -1, optind is the index in argv one past that of the last option (+/- option argument) processed.
This excerpt from the man page for getopt() clearly shows that each of the answers (and the original question) are not showing an understanding of getopt:
optstring is a string containing the legitimate option characters.
If such a character is followed by a colon,
[then] the option requires an argument,
so getopt() places a pointer
to the following text in the same argv-element,
or the text of the following argv-element,
in optarg.
your code should also allow for the following:
If getopt() does not recognize an option character,
it prints an error message to stderr,
stores the character in optopt,
and returns '?'.
and finally this (which will allow for the - to be in any position on the command line:
By default, getopt() permutes the contents of argv as it scans, so that
eventually all the nonoptions are at the end.

Getopt and Optarg

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".

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