Printing integers from command line arguments in C - c

I'm running my program with some command line arguments. But when I enter 10, 10, 10 and print them out, it prints out 49, 49, 49. Here's my code:
int main(int argc, char *argv[]) {
int seed = *argv[0];
int arraySize = *argv[1];
int maxSize = *argv[2];
Why is this happening??

Well, argv is an array of pointer to strings. All command line arguments are passed as strings and the pointer to each of them is held by argv[n], where the sequence for the argument is n+1.
For a hosted environment, quoting C11, chapter §5.1.2.2.1
If the value of argc is greater than zero, the string pointed to by argv[0]
represents the program name; argv[0][0] shall be the null character if the
program name is not available from the host environment. If the value of argc is
greater than one, the strings pointed to by argv[1] through argv[argc-1]
represent the program parameters.
So, clearly, for an execution like
./123 10 10 10 //123 is the binary name
argv[0] is not the first "command line argument passed to the program". It's argv[1].
*argv[1] does not return the int value you passed as the command-line argument.
Basically, *argv[1] gives you the value of the first element of that string (i.e, a char value of '1'), most possibly in ASCII encoded value (which you platform uses), ansd according to the ascii table a '1' has the decimal va;lue of 49, which you see.
Solution: You need to
Check for the number of arguments (argc)
Loop over each argument string argv[1] ~ argv[n-1] while argc == n
Convert each of the input string to int (for this case, you can make use of strtol())

Dereferencing a string (*argv[x]) gives you a char (the value of the first character in the string), in this case the value is ASCII '1': decimal 49
You can convert those strings (without dereferencing) using strtol
int arraySize = (int)strtol(argv[1], NULL, 10);
Anyway argv[0] is the name of your program, are you sure that the program name starts with 1?

Related

Segmentation fault when file is not found even if I try to create it in C

I'm writing a code that appends text to a file.
It uses fopen in the beginning of WriteToFile so even if the file does not exist, it creates it.
But, what happens when I enter no file at all? no arguments at all? Just ./a.out?
Segmentation fault.
I don't know why, it seems to me I did everything fine to avoid any problems.
int main(int argc, char **argv)
{
char file_name[30] = "file.txt";
printf("%s",file_name); /* for debugging : doesn't print it */
if (0 != argc)
{
strcpy(file_name, argv[1]);
}
WriteToFile(file_name);
}
OR
(in case I can't really put a string literal into char array):
char file_name[30];
if (0 == argc)
{
strcpy(file_name, "file.txt");
}
else
{
strcpy(file_name, argv[1]);
}
For both of the cases i'm getting
Segmentation fault (core dumped)
if (0 != argc)
The argc value is normally(a) the count of arguments including the program name. Hence, running ./a.out will have an argc of one rather than zero. And, since argv[argc] is usually NULL, dereferencing it is not going to end well :-)
If you want to ensure another argument is available, you can use:
if (argc > 1) { // Have both argv[0] AND argv[1].
nowSafeToUse(argv[1]);
}
In more detail, the C11 standard states:
If they are declared, the parameters to the main function shall obey the following constraints:
The value of argc shall be nonnegative.
argv[argc] shall be a null pointer.
If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.
The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.
As an aside regarding this line:
printf("%s",file_name); /* for debugging : doesn't print it */
If this is not printing, it's probably because standard output is line buffered (default if it's determined to be an interactive device, otherwise fully buffered).
By not outputting a \n at the end, the characters are probably still sitting in a buffer somewhere, ready to be written. The crash will probably kill off the process without flushing the buffer. So a simple solution may be just to use one of:
printf("%s",file_name);
puts(file_name);
As another aside, you're going to get into trouble if the filename you enter is larger than 29 characters since it will overflow file_name, allowing for the \0 at the end as well.
A better approach may be just to use either your default string or argv[1] directly (without copying), something like:
int main(int argc, char **argv) {
char *file_name = (argv > 1)
? argv[1]
: "file.txt";
printf("%s\n", file_name); // for debugging : probably does print it :-)
WriteToFile(file_name);
}
(a) Not required by the standard since it allows for implementation-specific differences, but it's the usual case. Specifically, the phrase:
... which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment.
pretty much means it can do whatever it wants :-)
A related answer (though a non-duplicate question) can be found here.
When argc is 1, argv is treated as an array of 2 pointers to char. The first is a valid pointer (typically to the program name), the second is NULL.
argv[1] accesses the second element of argv. With no arguments supplied, argc will be 1 and argv[1] will be NULL. You're therefore dereferencing a NULL pointer.
The condition 0 != argc should instead be argc >= 2 or argc > 1, and the condition 0 == argc should be argc < 2 or argc <= 1.
You have to account for the program's name so you should write if (argc >= 2) instead. See the man
The value of the argc argument is the number of command line arguments. The argv argument is a vector of C strings; its elements are the individual command line argument strings. The file name of the program being run is also included in the vector as the first element; the value of argc counts this element. A null pointer always follows the last element: argv[argc] is this null pointer.
argv[1] means index 1 but in C you start at index 0.
Fixed code
int main(int argc, char **argv)
{
char file_name[30] = "file.txt";
printf("%s",file_name); /* for debugging : doesn't print it */
if (argc >= 2)
strcpy(file_name, argv[1]);
else
return 1; // exit program with error code.
WriteToFile(file_name);
return 0; // exit with success
}

