The program you have posted is doing following (in the given sequence below):
- Declare/define a pointer in a function
- Allocate memory to that pointer in some other function and fill that memory with user input
- Print the content of that memory using another function
- Deallocate memory and exit
The part which is confusing you is 2.
I don't understand why ar in the input function is an int** and not an int* ....
If you want to allocate memory to a pointer (or want to change the pointer, like, e.g. making it point to some other memory or reallocating memory etc.) in some other function, you need access of that pointer in that function and you can get access if you have the address of that pointer.
And that's why here the address of ar pointer is passed:
input(&ar, &n);
Pass address of ar to input() function and in the input function dereference that address (i.e. *ar) will give the ar pointer (declared/defined in main()).
For better understanding, I am renaming the ar parameter of input() function to input_ar:
void input(int *input_ar, int *n) {
.....
.....
When input() function called from main() function, the in-memory view would be something like this:
input_ar ar
+-----+ +-----+
| 200 | ----> | NULL|
+-----+ +-----+
[200 is address of ar pointer]
In input() function, when you do:
*input_ar = (int*)malloc(*n * sizeof(int));
dereferencing input_ar (i.e. *input_ar) will give ar:
input_ar *input_ar (ar) (newly allocated memory block)
+-----+ +-----+ +-----+
| 200 | ---------> | 300 | ----> | |
+-----+ +-----+ +-----+
[300 is address of the newly allocated memory block]
Hence, by dereferncing input_ar, the pointer ar can be changed in input().
I mean I try to replace int** ar with int* ar and delete the * in int* ar = NULL in the main function and there's no compile error.
Note that if you remove the * from declaration of ar in main() then ar will be a variable of type int, that means, it will not be a pointer but a variable which can hold a int type value. If you do this change in your program, you have to make changes in other places as well like, the way you are taking input from user in input() function, respective changes in output() function etc.
You have not shown the program with the changes that you have done after deleting * from ar declaration so, I will just talk about the ar argument passed to input():
This is what you might have tried:
int ar;
input (&ar, &n);
and in input():
void input(int *ar, int *n) {
printf("Number of elements: ");
scanf("%d", n);
ar = (int*)malloc(*n * sizeof(int));
.....
Note that the ar pointer parameter is a local variable of input() function.
When input() function is called from main() function, the ar will hold the address of ar variable of main() function.
If you want, you can make changes in the value of ar variable using the pointer ar in input() function, e.g. - *ar = 9;
This will assign value 9 to variable ar (of main()). The in-memory view would be something like this
ar (of input()) ar (of main())
+-----+ +-----+
| 200 | -------------> | |
+-----+ +-----+
[200 is address of ar variable of main()]
But when you do
ar = (int*)malloc(*n * sizeof(int));
the ar has lost the address of ar variable of main() function and newly allocted memory reference is assigned to pointer ar of input(), i.e.
ar (of input()) newly allocated memory block
+-----+ +-----+
| 400 | -------------> | |
+-----+ +-----+
[400 is address of the newly allocated memory block]
You can write/modify the contents in this memory but when returned from input(), this memory reference will be lost because input() is not returning anything and this will be a memory leak in your program.