0

I apologize if this is a relatively simple question. I'm trying to get a handle on C programming after having learn't python. I'm trying to read a command line argument like ./myprogram 8, and to be able to access that 8. I've managed to get it working by directly accessing the users input like printf("%s\n", argv[1]); But I'm struggling to store it as a variable. The code below runs but it doesn't print the 8 at all.

#include <stdio.h>

int main(int argc, char* argv[]) {
    int UserInput1;

    UserInput1 = argv[1];
    printf("%s\n", UserInput1);

    return 0;
}

I appreciate any and all help, and i thank you in advance for your time

  • 1
    As the declaration says, `argv[1]` is of type char-array. So there is no way to assign that to an `int UserInput1` without performing some conversion (e.g. `strtol`). Furthermore the `printf` format specifier `%s` needs a `char *` argument but you pass an `int` argument. – Wör Du Schnaffzig Apr 12 '21 at 11:36
  • @Jeremiah Longlow Note this post does not ask a particular question. Consider adding one to help focus the issue. – chux - Reinstate Monica Apr 12 '21 at 12:33

3 Answers3

2

Arguments passed through the command line are passed as strings (char*). To store it as an int variable you need to convert it to an integer.

int main(int argc, char* argv[]){
    if(argc < 2){
        fprintf(stderr, "Pass an integer through the command line\n./%s 8\n", argv[0]);
        return -1;
    }
    long intarg = strtol(argv[1], NULL, 10);
    printf("%ld\n",intarg);
}

You can also check if user passed an argument through argc which is the number of arguments.

Irelia
  • 3,407
  • 2
  • 10
  • 31
  • Strictly spoken it should be `strtol(argv[1], NULL, 10)` – Jabberwocky Apr 12 '21 at 11:42
  • This way we successfully prevent any error checking on `strtol` making it no better than `atoi`. Of course, the endptr arg should be used and as it is a double pointer, the original pointer it points to should be checked on the difference to the first argument after the return of the `strtol` function. If there is no difference, then `argv[1]` did not contain a numeric literal. If it is different, at least the first few characters of `argv[1]` were numeric. If the `argv[1]` is completely numeric, the original pointer should point to a whitespace or `\0`. – Wör Du Schnaffzig Apr 12 '21 at 12:02
  • Yes error checking should be done. In this specific case though because I was printing intarg and in probably any case the return value would be checked it felt unnecessary. If it didn't print the value I requested then we can always know that it failed. But it is good to point out. – Irelia Apr 12 '21 at 12:16
  • 1
    @Jabberwocky Either `strtol(argv[1], NULL, 10);` or `strtol(argv[1], 0, 10);` is fine. A style issue, not a "should be" one. – chux - Reinstate Monica Apr 12 '21 at 12:35
  • 1
    @pqans "prevent any error checking on strtol making it no better than atoi" . `strtol()` is better than `atoi()` as `atoi()` is UB on overflow. `strtol()` is well defined. The rest of the `endptr` idea is good. – chux - Reinstate Monica Apr 12 '21 at 12:39
  • UB = ultimately blind? – Wör Du Schnaffzig Apr 12 '21 at 12:43
  • @pqans UB is [Undefined behavior](https://stackoverflow.com/a/2397995/2410359). – chux - Reinstate Monica Apr 12 '21 at 12:59
  • Yes I just read the [FAQ](http://c-faq.com/null/nullor0.html) you can use 0 or NULL interchangeably however when dealing with a pointer context, NULL is referred. – Irelia Apr 12 '21 at 13:41
2

The code below runs but it doesn't print the 8 at all.

The number one thing to learn here is to enable all compiler warnings. This saves you (and us) time.

A good, well enabled compiler with report something like

UserInput1 = argv[1];
// warning: assignment to 'int' from 'char *' makes integer from pointer without a cast [-Wint-conversion]

printf("%s\n", UserInput1);
// warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat=]

Code is attempting to change a pointer to an int. Instead, use a function to read the string pointed to by argv[1] as decimal text and convert to an integer.


read a command line argument ... and to be able to access

argv[1] deserves some tests. Not all strings represent an integer.

Does it exist?

Is there a string to parse?

if (argc < 2) {
  puts("argv[1] missing");
}

Convert from a string to an integer

Do we want to limit the range? Is "123456789012345678901234567890" OK?

Let us assume the int range.

C, sadly, does not have a robust conversion function to int, but does them for wider types.

errno = 0;
char *endptr;
long number = strtol(argv[1], &endptr, 10);

if (argv[1] == endptr) {
  puts("No conversion");
} else if (errno == ERANGE) {
  puts("Outside long range");
} else if (number < INT_MIN || number > INT_MAX) {
  errno = ERANGE;
  puts("Outside int range");
} else if (*endptr)) {
  puts("Extra text after the number");
} else {
  int UserInput1 = (int) number;
  printf("Success %d\n", UserInput1);
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

You could also just change the type of your UserInput variable from int to char