What Does Input Arguments is _

I wanna know why is result 1 for no arguments.
int main(int argcount, char *arglist[]) {
int i;
printf("Number of arguments %d\n",argcount);
printf("Arguments list:\n");
for (int i=0;i<argcount;i++)
printf("%s\n",arglist[i]);
return EXIT_SUCCESS;
}
From the standard (C11), noting especially the bold bit:
If they are declared, the parameters to the main function shall obey the following
constraints:
The value of argc shall be nonnegative.
argv[argc] shall be a null pointer.
If the value of argc is greater than zero, the array members argv[0] through
argv[argc-1] inclusive shall contain pointers to strings, which are given
implementation-defined values by the host environment prior to program startup. The
intent is to supply to the program information determined prior to program startup
from elsewhere in the hosted environment. If the host environment is not capable of
supplying strings with letters in both uppercase and lowercase, the implementation
shall ensure that the strings are received in lowercase.
If the value of argc is greater than zero, the string pointed to by argv[0]
represents the program name; argv[0][0] shall be the null character if the
program name is not available from the host environment. If the value of argc is
greater than one, the strings pointed to by argv[1] through argv[argc-1]
represent the program parameters.
The parameters argc and argv and the strings pointed to by the argv array shall
be modifiable by the program, and retain their last-stored values between program
startup and program termination.
In other words, argc includes the argument representing the program name - the actual parameters to the program start at argv[1]. That becomes evident from the program output as per the following transcript, where the first argument is the program name:
pax> cat testprog.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Argument count: %d\n", argc);
printf("Arguments:\n");
for (int i = 0; i < argc; i++)
printf(" %s\n", argv[i]);
return 0;
}
pax> gcc --std=c11 -o testprog testprog.c && ./testprog 1 2 3
Argument count: 4
Arguments:
./testprog
1
2
3
pax> ./testprog
Argument count: 1
Arguments:
./testprog
./a.out is the first argument so that's why argcount equals to 1.
From the C Standard (5.1.2.2.1 Program startup. p.#2)
— If the value of argc is greater than zero, the string pointed to by
argv[0] represents the program name; argv[0][0] shall be the null
character if the program name is not available from the host
environment.
So the used by you environment supplies the program name in the first argument.

Why aren't there any passed arguments to argv[]?

So, I noticed that my argc is always 1 as I will always get the message Error: missing command line arguments!, but as stated in code I am using argv[1] and argv[2] to read the files names.
Shouldn't automatically argc be 3 in this case, and to be able to pass that error?
Notes:
If I am not using if (argc < 2) statement, after I enter the name for the output file my program crushes.
For the input file I already have this one created in the project folder, so I just enter the name of that file.
This is the code:
#include <stdio.h>
#include <stdlib.h>
FILE *IN, *OUT;
int main(int argc, char* argv[])
{
if (argc < 2)
{
printf("Error: missing command line arguments!\n");
return 1;
}
printf("Enter the name of the file with the input data: ");
scanf("%s", argv[1]);
printf("\nEnter the name of the file for the output data: ");
scanf("%s", argv[2]);
IN = fopen(argv[1], "r");
OUT = fopen(argv[2], "w");
fclose(IN);
fclose(OUT);
return 0;
}
You're complete mis-understanding the purpose of argc and argv. They are supposed to receive the supplied command line argument (program parameters) before the program startup, not supposed to hold the scannned input at runtime.
Quoting C11, chapter §5.1.2.2.1,
If they are declared, the parameters to the main function shall obey the following
constraints:
— The value of argc shall be nonnegative.
— argv[argc] shall be a null pointer.
— If the value of argc is greater than zero, the array members argv[0] through
argv[argc-1] inclusive shall contain pointers to strings, which are given
implementation-defined values by the host environment prior to program startup. The
intent is to supply to the program information determined prior to program startup
from elsewhere in the hosted environment.
and
If the value of argc is greater than zero, the string pointed to by argv[0]
represents the program name; argv[0][0] shall be the null character if the
program name is not available from the host environment. If the value of argc is
greater than one, the strings pointed to by argv[1] through argv[argc-1]
represent the program parameters.
To elaborate, when a program is invoked like
./a.out three total arguments
then, in your program
argc will be 4
argv[0] will be ./a.out
argv[1] will be three
argv[2] will be total
argv[3] will be arguments
argv[4] will be NULL (see the property for argv[argc] above)
(To generalize, argv[1] - argv[argc-1] will hold the supplied arguments, argv[argc] will be NULL)
You don't need to explicitly scan the input, those values will be populated from the host environment.
On the other hand, you cannot just invoke the program like
./a.out
and exptect argc to be 3 (or any other value, other than 1, for that matter) and argv[1] - argv[n-1] to be valid because at compile-time the invokes program has no way to know that you plan to supply some values at runtime. It's not clairvoyant.

Command line argument condition pset2 caesar

I'm just started with a course for learning C, and am bumping in a problem with command line arguments. The assignment is this (there is more, but this is the part about the command line argument at the start):
- Your program must accept a single command-line argument, a non-negative integer.
- If your program is executed without any command-line arguments or with more than one command-line argument, your program should print an error message of your choice and return 1.
- You can assume that, if a user does provide a command-line argument, it will be a non-negative integer (e.g., 1). No need to check that it’s indeed numeric.
So I came up with this code:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
int main(int key, string plain[]) {
if (key < 0 || plain[key] > 1)
{
printf("error\n");
return 1;
}
else
etc...code continues.
Now I've tried several things, but I'm running into a wall.The compiler doesn't want to accept the if-condition I came up with, saying there is an error with comparison between pointer and integer which refers to the bold condition on the list of the assignment. So I understood that the argv part of the command line argument is the array of strings that the user put in. So my thought was to tell the compiler that when the user gives more than one string it should give an error message, so I wrote "plain[key] > 1)". Or is my understanding of command line arguments completely off here? Thanks.
plain[key] access the key element of plain array of string pointers (argv).
The size of that array is expressed by key (argc).
So what you want is
if (key > 1)
{
//..
}
Moreover plain last element is key-1, 'cause is 0 based index.
You misunderstood the purpose of the arguments to main. The first int argument (usually named argc) is the number of items in the array argument.
And the array argument (usually called argv) contains all the arguments to your program (including the executable name) as text.
So if your executable is called foo, and you invoked it as foo 1 a bar, the arguments to main will be as follows:
int argc == 4
char **argv => {"foo", "1", "a", "bar"}
So if your program must accept a single argument, it must hold that argc == 2 and argv[1] is the argument, that you must convert to a number from a string.

Passing int using char pointer in C

I'm trying to figure out how to pass an int using a char pointer. It fails once the int value is too large for the char. This is what I'm trying to figure out:
char *args[5];
int i = 20;
/*some other code/assignments*/
args[2] = (char *)&i;
execv(path, args);
How would I do something like this if i was a bigger value, like 400?
Thanks in advance.
Programs simply do not take integers as arguments, they take strings. Those strings can be decimal representations of integers, but they are still strings. So you are asking how to do something that simply doesn't make any sense.
Twenty is an integer. It's the number of things you have if you have eighteen and then someone gives you two more. Twenty cannot be a parameter to an executable.
"20" is a string. It can represent the number twenty in decimal. But it's a sequence of two characters, the decimal digit '2' followed by the decimal digit '0'.
You pass strings to executables, not integers.
When you enter a command like tail -f 20, the number twenty is not one of the arguments. They are the string "tail", the string "-f", and the string "20" (the digit '2' followed by the digit '0'). There are no numbers in there, just strings (though one of them happens to represent a number).
You can do this:
int i = 10;
char parameter[32];
sprintf(parameter, "%d", i);
// parameter now contains the string "10"
args[2] = parameter;

Resources