Compare string literal command line parameters in C - c

I need my program to run this way ./src c 2345 or ./src s 345, whereby the first character hs to be either c or s and second an integer. The program should throw an usage error if there's any less parameters and also any charcter other than c or s. Here's my code
int main(int argc, char **argv) {
int num_of_connections = 0, client_sockfd;
int max_sockfd, master_socket;
fd_set socket_collection, read_collection;
// Check validity of the user input
if(argc < 3) {
if((strcmp(argv[2], "s") != 0) || (strcmp(argv[2], "c") != 0)){
fprintf(stderr, "Usage: ./src <s/c> <port>\n");
exit(EXIT_FAILURE);
}
}
When I enter one argument I get a segmentation fault. Also it doesnt identify the C or S parameter. Any help will be appreciated.

Notice that main has a very specific convention: the argv array has argc+1 members, with the last being NULL and the others being non-null distinct pointers to zero-terminated strings.
So if argc is 1 (e.g. if your run ./src alone) or 2, argv[2] is NULL and you cannot pass it to  strcmp
You can call strcmp(argv[2],"s") only when argc>=3
BTW, I would suggest to use getopt(3) or preferably (on Linux only) getopt_long and to accept the --help and --version arguments, per GNU conventions.
Also, compile with all warnings and debug info (gcc -Wall -g) and use the gdb debugger. It would be faster for you to use gdb than to ask here and wait for replies.

if(argc < 3) { does not make sense if you want exactly two parameters. In the inner if block you are confusion || (logical or) with && (logical and).
In your invocation example ./src s 345 the character is the first argument, so probably argv[2] should read argv[1].
if ((argc != 3) || ((strcmp(argv[1], "s") != 0) &&
(strcmp(argv[1], "c") != 0))) {
fprintf(…);
return EXIT_FAILURE;
}
Note: all parentheses in this if (…) condition are optional, because of C's operator precedence. I put them for readability.

Related

True and false in C in if statement with getopt()

I have a hard time in understatanding how true and false works with "if statement" when I am using argv & getopt.
This is the simple code:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
int opt;
while ((opt = getopt (argc, argv, "i:l:")) != -1)
switch (opt) {
case 'i':
printf("This is option i");
break;
case 'l':
printf("This is option l");
break;
default:
fprintf(stderr,"Usage: %s here goes usage\n",argv[0]);
}
if (argc == 1) {
printf("Without options");
}
if ((argc == 2) && (argv[1] != "-l") || (argv[1] != "-i")) {
printf("Without option -l or -i but with other argument \n");
printf("argv[1] is %s\n", argv[1]);
}
Usage:
./a.out foo
Output:
Without option -l or -i but with other argument
argv[1] is foo
It's good so far. Now let me check if it works when argv[1] is "-l":
Usage:
./a.out -l
Output:
./a.out: option requires an argument -- 'l'
Usage: ./a.out here goes usage
Without option -l or -i but with other argument
argv[1] is -l
Getopt works fine, but second information occurs even if argv[1] is -l and I set in "if" statement that (argv[1] != "-l"). Why it works like that? I have no clue.
Thanks for any answer.
B.
Do not use:
argv[1] != "-l"
to compare strings in C(a), this compares the addresses of two arrays of char(b) rather than the contents of those two strings. Instaed, you should be using:
strcmp(argv[1], "-l") == 0
(a) This is one of the things fixed in C++ strings, the equality operators there compare the content of the strings.
(b) This may sometimes seem to work with something like "xyzzy" == "xyzzy" but that's only because the compiler is allowed (but not required) to fold identical string constants together (so they take less room). It generally is not possible when one of the strings is not a constant (such as when it's passed on the command line).
You re comparing two char *s using != this compares the addresses.
(argv[1] != "-l")
The way to compare strings is using strcmp. Mind hat the strcmp function is "trinary", and returns either a negative or positive value if the strings are different (to provide order) or 0 if equal.
(strcmp(argv[1], "-l") == 0)
AND (&&) has precedence over OR (||), so I think your code inside the if statement is interpreted like this: if (((argc == 2) && (argv[1] != "-l")) || (argv[1] != "-i")) So the logic inside of it is always true, because even if your option IS -l and it's one and only (number of option != 2) it's also true that the option you typed is NOT -i.

argc/argv in c linked list or binary tree

So I am trying to make a linked list/binary tree and:
The user should be able to choose the data structure directly from the command line when it starts the program. This should use the argc or argv arguments to main()
how would I do this? I don’t get it why not just use switch case statement asking the student.
option 1: linked list
option 2: binary tree?
we didn’t really cover argc argv properly can anyone help?
Apparently its a duplicate ... hmm.. well i am asking specically about binary tree/linked list how would the user tell it to choose which data structure?
Experiment with the following skeleton program, and find out.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: %s COMMAND\n", argv[0]);
return EXIT_FAILURE;
}
if (!strcmp(argv[1], "foo")) {
printf("Doing foo.\n");
} else
if (!strcmp(argv[1], "bar")) {
printf("Doing bar.\n");
} else {
fprintf(stderr, "Unknown command line parameter '%s'.\n", argv[1]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
The most common way to inform the utility user as to what to do, is to run the utility without parameters, or with -h or --help as the only parameter. (Windows command-line utilities might use /? or similar.)
Let's say the user can run the compiled program, program in the following ways:
./program list
./program tree
./program -h
./program --help
./program
where the first form tells the program to use a linked list; the second form tells the program to use a tree; and the other forms just output usage, information on how to call the program:
Usage: ./program [ -h | --help ]
./program MODE
Where MODE is one of:
list Linked-list mode
tree Tree mode
Further details on what the program actually does...
You achieve this with very little code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
enum {
NO_MODE = 0,
LIST_MODE,
TREE_MODE
};
int main(int argc, char *argv[])
{
int mode = NO_MODE;
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
printf("Usage: %s [ -h | --help ]\n", argv[0]);
printf(" %s MODE\n", argv[0]);
printf("\n");
printf("Where MODE is one of\n");
printf(" list for linked list mode\n");
printf(" tree for tree mode\n");
printf("\n");
printf("Further details on what the program actually does...\n");
printf("\n");
return EXIT_SUCCESS;
}
if (!strcmp(argv[1], "list"))
mode = LIST_MODE;
else
if (!strcmp(argv[1], "tree"))
mode = TREE_MODE;
else {
fprintf(stderr, "%s: Unknown MODE.\n", argv[1]);
return EXIT_FAILURE;
}
/* mode == LIST_MODE or TREE_MODE here,
depending on the first command line parameter.
*/
return EXIT_SUCCESS;
}
Note that || operator is short-circuited in C: if the left side is false, the right side is not evaluated at all. So, above, the first strcmp() check is only done when argv == 2, and the second when argv == 2 and the first strcmp() returned nonzero (no match).
In other words, the body of the usage section is only run when argv != 2 (there is less than two, or more than two command line items, counting the program name as one); or if the sole command-line parameter matches either -h or --help.
! is the not operator in C. !x evaluates to 1 if and only if x is zero or NULL; and to 0 otherwise.
(You can confuse people by using !!x. It evaluates to zero if x is zero, and to one if x is not zero. Which is logical. It's often called the not-not operation.)
The enum is just there to remind you that magic constants are bad; it is better to use either enums, or preprocessor macros (#define NO_MODE 0 and so on). It would be terribly easy to use 1 in one place to indicate tree mode, and 2 in another; such bugs are horrible to debug, needs way too much concentration from the human reading the code, to find such bugs. So don't use magic constants, use enums or macros instead.
Above, I decided that NO_MODE has value zero, and let the compiler assign (increasing) values to LIST_MODE and TREE_MODE; consider them compile-time integer constants. (Meaning, you can use them in case labels in a switch statement.)
Because strcmp() returns zero if the two strings match, !strcmp(argv[1], "baz")) is true (nonzero) if and only if argv[1] contains string baz. You see it all the time in real-world code when strings are compared.
If you look at my answers here, you'll very often see an if (argc ...) "usage" block in my example code. This is because even I myself will forget, often within days, exactly what the purpose of the program is. I typically have several dozen example programs on my machines I've written, and rather than looking at the sources to see if something jogs my memory, I simply run the example snippets without command-line parameters (or actually, with -h parameter, since some are filters), to see what they do. It's faster, less reading, and I'll find the relevant snippet faster.
In summary, write an usage output block in all your programs, especially when it is just a test program you won't publish anywhere. They are useful, especially when you have a library full of them, of various code snippets (each in their own directory; I use a four-digit number and a short descriptive name) that implement interesting or useful things. It saves time and effort in the long run, and anything that lets me be efficient and lazy is good in my book.
argc = argument count, argv = array of arguments. argv[0] is the executing program. argv[1..n] are the arguments passed to the executable.
Example: I call the executable foo with 2 arguments, bar and bas:
foo bar bas
argc = 3, argv = [foo, bar, bas]

clarification on argc and argv

I have some doubts on what are argc and argv, i cant seem to grasp the concept, for what should i use them and how should i use them?
like i have this program that receives from the command line two integers between -100000 and 100000 computes thir addition and prints the result, while performing all needed check about te number of paramenters and their correctness.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int a, b;
char ch;
if (argc != 4)
{
printf("ERROR - Wrong number of command line parameters.\n");
exit(1);
}
if (sscanf(argv[1], "%d", &a) != 1)
{
printf("ERROR - the first parameter (%s) is not a valid integer.\n",
argv[1]);
exit(2);
}
if (sscanf(argv[2], "%d", &b) != 1)
{
printf("ERROR - the second parameter (%s) is not a valid integer.\n",
argv[2]);
exit(2);
}
ch = argv[3][0];
if (ch == 'a')
printf("The sum result is %d\n", a + b);
else if (ch == 'b')
printf("The subtraction result is %d\n", a - b);
else if (ch == 'c')
printf("The multiplication result is %d\n", a * b);
else if (ch == 'd')
{
if (b != 0)
printf("The division result is %d\n", a / b);
else
printf("ERROR the second value shoulb be different than 0 \n");
}
else
printf("ERROR parameter (%c) does not correspond to a valid value.\n",
ch);
return 0;
}
but how does the program receive from the command line two arguments?? where do i input them?? i am using codeblocks.
argc is the number of parameters passed to your program when it's invoked from command line.
argv is the array of received parameters, and it is an array of strings.
Note that the name of the program is always passed automatically.
Assuming your program executable is test, when you invoke from terminal:
./text 145 643
argc will be 3: program name and the two numbers
argv will be the char* array {"./text","145","643"}
When you write a code, say hello.c, you can run it from the terminal, by going to that directory/folder from the terminal, and compile it using a compiler like gcc.
gcc hello.c -o hello
If you are using Windows, with a compiler like Turbo C or Visual Studio, then it would create a .exe file. This creates an executable file.
When you run the file from command line, you can give command-line arguments as a way of input to the program.
On terminal, you could ./hello arg1 arg2, where arg1 and arg2 are the command line arguments to it. To see how to do this in Windows using a compiler like Turbo C, see this link too.
So what are argc and argv[]?
Your main functions uses main(int argc, char *argv[]), to take the command line arguments.
argc is the number of command line arguments passed. In the above case, that is 3.
argv[] is an array of strings, which in this case are 3 strings. argv[1] will be equal to "arg1" and argv[2] will be equal to "arg2". "./hello" will be in argv[0].
So you give your command line arguments in the command line, be it Linux or Windows. The above explanation was more for Linux. See this and this for command line arguments in Turbo C (I do not recommend Turbo C), and this in case of Visual C.
To know more about command line arguments, you can read this.

how to parse command line arguments in C?

I am trying to parse command line arguments in C. Currently, I am using getopt do the parse. I have something like this:
#include <unistd.h>
int main(int argc, char ** argv)
{
while((c=getopt(argc, argv, "abf:")) != -1)
{
switch(c)
{
case 'a':
break;
case 'b':
break;
case 'f':
puts(optarg);
break;
case ':':
puts("oops");
break;
case '?'
puts("wrong command");
break;
}
}
}
then need to use ./a.out -fto run the program, and -f is the command element, but looks like -f must start with a '-', if I do not want the command element starts with '-', i.e, using ./a.out f instead of ./a.out -f, how to achieve it?
if getopt does not support parsing a command line in this way, are there any other library to use in C?
The argc and argv variables give you access to what you're looking for. argc is "argument count" and argv is "argument vector" (array of strings).
getopt is a very useful and powerful tool, but if you must not start with a dash, you can just access the argument array directly:
int main( int argc, char** argv) {
if( argc != 1) { /* problem! */ }
char * argument = argv[1]; // a.out f ... argv[1] will be "f"
}
You could use (on Linux with GNU libc) for parsing program arguments:
getopt with getopt_long; you might skip some arguments using tricks around optind
argp which is quite powerful
and of course you could parse program arguments manually, since they are given thru main(int argc, char**argv) on Linux (with the guarantee that argc>0, that argv[0] is "the program name" -e.g. to find it in your $PATH when it contains no / ..., that argv[argc] is the NULL pointer, and that before that every argv[i] with i<argc and i>0 is a zero-terminated string. See execve(2) for more.
GNU coding standards: command line interfaces document quite clearly some conventions. Please, obey at least the --help and --version conventions!
You might also be concerned by customizing the shell auto-completion facilities. GNU bash has programmable completion. zsh has a sophisticated completion system.
Remember that on Posix and Linux the globbing of command words is done by the shell before starting your program. See glob(7).
The getopt library will stop parsing at the first non-option argument. For command-based programs, this will be at the command name. You can then set optind to the index to start at and run getopt again with the command-specific arguments.
For example:
// general getopts
if (optind >= argc) return 0; // error -- no command
if (strcmp(argv[optind], "command") == 0)
{
++optind; // move over the command name
// 'command'-specific getopts
if (optind >= argc) return 0; // error -- no input
}
This should allow git-like command-line parsing.

Unix tail program in C using an implemented function

I have implemented my own dynamic-memory version of getline function:
char * fgetline(FILE * f)
Starts with 30 character buffer and when the buffer is full allocate a new one copy the contents and free the old buffer. When we get EOF or \n we return from the function.
I want to use this function to implement a version of the program tail. Input comes from stdin, output goes to stdout. If the first argument begins with -, everything after the - is the number of lines to print. The default number of lines to print is 10, when no argument is given.
I have thought until now that I should use the function:
int atoi (const char *s)
from stdlib.h and have an array of pointers to lines but I don't know exactly how to do this.
Any ideas?
Declare your main function as
int main (int argc, char**argv) {
}
If you compile your program to myprog executable, and invoke it as myprog -20 somefile anotherfile then you have:
argc == 4
&& strcmp(argv[0], "myprog") == 0
&& strcmp(argv[1], "-20") == 0
&& strcmp(argv[2], "somefile") == 0
&& strcmp(argv[3], "anotherfile") == 0
&& argv[4] == NULL
in other words, you might want to have your program containing
int nblines = 10;
int main(int argc, char**argv) {
int argix = 1;
if (argc>1) {
if (argv[1][0]=='-')
{
nblines = atoi(argv[1]+1);
argix = 2;
}
for (; argix < argc; argix++)
tail (argv[argix]);
}
return 0;
}
It is up to you to implement your void tail(char*filename); function appropriately. Don't forget to compile with all warnings & debugging info, e.g. with gcc -Wall -g on Linux. Use your debugger (gdb on Linux) to debug your program. Take into account that fopen can fail, and use errno to display an appropriate error message.
Notice that you don't need your fgetline function. The getline(3)
function is standard (in Posix 2008) and is dynamically allocating the line buffer.

Resources