Following a pointer in C - c

I will show the entire code, but look for the quotes above the pointers as I will be talking about my problem there. I will tell you what I think happened there at the quote comments. The code compiles and runs, I just need help understanding parts of the code.
#include <stdio.h>
#include <stdlib.h>
int *get_data(int num_grades);
float calc_average(int num_grades, int grades[]);
void display_average(float ave);
int main()
{
int num_grades = 10;
const int MAX_GRADE = 100;
Below this quote box at: int *result = get_data(num_grades);
I have a pretty simple understanding of pointers at this point, as I've been introduced to them recently, however I can't seem to wrap my head around what happens when you assign a function to a pointer. What I think should happen is that the pointer int *result should be pointing at an address. Instead its pointing to a function that is also a pointer i think. So is this a pointer to a pointer at: int *result = get_data(num_grades); ?
I will put the rest of my question at the get_data function below.
int *result = get_data(num_grades);
^ Above ^
if (num_grades ==0)
printf("no grades to average\n");
else
{
float ave = calc_average(num_grades, result);
display_average(ave);
}
free(result);
return 0;
}
float calc_average(int num_grades, int grades[])
{
float ave;
int i;
int sum = 0;
for (i = 0; i < num_grades; i++)
{
sum+=grades[i];
}
ave = (float)sum/num_grades;
return ave;
}
void display_average(float ave)
{
printf("average: %.2f\n", ave);
}
Below this quote box,
I think this is a function pointer that returns a int pointer?
So, inside the body of the function, we create a new pointer, allocate memory for it, assign grades for each 'pointee' i think, and then I'm not sure why a[i] = grade is working, what are these indexes coming from, I don't understand why this is working if there is no array declared. Can someone explain what is happening here? How does this work? I'm really confused here.
int *get_data(int num_grades)
{
int* a;
a = malloc(num_grades * sizeof(int));
int i;
for (i = 0; i < num_grades; i++)
{
printf("enter a grade: ");
int grade;
scanf("%d", &grade);
if(grade<=100)
{
a[i] = grade;
}
else
{
printf("grade needs to be > 0 and <= 100\n");
i--;
}
}
return a;
^ Above, this whole function ^
}

get_data is a function which returns a pointer to an integer. First of all:
int *result = get_data(num_grades);
in this line you are not assigning to result a pointer to function, but the result of the function being called with num_grades as argument. That is to say, to the a you calculated in the body of get_data. And after that:
int *get_data(int num_grades)
this is the declaration of a function called get_data which takes one int parameter and returns a pointer to int. You could rearrange the spaces like this:
int* get_data(int num_grades)
if it makes things clearer. In this context, saying that get_data is a pointer to function would not even make sense, since it's immediately followed by its body. For reference:
int (*get_data)(int num_grades);
this is how the declaration of a pointer to function taking one int param and returning an int looks like. And there can't be a function body after it.

... however I can't seem to wrap my head around what happens when you assign a function to a pointer.
You aren't assigning a function to a pointer; you're assigning the return value of the function (which happens to be an int * value) to a variable which happens to store int * values.
So is this a pointer to a pointer at: int *result = get_data(num_grades); ?
No. int * means 'pointer to int'.
I think this is a function pointer that returns a int pointer?
No. The function returns an int * (pointer to int). There is a function pointer in your code, though that isn't a function (because it's a function pointer) and it doesn't return anything (because it's not a function; it's a function pointer).
Remember, int * means 'pointer to int'.
and then I'm not sure why a[i] = grade is working, what are these indexes coming from, I don't understand why this is working if there is no array declared. Can someone explain what is happening here? How does this work? I'm really confused here.
The array[index] operator is actually a pointer[index] operator. It's syntactic sugar for *(array + index) or *(pointer + index).
Whenever an expression that has an array type is used (with the exception being taking the sizeof or &addressof an array), the expression is converted to a pointer. The pointer points to the first item of the array...
So whilst your pointer declaration will have different semantics for the sizeof and &addressof operators, it'll have the same semantics for the 'array subscript' operator.
A similar concept applies to functions (hence the "function pointer" explanation above). Technically, in your expression int *result = get_data(num_grades); you're not applying the function(argument) operator; you're applying the function_pointer(argument) operator. The expression denoting the function is converted to a function pointer...

