clarification on argc and argv - c

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.

Related

Change input stream mid-program

I have the following program which prints text from a file:
#include<stdio.h>
int main(void) {
int ch;
while ((ch=getchar()) != EOF) {
putchar(ch);
}
printf("Enter a character now...\n");
// possible to prompt input now from a user?
ch = getchar();
printf("The character you entered was: %c\n", (char) ch);
}
And running it:
$ ./io2 < file.txt
This is a text file
Do you like it?
Enter a character now...
The character you entered was: �
After this, how would I get a user to enter in a character. For example, if I were to do getchar() (when not redirecting the file to stdin)?
Now it seems it just will keep printing the EOF character if I keep doing getchar() at the end.
My previous suggestion won't work because the cat command will just join both the file and stdin as one and supply that to your program and you will eventually reach the same conclusion.
If your program needs the file, it should just read from it directly, then get the rest of its input from standard input...
#include<stdio.h>
#include<stdlib.h>
int main(void) {
int ch;
FILE* file = fopen("file.txt", "r");
if (file == NULL) {
perror("fopen");
return EXIT_FAILURE;
}
while ((ch=fgetc(file)) != EOF) {
putchar(ch);
}
fclose(file);
... // now just read from stdin
return EXIT_SUCCESS;
}
You can call clearerr(stdin) to clear the end-of-file (and error) conditions:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int c;
/* Consume standard input */
while ((c = getchar()) != EOF) {
putchar(c);
}
/* Clear the error condition */
clearerr(stdin);
printf("Please provide more input.\n");
fflush(stdout);
/* Consume more standard input */
while ((c = getchar()) != EOF) {
putchar(c);
}
return EXIT_SUCCESS;
}
However, this is the wrong approach. If you run echo Hello | ./io2, the program will not wait for additional input, because standard input is provided by echo, and is no longer connected to the terminal.
The proper approach is to use command-line parameters to specify the file name, and read it using a separate FILE handle:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
FILE *in;
int c;
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *arg0 = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", arg0);
fprintf(stderr, " %s FILENAME\n", arg0);
fprintf(stderr, "\n");
fprintf(stderr, "This program reads and outputs FILENAME, then\n");
fprintf(stderr, "prompts and reads a line from standard input.\n");
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
/* Open specified file. */
in = fopen(argv[1], "r");
if (!in) {
fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
/* Read and output file, character by character ("slow") */
while ((c = getc(in)) != EOF) {
putchar(c);
}
/* Check if the EOF indicated an error. */
if (ferror(in)) {
fprintf(stderr, "%s: Read error.\n", argv[1]);
return EXIT_FAILURE;
}
/* Close the input file. Be nice, and check for errors. */
if (fclose(in)) {
fprintf(stderr, "%s: %s.\n", argv[1], strerror(errno));
return EXIT_FAILURE;
}
/* Prompt for new input. */
printf("Please input something.\n");
fflush(stdout);
while (1) {
c = getchar();
if (c == EOF || c == '\n' || c == '\r')
break;
putchar(c);
}
printf("All done.\n");
return EXIT_SUCCESS;
}
There are several things worthy of note here:
argv[0] is the command itself (./io2 in your example). The first command-line argument is argv[1]. Because argc is the number of entries in argv, argc == 1 means there are no arguments; argc == 2 means there is one argument, and so on.
If argc == 2, then argv[0] and argv[1] are valid. In POSIXy systems like Linux and BSDs and Mac, and standard C libraries conforming to C11, argv[argc] == NULL, and is safe to access.
The if line relies on C logic rules. In particular, if you have expr1 || expr2, and expr1 is true, expr2 is never evaluated.
This means that if argc != 2, the strcmp() checks are not evaluated at all.
The !strcmp(argv[1], "-h") is true if and only if argv[1] matches -h.
Thus, the if line reads, "if argc says we don't have exactly two elements in argv array, or we have and argv[1] matches -h, or we have and argv[2] matches --help, then".
It is often possible to execute a program without any arguments in POSIXy systems, for example via execl("./io2", NULL, NULL) or by some other nonstandard trick. This means that it is technically possible for argc to be zero. In that case, we don't know how this program was executed.
The value of arg0 is a ternary expression which essentially reads, "if argc says we we should have at least one element in argv array, and argv array exists, and the first element in argv array exists, and the first character in that first element is not end of string mark, then arg0 is the first element in argv array; otherwise, arg0 is (this)."
This is only needed because I like printing the usage when run with -h or --help as the first parameter. (Almost all command-line programs in POSIXy systems do this.) The usage shows how to run this program, and for this, I want to use the same command that was used to run this program; hence arg0.
When getc()/getchar()/fgetc() returns EOF, it means that there is no more input in the stream. This can happen because of end of stream, or because a read error occurred.
I like to carefully check for errors. Some consider it "useless", but to me, error checking is important. As an user, I want to know – no, I need to know if my storage media is producing errors. Therefore, the ferror(in) check is important to me. It is true (nonzero) only if there was a read/write error (I/O error) when accessing the stream in.
Similarly, it is possible for fclose(in) to report a delayed error. I do not believe it is possible to happen for a read-only stream, but it definitely is possible for streams we write to, because the C standard library buffers stream data, and the final underlying write operation can occur when we are closing the stream handle. Even the man 3 fclose man page explicitly says this is possible.
Some programmers say that it is not useful to check for fclose() errors, because they are so rare. To me, as an user, it is. I want the programs I use to report the errors they detect, instead of assuming "eh, it's so rare I won't bother checking or reporting those"*.
By default, standard output (stdout) is line-buffered, so technically the fflush(stdout) is not needed. (The fact that the previous printf() ends with a newline, \n, means that that printf() should cause the standard output to be flushed.)
Flushing a stream means ensuring the C library actually writes its internal buffer to the output file or device. Here, we definitely want to be sure the user sees the prompt, before we start waiting for input. Thus, while the fflush(stdout) is technically not needed, here it also provides us human programmers a reminder that at this point, we do need the stdout stream to be flushed to the actual output device (terminal).
It is often useful to redirect program output to a file, or via a pipe as input to another program. Because of this, I like to use the standard error (stderr) for error messages and the usage information.
If the user runs the program incorrectly, or an error occurs, with the output redirected to a file or piped to another program, they will typically still see the standard error output. (It is possible to redirect standard error too, though.)

