I see three issues here (may be more).
First, the assignment
const char *temp = argv;
assigns a pointer to an array of char pointers to a const char pointer (instead of assigning a char pointer, what probably was the intention).
Second, the function input_number is invoked
// Remember, now temp == argv
input_number(temp, argc);
but inside it there is this call
// Remember, now c == temp == argv
scanf("%c", *c);
which essentially overrides the value that the pointer that *c holds points to. What follows, since now c == argv, scanf overrides the value that the pointer to the first element of the array of program arguments points to, that is, the first character of the name of its executable. Indeed, if we try to print the executable name before and after such assignment (example code)
#include <stdio.h>
void f (const char **c) {
printf("%s\n", *c);
scanf("%c", *c);
printf("%s\n", *c);
}
int main(int argc, char *argv[]) {
const char *c = argv;
f(c);
return 0;
}
we receive (the input for scanf is a)
./prog
a/prog
what probably was not the intention.
Now, the third issue is, the assignment in the second issue works. But as far as I know, modifying a const value (**c in this case) results in undefined behavior. That is, now it works, but in some other execution, compiler, computer etc. it may not. Compare:
Edit: another issue is of course what Jabberwocky and the compiler say: you try to call atoi with a pointer to pointer to char, while it expects a pointer to char.
Edit: worth to note, in the condition
if (!(f >= '0' && f <= '9'))
the constants '0' and '9' are of type int (see [1]), so the comparisons are fine. But f is both declared as int and is assigned the result of atoi, therefore for me it is expected to be just an int, therefore in my opinion it would be clearer to write the comparisons using only integer constants, that is
if (!(f >= 0 && f <= 9))
Edit: another issue is that the function input_file is declared with a char parameter, that is
void input_file(char c);
but then it's called with an int parameter, that is
// Where c is declared as "int c;"
input_file(c);
It would be clearer in my opinion to keep the types the same: both chars or both ints.
An interesting thing would be to know why it works at all: how can you place an int variable, where there is a char variable expected? For one, C99 standard draft says that
[t]he type char, the signed and unsigned integer types, and the enumerated types are
collectively called integer types.
So, char is an "integer type". Then, cppreference.com says that
[a] value of any integer type can be implicitly converted to any other integer type.
and later
if the target type can represent the value, the value is unchanged
But what is the value of c here? It is declared as
int c;
So, first, cppreference.com says that
[t]here are four kinds of storage duration in C:
- automatic storage duration. The storage is allocated when the block in which the object was declared is entered and deallocated when it is exited by any means (goto, return, reaching the end).
and then it says that
[i]f an initializer is not provided:
- objects with automatic storage duration are initialized to indeterminate values (which may be trap representations)
So, c in the moment of the conversion has an indeterminate value. What follows, it cannot be sure before actually executing the program whether "the target type can represent the value". What follows, we need to look for another rule about converting chars to ints: cppreference.com says that
- otherwise, if the target type is unsigned, the value 2b
, where b is the number of bits in the target type, is repeatedly subtracted or added to the source value until the result fits in the target type. In other words, unsigned integers implement modulo arithmetic.
- otherwise, if the target type is signed, the behavior is implementation-defined (which may include raising a signal)
And the C99 standard draft says that
[t]he implementation shall define char to have the same range,
representation, and behavior as either signed char or unsigned char.
Ultimately, not going into details, it is up to the particular implementation of C you use to decide what is going to happen when you try to call a function expecting a char with an int if the value is beyond range (and, again, we don't know whether it will be beyond range or not when the code will be executed).
Edit: another issue is, in the function input_file there is this line
strcpy(Contact.name, &file);
What it does is it copies a single character into a char array. An address of a single character is possibly not expected by strcpy because man 3 strcpy reads that
[t]he strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest.
Unfortunately, I see no clues neither in the man page nor on the internet how this function shall behave if there is no \0. In this answer to another question, Sourav Ghosh says that it is undefined behavior. And if he is true, I suppose that this is not what you expected.