Related

Where is the error in this function to print a random array?

I don't understand where the error is in the function.I need to print 2 arrays with random elements.
int *boo3(int *x , int n){
x = (int*) malloc(sizeof(int)*n);
int i;
for(i=0;i<n;i++){
x[i] = rand()%10-(rand()%10);;
printf("%5d ",x[i]);
}
printf("\n");
}
int main(int argc, char *argv[])
{
int *x ,*y;
int n , m;
int i,j;
printf("enter size of X[n]: ");
scanf("%d",&n);
printf("enter size of Y[m]: ");
scanf("%d",&m);
x=boo3(*x,n);
y=boo3(*y,m);
free(x);
free(y);
return 0;
}
There are several problems with this code:
x = (int*) malloc(sizeof(int)*n); overwrites the function parameter x.
No return statement in boo3,
x=boo3(*x,m) in this line, *x is dereferencing pointer x which gives you int
In main function, you tried to free uninitialized pointer x and y
In your code
int *boo3(int *x , int n)
This indicates that you should receive a return value from this function.
In general a return value can be error code or any data which you might want to use going ahead.
Just like a math function for addition, taking operands as an argument and returning the sum. In your case, it is a pointer to the memory you have been allocated with.
In boo3() function, you are allocating some memory and you need the pointer to that memory for further usage. boo3() doesn't return anything, however, in main() function, you are assuming that you have caught it, hence the problem.
You should return the pointer to data from boo3().
I can see in main() function,
x=boo3(*x,n);
This is alarming. You are dereferencing a int* pointer and passing an int (instead of int*) as an argument to boo3() function which expects a int*.
If you wish to assign the pointer declared in main() with the address of memory allocated in boo3(), then you don't catch it and change to
boo3(x, n);
boo3(y, m);
And change to
void boo3(int *x , int n)
However, ideally, the function should return and the value be caught as a return value. In that case, change to
int* boo3(int n)
At the end of boo3 add a return x;. And use it as
x = boo3(n);
Additionally, you are not checking if the malloc() has allocated any memory or not. You should check if the pointer is NULL to see if memory is allocated. It is minimum error-checking and handling you need to have. Secondly, malloc() returns a void*, so the typecast is needless.
The problem is, you do not return anything from the function boo3(), and try to use the return value. This causes undefined behavior.
You need to add a return x; at the end of the function so as to return the pointer holding the address of the allocated memory (and populated values).
That said, passing the pointer argument is not needed when you return the pointer from the function. Apart from the fact that your call does not even try to pass a pointer as the first argument, as expected by the function signature - to allocate memory to a pointer from a called function, you need to pass the address of the pointer anyways, passing the pointer alone will not suffice. You don't need to do that, just define the function as
int *boo3(int n) { //......
and in the end, add
return x;
and from main(), call it like
x=boo3(n);
y=boo3(m);
There are many issues in your code.
Following has been corrected:
boo3 now simply returns the pointer to the allocated memory filled with random numbers, the useless x parameter has been removed and the function now contains the missing return statement. This is actually the main problem in your code.
The pointless (int*) cast has been removed from malloc.
The code is formatted properly.
Variables are declared as close as possible to their scope. This is the idiomatic way, declaring all variables at the start of the scope is a thing from the last century.
Usage of meaningful variable names.
This is a correct version of your program:
#include <stdlib.h>
#include <stdio.h>
int* boo3(int n) {
int *array = malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
array[i] = rand() % 10 - (rand() % 10);;
printf("%5d ", array[i]);
}
printf("\n");
return array;
}
int main(int argc, char* argv[])
{
int sizex, sizey;
printf("enter size of X[n]: ");
scanf("%d", &sizex);
printf("enter size of Y[m]: ");
scanf("%d", &sizey);
int *xvalues = boo3(sizex);
int *yvalues = boo3(sizey);
free(xvalues);
free(yvalues);
return 0;
}
Disclaimer: for brevity there is no error checking for scanf and malloc.