getopt to take only one argument

I have a question about getopt in C. I have multiple option flags and am trying to get it to take one argument for everything. The command line will look something like command -a fileName or command -b fileName or command -ab fileName. Basically every command takes in one fileName and if they want to combine commands they should only have to type in one fileName. In getopt the string looks like a:b: and a variable is set to argv[argc -1]. This is fine if it's just one option but fails if there are multiple options (ie command -ab fileName) since : forces users to input an option but :: will make the singe options not force the user to type in an option. Any suggestions?
The optind global variable lets you know how many of the argv strings were used. So one way to approach this problem is to just drop the colons, and use a string like "ab".
Here's an example of what the code looks like (adapted from the example in the man page):
int main(int argc, char *argv[])
{
int ch;
while ((ch = getopt(argc, argv, "ab")) != -1)
{
if (ch == 'a')
printf("Got A\n");
else if (ch == 'b')
printf("Got B\n");
else
printf("Got confused\n");
}
if (optind != argc-1)
printf("You forgot to enter the filename\n");
else
printf("File: %s\n", argv[optind]);
}
If you run this with a command line like
./test -ab hello
the output is
Got A
Got B
File: hello

Compare string literal command line parameters in 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.

Handle segmentation fault accessing non-existent command line argument

I'm making a program in C in linux environment. Now, program runs with arguments which I supply in the command line.
For example:
./programName -a 45 -b 64
I wanted to handle the case when my command line parameters are wrongly supplied. Say, only 'a' and 'b' are valid parameters and character other than that is wrong. I handled this case. But suppose if my command line parameter is like this:
./programName -a 45 -b
It gives segmentation fault(core dumped). I know why it gives because there is no arguments after b. But how can I handle this situation such that when this condition arrives, I can print an error message on screen and exit my program.
As per the main function wiki page:
The parameters argc, argument count, and argv, argument vector, respectively
So you can use your argc parameter to check whether or not you have the right number of arguments. If you don't have 4, handle it and proceed without segfault.
You can, and quite probably should, use getopt() or its GNU brethren getopt_long().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int b = 0;
int a = 0;
int opt;
while ((opt = getopt(argc, argv, "a:b:")) != -1)
{
switch (opt)
{
case 'a':
a = atoi(optarg);
break;
case 'b':
b = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: %s -a num -b num\n", argv[0]);
exit(1);
}
}
if (a == 0 || b == 0)
{
fprintf(stderr, "%s: you did not provide non-zero values for both -a and -b options\n", argv[0]);
exit(1);
}
printf("a = %d, b = %d, sum = %d\n", a, b, a + b);
return(0);
}
You can make the error detection more clever as you wish, not allowing repeats, spotting extra arguments, allowing zeros through, etc. But the key point is that getopt() will outlaw your problematic invocation.
We can't see what went wrong with your code because you didn't show it, but if you go accessing a non-existent argument (like argv[4] when you run ./programName -a 42 -b), then you get core dumps. There are those who write out option parsing code by hand; such code is more vulnerable to such problems than code using getopt() or an equivalent option parsing function.

