Reading command line parameters - c

I have made little program for computing pi (π) as an integral. Now I am facing a question how to extend it to compute an integral, which will be given as an extra parameter when starting an application. How do I deal with such a parameter in a program?

When you write your main function, you typically see one of two definitions:
int main(void)
int main(int argc, char **argv)
The second form will allow you to access the command line arguments passed to the program, and the number of arguments specified (arguments are separated by spaces).
The arguments to main are:
int argc - the number of arguments passed into your program when it was run. It is at least 1.
char **argv - this is a pointer-to-char *. It can alternatively be this: char *argv[], which means 'array of char *'. This is an array of C-style-string pointers.
Basic Example
For example, you could do this to print out the arguments passed to your C program:
#include <stdio.h>
int main(int argc, char **argv)
{
for (int i = 0; i < argc; ++i)
{
printf("argv[%d]: %s\n", i, argv[i]);
}
}
I'm using GCC 4.5 to compile a file I called args.c. It'll compile and build a default a.out executable.
[birryree#lilun c_code]$ gcc -std=c99 args.c
Now run it...
[birryree#lilun c_code]$ ./a.out hello there
argv[0]: ./a.out
argv[1]: hello
argv[2]: there
So you can see that in argv, argv[0] is the name of the program you ran (this is not standards-defined behavior, but is common. Your arguments start at argv[1] and beyond.
So basically, if you wanted a single parameter, you could say...
./myprogram integral
A Simple Case for You
And you could check if argv[1] was integral, maybe like strcmp("integral", argv[1]) == 0.
So in your code...
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc < 2) // no arguments were passed
{
// do something
}
if (strcmp("integral", argv[1]) == 0)
{
runIntegral(...); //or something
}
else
{
// do something else.
}
}
Better command line parsing
Of course, this was all very rudimentary, and as your program gets more complex, you'll likely want more advanced command line handling. For that, you could use a library like GNU getopt.

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int i, parameter = 0;
if (argc >= 2) {
/* there is 1 parameter (or more) in the command line used */
/* argv[0] may point to the program name */
/* argv[1] points to the 1st parameter */
/* argv[argc] is NULL */
parameter = atoi(argv[1]); /* better to use strtol */
if (parameter > 0) {
for (i = 0; i < parameter; i++) printf("%d ", i);
} else {
fprintf(stderr, "Please use a positive integer.\n");
}
}
return 0;
}

Parsing command line arguments in a primitive way as explained in the above answers is reasonable as long as the number of parameters that you need to deal with is not too much.
I strongly suggest you to use an industrial strength library for handling the command line arguments.
This will make your code more professional.
Such a library for C++ is available in the following website. I have used this library in many of my projects, hence I can confidently say that this one of the easiest yet useful library for command line argument parsing. Besides, since it is just a template library, it is easier to import into your project.
http://tclap.sourceforge.net/
A similar library is available for C as well.
http://argtable.sourceforge.net/

There's also a C standard built-in library to get command line arguments: getopt
You can check it on Wikipedia or in Argument-parsing helpers for C/Unix.

Related

Print command line parameter on console