Passing pointer array to function in C

I am having trouble passing a pointer array to a function. I will post a simple example that still doesn't work for me. Could you please tell me what I am doing wrong?
#include <stdio.h>
#include <stdlib.h>
int transformare(int *v[1])
{
*v[1] = 10;
return 0;
}
int main()
{
int v[1];
printf("n = ");
scanf("%d", &v[1]);
transformare(&v);
printf("%d", v[1]);
return 0;
}
You have two problems:
Array indexes are zero-based. That is, an array of N elements have indexes from 0 to N - 1 (inclusive)
The declaration int *v[1] declares v as an array of one pointer to int, not as a pointer to an array of one int. That would be int (*v)[1]. Which is also the type of &v from the main function.
The solution to the second problem (using the correct type) then leads to a third problem, as it means that *v[0] is incorrect due to operator precedence. You need to use parentheses here too, as in (*v)[0].
However the second (and the following third) problem is moot, since you don't need to pass arrays "by reference".
Arrays naturally decays to pointers to their first element. When using plain v when a pointer to int is expected, the compiler will automatically translate it as &v[0].
That means you could declare the function to simply take an int * as argument, and simply pass plain v as the argument.
First, please note that indizes are 0-based in C, i.e. the first (and - in your case only) element is v[0].
Concerning passing it, just define the parameter as pointer to int, i.e. int*. A variable of type int[1] will decay to a pointer to int when passed to a function (so there is no need to write transformare(&v), its transformare(v).
int transformare(int *v)
{
v[0] = 10;
return 0;
}
int main()
{
int v[1];
printf("n = ");
scanf("%d", &v[0]);
transformare(v);
printf("%d", v[0]);
return 0;
}

Why is there an asterisk after a function type declaration in C?

My question is in the title and is more of a syntax related question. Does anyone know what the * is doing in the function below? See here:
int* reat(int *n)
{
int i, *array;
do
{
printf("n="); scanf("%d", n);
} while (*n < 1);
array = (int *)malloc(*n * sizeof(int));
for (i = 0; i < *n; i++)
{
printf("%d. broj: ", i + 1);
scanf("%d", array + i);
}
return array;
}
The syntax
int i, *array;
declares i to be a variable of type int and array to be a variable of type int*. This sort of declaration isn't particularly common, but is legal C code.
Hope this helps!
The * in int* reat(int *n) indicates in the return that this function is returning a pointer to an integer value rather than the integer value itself. The * indicates in the argument list that this function also wants a pointer to an integer value rather than a "raw" integer value for its argument.
For example,
int x = reat(n); // assume n is a pointer to an int
probably won't compile on most systems. If it does, you'll be storing a memory address in x rather than the integer value you were expecting. Instead write
int *x = reat(n)
to store in x the pointer (to some integer value) returned by reat(). Consider this function:
int addone(int x) {
return 1 + x;
}
This function takes an integer value for its argument. To access the value of the integer pointed to by the return from reat() and use it in addone(), we'll need to call it like so:
int *x = reat(n)
addone(*x)
Thereby dereferencing x with the * operator to access the integer value it points to. addone(x) won't compile because x, without dereferencing, is a memory address and not an integer.
Understanding when the * is being used to define a pointer and when its being used to dereference one will become second nature over time. Trust that any time it shows up in a function definition, whether as an argument or a return, it indicates a pointer is being used.

assign dynamic array in a function and send it back to the caller in C

I have been using java for long time but for some reason I need to use C (ANSI C not C++) to write a simple code. I need to pass the pointer from outside to a function, allocate some memory to the pointer and assign some values also before the function return. I have my code like
#include <stdio.h>
#include <stdlib.h>
void test(int *a)
{
int n=3;
// I have to call another function t determine the size of the array
n = estimatesize(); // n >=3
// I tried fix size n=10 also
a = (int*)malloc(n*sizeof(int));
a[0] = 1;
a[1] = 2;
a[2] = 3;
}
void main(void)
{
int *s=NULL;
test(s);
printf("%d %d %d", s[0], s[1], s[2]);
}
I don't know why the code crashes. I thought at the beginning it is estimatesize() return wrong number but even I fix n to 10, the error still there. So I cannot pass a pointer to a function for memory allocation? If so, how can I dynamically create memory inside a function and pass it out? I know it may be a safe problem in this way but I just want to know if it is possible and how to do that. Thanks.
There are two solutions to this: Either return the pointer from the function, or pass the argument by reference.
For the first one, you simply don't take any arguments, instead you return the pointer:
int *test(void)
{
int *a = malloc(...);
...
return a;
}
int main(void)
{
int *s = test();
...
}
For the second one, you need to pass the address of the pointer, in other words a pointer to the pointer, using the address-of operator &:
void test(int **a)
{
*a = malloc(sizeof(int) * 3);
for (int i = 0; i < 3; ++i)
(*a)[i] = i;
}
int main(void)
{
int *s;
test(&s);
...
}
The reason it doesn't work now, is because the pointer (s in main) is passed by copying it. So the function test have a local copy, whose scope is only in the test function. Any changes to a in the test function will be lost once the function returns. And as s is copied for the argument, that means that s in main never actually changes value, it's still NULL after the function call.

How to navigate through arrays using pointers?

Why isn't my code working?
#include <stdio.h>
int main()
{
int test[] = { 3, 9, 7 };
printf("%d", find(test, 3));
return 0;
}
int find (int array[], int size)
{
int i, largest, where;
largest = array [0];
for (i=0; i<size; ++i) {
if (array[i]>largest) {
largest = array[i];
where = i;
}
}
return (int) *(&array+sizeof(int)*where);
}
I know I can replace:
return (int) *(&array+sizeof(int)*where);
with:
return array[where];
but that isn't the point of the exercise.
Pointer arithmetic doesn't work the you think it does. You're looking for:
return *(array + where);
array is already a pointer, and pointer arithmetic just "does the right thing" when adding.
You might be confusing yourself because of the int array[] in your function signature - that's just syntatic sugar for int *array. You really have a pointer, not an array.
Since there is some misinformation flying around in other answers, I'm going to write a more complete explanation here. This function signature:
int find(int array[], int size)
really means:
int find(int *array, int size)
The use of the [] is just syntactic sugar, as mentioned above. When you call the function, like:
find(test, 3);
test is decaying automatically into a pointer to its first element. It's identical to if you had called:
find(&test[0], 3);
Now, looking at your return statement, you can see that:
return (int) *(&array+sizeof(int)*where);
Doesn't make sense - first of all &array is the address of parameter - in this case a pointer parameter, but that doesn't really matter. If you add to it and dereference, you're going to return some random data from your stack, not not from the array you want to.
Secondly, the multiplication by sizeof(int) is unnecessary. Pointer arithmetic in C already includes an implicit multiplication by the size of the pointed-to type. What you're really trying to return is:
return array[where];
which is equivalent to:
return *(array + where);
You're greatly overcomplicating this...
return array[where]; // this means, take the base memory location of "array" then
// add in an offset of where and dereference the result
That's exactly the same as:
return *(array + where);
The fact is that in your main function you have an array called test, once you pass this to your find() function the array will decay to a pointer. So if you now know that you have a pointer you should see why you shoud not be grabbing the address like this:
&array
And you don't need to be adding the "sizeof" offset, because that's given by the type of the pointer (int *)
You should do:
return *(array+where);
since where is the offset to the array. You don't need sizeof(int) anymore

Resources