I'm new to the C programming language and beginning to mess around with pointers and allocating memory to objects. I wanted to make a simple program that would read in (x) elements from the user and simply print them out using functions.
This was my inital code at the beginning. The code was reading in the user input properly but it gave the wrong output and crashed when displaying elements within the main function.
int main() {
int *myArr;
int myArrSize;
getInputArr(&myArrSize, &myArr);
for (int i = 0; i < myArrSize; i++) {
printf("Element No.%i: %i\n", i, myArr[i]);
}
free(myArr);
return 0;
}
void getInputArr(int *arrSize, int *arr) {
printf("Please Enter Length of Array: \n");
scanf("%i", arrSize);
arr = (int *) malloc(*arrSize * sizeof(int));
printf("Enter %i Numbers!\n", *arrSize);
for (int i = 0; i < *arrSize; i++) {
scanf("%i", &arr[i]);
}
}
After messing around, I finally got it to work using double pointers but I am unsure how it completely works, could someone explain why the code below behaves as expected?
int main() {
int *myArr;
int myArrSize;
getInputArr(&myArrSize, &myArr);
for (int i = 0; i < myArrSize; i++) {
printf("Element No.%i: %i\n", i, myArr[i]);
}
free(myArr);
return 0;
}
void getInputArr(int *arrSize, int **myArr) {
printf("Please Enter Length of Array: \n");
scanf("%i", arrSize);
*myArr = (int *) malloc(*arrSize * sizeof(int));
printf("Enter %i Numbers!\n", *arrSize);
for (int i = 0; i < *arrSize; i++) {
scanf("%i", &((*myArr)[i]));
}
}
There are several surprising things in your implementation, but in the end they all make sense, and indeed they must be present in order for this implementation to work.
int *myArr
in main
to simulate an array of int
, but in getInputArr
you refer to it using a "double pointer" int **myArr
. But this makes sense, because any time you want to return something from a function "by reference" like this, you need to use a pointer -- an extra pointer. To return an int by reference, you'd use an int *
. But to return an int *
by reference, you need an int **
. The fact that you (correctly) call getInputArr(&myArrSize, &myArr)
in main
shows that getInputArr
's second argument is going to be an int **
.scanf
, you do not have an &
next to the argument you pass to scanf
for %d
to read into. This is highly unusual, but in this case it's absolutely correct, because arrSize
is already a pointer.*myArr = (int *) malloc(*arrSize * sizeof(int))
. This was the first thing I spotted in your initial (nonworking) implemenation that was quite wrong. In getInputArr
, myArr
is a pointer to the pointer that you want to set. So *myArr
is the pointer that you want to set.scanf("%i", &((*myArr)[i]));
. This looks pretty ugly, and there are probably simpler ways to write it, but it's correct. Let's break it down. Again, myArr
is a pointer to the pointer you want to work with. So *myArr
is the pointer you want to work with. So (*myArr)[i]
is one element of the simulated array (pointed to by the pointer) that you want to work with. You need explicit parentheses, because if you wrote *myArr[i]
this would mean, "take the i
'th element pointed to by myArr
, interpret it as a pointer, and take the contents." But what you want (and, with the parentheses, you have) is "take myArr
, interpret it as a pointer, take the thing that it points to, which is *myArr
, and interpret that as a pointer, and finally take the i
'th element that it (the second pointer) points to."