I want to pass a file name to my programm. If I type it in the terminal it works. But if I pass it as a command line parameter it doesn`t print the string in the end. Just something like: "²☺"
Any ideas why?
#include <stdio.h>
int main(int argc, char* argv[]){
char *nameDatei[100];
if(argv[1] != NULL) {
nameDatei[100] = argv[1];
} else {
printf("type in the name of the file: ");
scanf("%s", nameDatei);
}
printf("%s", &nameDatei);
return 0;
}
It only works "by accident" when you type the name at the terminal, and that's because you are either ignoring compiler warnings or using an obsolete compiler (any compiler which is not complaining about the code is obsolescent, though GCC 11.2.0 seems to accept it unless you pass warning options such as -Wall -Wextra -Werror).
You pass a char *(*)[100] to printf() but tell it that the argument is a char *
You pass a char ** to scanf() but tell it that the argument is a char *
You try to access element 100 of an array of size 100, which is one too many.
You happen to have 100 * sizeof(char *) bytes to hold the name, which is where the accident comes in, but that's not the correct type.
You need code more like:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *nameDatei;
char nameBuffer[100];
if (argv[1] != NULL)
nameDatei = argv[1];
else
{
printf("type in the name of the file: ");
if (scanf("%99s", nameBuffer) != 1)
{
fprintf(stderr, "failed to read file name\n");
exit(EXIT_FAILURE);
}
nameDatei = nameBuffer;
}
printf("%s\n", nameDatei);
return 0;
}
I called the source cla61.c and the program cla61. A couple of sample runs:
$ cla61 abyssinian-coffee
abyssinian-coffee
$ cla61
type in the name of the file: abyssinian-coffee
abyssinian-coffee
$
Don't copy command-line arguments unless you are going to modify them. But it's legitimate to make a new variable point to a command-line argument. And when there isn't a command-line argument, you need to allocate space for the replacement value — the value read from the terminal in this example.

How to execute a code whose main function looks like this?

The code is like (real noob question) :
int main(int argc, char **argv){
//some code
}
I know, it means I have to give some arguments while executing in the terminal, but the code does not require any arguments or information from the user. I don't know what to give as the argument?
For example:
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello World\n");
}
Compile with GCC,
$gcc prog.c -o prog
$./prog
Hello World
So, If you do not use agave in your code, then, there is no need to provide an argument.
I have to give some arguments while executing in the terminal,
No, you don't have to. You may give some arguments. There are conventions regarding program arguments (but these are just conventions, not requirements).
It is perfectly possible to write some C code with a main without argument, or with ignored arguments. Then you'll compile your program into some executable myprog and you just type ./myprog (or even just myprog if your PATH variable mentions at the right place the directory containing your myprog) in your terminal.
The C11 standard n1570 specifies in §5.1.2.2.1 [Program startup] that
The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be
used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent) or in some other implementation-defined manner.
The POSIX standard specifies further the relation between the command line, the execve function, and the main of your program. See also this.
In practice I strongly recommend, in any serious program running on a POSIX system, to give two argc & argv arguments to main and to parse them following established conventions (In particular, I hate serious programs not understanding --help and --version).
You can always pass some number of arguments or pass nothing unless you are checking for the number of arguments and arguments passed (or forcing compiler to do so). Your command interpreter has no idea what your program is going to do with the passed argument or whether the program need any argument. It's your program which takes care of all these things.
For example,
int main(void){
return 0;
}
you can pass any number of arguments to the above program
$ gcc hello.c -o hello
$ ./hello blah blah blah
In case of
int main(int argc, char **argv){
return 0;
}
you can pass no arguments.
$ gcc hello.c -o hello
$ ./hello
For
int main(int argc, char **argv){
if(argc < 3){
printf("You need to pass two arguments to print those on the terminal\n");
exit(0);
}
else{
printf("%s %s\n", argv[1], arv[2]);
}
return 0;
}
You have to pass two arguments because the program checking the number of arguments passed and using them
$ gcc hello.c -o hello
$ ./hello Hello world

windows mingw asterisk '*' passing by argv[1] to string

I wrote a code below
#include<stdio.h>
int main(int argc, char *argv[]) {
char cmd[50]="dir";
if (argc == 2) {
sprintf(cmd,"dir %s",argv[1]);
}
if (argc == 3) {
sprintf(cmd,"dir %s %s", argv[1], argv[2]);
}
printf("%s\n",cmd);
system(cmd);
return 0;
}
when I executed like below
I think can't pass '*' by *argv[]
How can I pass something like "*.c" ?
update
code
#include<stdio.h>
int main(int argc, char *argv[]) {
char cmd[50]="dir";
if (argc == 2) {
sprintf(cmd,"dir %s",argv[1]);
}
if (argc == 3) {
sprintf(cmd,"dir %s %s", argv[1], argv[2]);
}
if (argc > 3) {
sprintf(cmd,"dir %s %s", argv[1], argv[2]);
}
printf("%s\n",cmd);
system(cmd);
return 0;
}
changing is below
what..... #.# ?
Updated code again
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[]) {
int i;
char sp[2]=" ", cmd[250]="dir";
if (argc > 1) {
sprintf(cmd,"dir /d ");
for (i =1 ; i < argc; i ++) {
strcat(cmd,sp);
strcat(cmd,argv[i]);
}
}
printf("%s\n",cmd);
system(cmd);
return 0;
}
see what happen when I executed
kind of ugly.... any decent idea?
This issue is not related to the C runtime, but to the shell behaviour. If you use Windows CMD.EXE, the * is passed unchanged to the programs, whereas if you use Cygwin's bash, the shell expands * to the list of files and passes this expansion as individual arguments to your program. You can prevent this expansion by quoting the wildcards with "*" or '*'.
Note that you should not use sprintf, but snprintf to avoid buffer overflows. If you link to the non standard Microsoft C library, you may need to use _snprintf instead.
EDIT: CMD.EXE does not seem to expand wildcards, but the C runtime you link your program with might do it at startup. See this question: Gnuwin32 find.exe expands wildcard before performing search
The solution is to quote the argument.
I'm afraid the accepted answer is not correct as the edit courteously admits. What is happening here is that globbing behaviour is provided in the C runtime but the default behaviour differs between compilers.
Yes, it's a major pain if you do not know what is happening. Worse the globbing does not occur if the glob does not match any files. I was pretty surprised myself.
Under Visual Studio, by default, wildcards are not expanded in command-line arguments. You can enable this feature by linking with setargv.obj or wsetargv.obj:
cl example.c /link setargv.obj
Under MinGW, by default, wildcards are expanded in command line arguments. To prevent this you can link with CRT_noglob.o or, much more easily, add the global variable:
int _CRT_glob = 0;
in your own source in the file which defines main() or WinMain().

Pass the arguments received in C down to bash script

I have the following piece of C code that is being called with arguments:
int main(int argc, char *argv[])
{
system( "/home/user/script.sh" );
return 0;
}
how do i pass all arguments received down to script.sh?
You could synthesize some string (escaping naughty characters like quote or space when needed, like Shell related utility functions of Glib do) for system(3).
But (on Linux and Posix) you really want to call execv(3) without using system(3)
You may want to read (in addition of the man page I linked above) : Advanced Linux Programming
I think that you are looking for the execv function. It will grant to you to execute a specific file passing to it some optional arguments.
Try something next:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
system("cat /etc/passwd");
extern char * const environ[];
char * const command[] = {"mylsname", "-lR", "/", NULL};
execve("/bin/ls", command, environ);
perror("execve");
exit(EXIT_FAILURE);
}
You can use snprintf() function to frame a string. For example, snprintf(filename, sizeof(char) * 64, "/home/user/script.sh %s", argv[1]); and use system(filename);

MSVS command line arguments

#include "hmap.h"
int main(char* argv[], int argc)
{
printf("%s", argv[0]); <---- fails here
system("pause");
fileOpen(argv[1]);
return 0;
}
I am using MSVS 2012. I'm wondering if I'm using the command line arguments wrong. The text file is in the same folder. All my header file has is the #include libraries I will using, some #define's I'll be using, and extern function prototypes.
When I run the program it says "expand.exe has stopped working...."
I usually program in a Linux environment using GCC but I'm trying to learn MSVS environment. Getting a little frustrated on how much of a hassle to input command line arguments :.
I think the arguments for main() are around the wrong way.
That is, the first argument should be the argument count (argv), and the second one the argument vector (argv).
int main(int argc, char* argv[]) {}
It fails because a subscript should be used only with an array or pointer.

Resources