How to run c program and give input in same line

I'm new to C and I'd like to ask about running a C program and supplying input at the same time.
What I would like to do is run a program (ex. fileOpener) and also state which file to open
./fileOpener < filename1
I've tried it already and it works fine, but what do I use to know what filename1 is? That way I can open the file with
fp = fopen(filename1, "r")
Thanks.
Edit: OK, I'll try to explain a bit more. If there wasn't a "<" then I could just use command line arguments as I have done before, but when I tried it with the <, it didn't work
Specifically: fileOpener code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
printf("%s", argv[1]);
}
when I use ./fileOpener < filename1 the output is ./fileOpener
I used gcc -o fileOpener fileOpener.c as the compiler
int main(int argc, char *argv[])
You can name them whatever you want, but these are the normal names.
argc is non-negative. It gives the number of useful elements in argv.
If argc is positive, argv[0] contains the program name. Then argv[1] through argv[argc - 1] point to character arrays that contain the program's command line arguments.
For example, if I run a program at the command line, such as
unzip filename.zip
argc will equal 2; and argv[0] will compare equal to "unzip"; and argv[1] will compare equal to "filename.zip".
Source
You can't do that, if you use redirection (i.e. "< filename") the file is opened by the system. You could discover the name, but it's non-portable, and anyway useless since the file is already open. Just use stdin instead of fp, and you need not use fopen() (nor fclose()):
int main()
{
char buffer[1024];
// fgets() reads at most 1024 characters unless it hits a newline first
// STDIN has been already opened by the system, and assigned to data flowing
// in from our file ( < inputFile ).
fgets(buffer, 1024, stdin);
printf("The first line of input was: %s", buffer);
}
A different approach is to use arguments:
int main(int argc, char **argv)
{
FILE *fp = NULL;
char buffer[1024];
if (argc != 2)
{
fprintf(stderr, "You need to specify one argument, and only one\n");
fprintf(stderr, "Example: %s filename\n", argv[0]);
// Except that argv[0], this program's name, counts.
// So 1 argument in command line means argc = 2.
return -1;
}
printf("I am %s. You wanted to open %s\n", argv[0], argv[1]);
fp = fopen(argv[1], "r");
fgets(buffer, 1024, stdin);
printf("The first line of input was: %s", buffer);
fclose(fp); fp = NULL; // paranoid check
return 0;
}
You need setup your program to take a command line argument. Here's a good tutorial that solves your exact question:
http://www.cprogramming.com/tutorial/c/lesson14.html
A program's main function in C has two arguments:
int main(int nArgs, char *pszArgs[]) {}
That first argument tells the program how many parameters were passed onto the program when you ran it. Usually, this will just be 1, because it includes the program's name.
The second argument is a table of strings, which can be accessed thus (the program below prints the parameters given to it):
int main(int nArgs, char *pszArgs[])
{
int i = 0;
while (i < nArgs)
{
printf("param %d: %s\n", i, pszArgs[i]);
i++;
}
return 0;
}

Resources