I'm trying to understand how the pointers in this piece of code works:
void allocateArray( int **arr, size_t size, int value )
{
*arr = malloc( size * sizeof( int ));
if ( *arr != NULL )
for ( size_t i = 0; i < size; ++i )
*( *arr + i ) = value;
}
int main( void )
{
int *vector = NULL;
allocateArray(&vector,5,45);
free( vector );
return 0;
}
If I declared a pointer to an int ( *vector ), how passing its address makes it a pointer to a pointer to int ( **arr )? I mean, how does it work, now that vector's address in the memory will be overwritten!
C passes function parameters by value. So, to allow a function to modify a variable provided by the caller, a pointer to it must be passed. And the function must dereference the pointer to make the modification.
void foo_1 (int a) {
a += 1; /* caller will not see any change to a */
}
void foo_2 (int *ap) {
*ap += 1; /* caller will see value has changed */
}
int a = 0;
foo_1(a); /* a is still 0 after return */
foo_2(&a); /* a becomes 1 after return */
The & operator results in a value that represents the address to the object it is applied to, and the resulting type is "pointer to (type of the object)". In the above example, the result of &a is "pointer to int".
Nothing is fundamentally different if the variable is a pointer type.
void foo_1 (int *a) {
a = malloc(sizeof(int)); /* caller will not see any change to a */
}
void foo_2 (int **ap) {
*ap = malloc(sizeof(int)); /* caller will see value has changed */
}
int *a = 0;
foo_1(a); /* a is still 0 after return */
foo_2(&a); /* a becomes initialized to memory allocated by malloc */
In the above example, since a is a pointer to int, type of &a is "pointer to pointer to int".
A pointer is a term that is used to refer to the address of an object. The address of an object is a value that represents where the object resides in memory. Knowing that address means the object can be read and modified. A pointer variable is a variable that can store the address of an object.
Normally, the name of a variable is used to represent the object. By object, I just mean the memory used by the variable, and its semantic representation, aka, its type (often, the terms variable and object are used interchangeably, but to me, the difference is that a variable has a name). Reading and modifying the object is done through the name. One way to obtain a pointer to an object is to apply the unary & operator to the name of a variable. A pointer variable holding that address is thus a pointer to that object. And now, that same object can be read and modified via the pointer by dereferencing the pointer, using the unary * operator.
int a = 0;
int *ap = &a;
a += 1; /* a now has the value 1 */
*ap += 1; /* a now has the value 2 */
A dynamically created object, i.e. through malloc(), does not have a name. But, malloc() returns a pointer through which the object can be read and modified.
int *ap = 0; /* ap initialized to NULL */
ap = malloc(sizeof(int)); /* ap points to dynamically allocated int */
*ap = 0; /* int pointed to by ap now holds value 0 */
*ap += 1; /* int pointed to by ap now holds value 1 */
Your allocateArray() function combines both of these uses of a pointer into a single function.
int *vector = NULL; /* vector is pointer to int variable initialized to NULL */
allocateArray(&vector,5,45); /* the address of vector is passed to allocateArray */
Since the address of vector is passed to allocateArray(), that function now has the means to modify the object named vector by derferencing the pointer value it received. The pointer value is received in the arr argument:
void allocateArray( int **arr, size_t size, int value )
And, by dereferencing arr, it is updating the vector object with the value returned by malloc():
*arr = malloc( size * sizeof( int ));
Perhaps the function would have been more clear if the allocation, initialization of the memory, and then the update of the vector variable happened in multiple steps.
void allocateArray( int **arr, size_t size, int value )
{
int *vec = malloc( size * sizeof( int )); /* vec points to size contiguous int */
if ( vec != NULL )
for ( size_t i = 0; i < size; ++i )
vec[i] = value; /* vec[i] set to value */
*arr = vec; /* return vec into first parameter */
}
Some background:
Parameters in C are always passed by value. For example, consider the code
void some_func(int i) { i = i + 2; printf("i = %d\n", i); }
void main_func() {
int n = 5;
some_func(n);
printf("n = %d\n", n);
}
Output:
i = 7
n = 5
The main function passes the value 5 to some_func, which changes its own local copy in i but cannot change n in the calling function.
Now, suppose you want to write a function that does change the caller's value. You can do this by passing the address of the variable you want to change:
void new_func(int *i) { *i = *i + 2; printf("*i = %d\n", *i); }
void main_func() {
int n = 5;
some_func(&n);
printf(" n = %d\n", n);
}
Output:
*i = 7
n = 7
The "trick" is that new_func doesn't change the value of its parameter; it changes some other value -- the variable its parameter points to. So the rule is:
If you want a function to alter a variable, you pass the address of that variable.
In other words, if you want a function to change foo, you pass a pointer to foo.
Application to your code:
The main function declared a pointer, vector, that has no memory allocated to it. Its value is NULL. It calls allocateArray() to allocate memory and assign it to vector. But that means it must change the value of vector from NULL to the address of the newly-allocated memory. Following the same rule as above, in order to change vector, you need to pass its address to allocateArray(). And since vector is of type pointer-to-int, its address is of type pointer-to-pointer-to-int.
To be clear: you haven't changed the type of vector; you've simply passed its address. So within allocateArray(), arr is of type int **, and *arr is of type int *. Syntactically, you use *arr exactly as you would use vector.
So vector is a pointer to an int, so the address of vector is a pointer to a pointer to an int(&vector is equivalent to int **). vector = *arr, not &vector = *arr. Therefore vector is gets the address that the call to malloc returns, not the address of vector. I think the confusion is between the address of vector and the address that vector points to.
Inside the function main(), vector is a single variable on the stack (probably 4 bytes). The address of the first of those 4 bytes is &vector. When you call allocateArray(), you allocate a chunk of memory on the heap. The address of those bytes has to be stored somewhere. The function stores that 4-byte address at the memory address passed to it, i.e., the bytes allocated on the stack.
So when we return to main(), the variable vector now points to the start of the allocated block. Because it is declared as a pointer to int, that memory will be accessed as an array of ints.
Memory addresses are just numbers like any other number. The "type" you assign to it in C just tells the compiler what you plan to do with the memory at that address. Declaring vector as an int * simply tells the compiler to fetch an int from memory when it sees *vector. The memory used to store the value of the variable itself is just the stack, exactly as if it had been a regular int, and that memory has nothing to do with the memory it points to.
We need to take the address of the stack variable because otherwise allocateArray() would have no way to affect the value of the variable vector, which is not defined in its scope, so we just have to tell it where to look.
Probably a better way to implement this is to remove that first argument to allocateArray() and have it return the address of the allocated block. Then we can just assign vector to that return value in main() where it's in scope.
int main( void )
{
int *vector = NULL;
allocateArray(&vector,5,45);
free( vector );
return 0;
}
As you see in the main function, when the statement allocateArray(&vector,5,45); executed,
the memory address of a 5-element array will be passed to the vector variable; However, if you use allocateArray(vector,5,45);(assume that was corrected modified), then the memory address would not passed to the vector variable, because the function allocateArray(vector, 5, 45) now just passed a value of vector into the function.
Related
In the following code p is pointer to an int. It is quite clear that p points to the address of i. Through my research i know &p points to the address of pointer p. But i don't get why would you need separate address for that. And also when would you use &p.
int main() {
int i = 3, *p = &i;
printf("%p",&p);
printf("%p",p);
return 0;
}
If p is pointer to int then
int **q = &p;
When you want to use pointer to pointer, then use the address of a single pointer to assign it to pointer to pointer.
Just to make a point that pointer is also a data-type and it stored in the memory location and it holds a valid memory location as its value. The address in which this valid memory location is stored is given by &p
Your printf() also needs to be fixed. %p expects void *
printf("%p",(void *)p);
But i don't get why would you need separate address for that
You don't, but there exists the address of operator so you can take the address of a pointer, which is what
printf("%p\n", &p);
is printing.
And also when would you use &p
There are cases where this might be useful, consider for example that you need to pass a pointer to a function which could be reassigned into the function, you can do something like this
int allocateIntegerArray(int **pointerToPointer, size_t someSize)
{
if (pointerToPointer == NULL)
return 0;
*pointerToPointer = malloc(someSize * sizeof(int));
return (*pointerToPointer != NULL);
}
then you could use this funciton the following way
int *pointer;
if (allocateIntergerArray(&pointer, 10) == 0)
{
fprintf(stderr, "Error, cannot allocate integer array\n");
/* do some extra cleanup or recover from this error, or exit() */
exit(0);
}
The pointers themselves are also variables and as such they need to be sotred somewhere, so the address of a pointer tells you where is the pointer stored, it's value tells you where it is pointing to.
By knowing where it is stored you can do things like the one explained above.
A trivial example:
int nochange(int *c, int *val)
{
c = val; // Changes local pointer c to point to val
// Note that C passes copies of the arguments, not actual references.
}
int do_change(int **c, int *val)
{
*c = val; // Accesses the real pointer c at its real location and makes
// that one point to val
// Even though c is a pointer-to-pointer copy, its value is
// copied too, and the value is the address of the real c
}
int main()
{
int a = 1;
int b = 2;
int *c = &a; // A pointer is also a datatype that resides in memory
printf("%d\n", *c); // Will print 1
nochange(c, &b);
printf("%d\n", *c); // Will print 1
do_change(&c, &b);
printf("%d\n", *c); // Will print 2 because c now points to b
}
I have a similar answer with a bit more detail here about pointer vs pointer-to-pointer: pointer of a pointer in linked list append
I am trying to read an array of data and receiving an access violation. I can read the data from the array within the function that the array was allocated using:
AllCurrentData[newLineCount].data[tabCount] = malloc(length + 1);
strcpy( AllCurrentData[newLineCount].data[tabCount], buffer );
printf("%s", AllCurrentData[newLineCount].data[tabCount]);
But can't read it outside of the function. This is where I get the access violation, looks like it is trying to read a null location.
How can I access the data in the array AllCurrentData in a different function? thanks!
Extra info:
typedef struct current{
char **data;
}CurrentData;
AllCurrentData is declared in main:
CurrentData *AllCurrentData = '\0';
Function call
getCurrentData(current, AllCurrentData);
printf("%s", AllCurrentData[0].data[0]); //<----- error here
CurrentData *AllCurrentData = '\0';
This declares a pointer. This pointer is a variables that holds a number that is interpreted as an address. You initialize the pointer to '\0' (null).
getCurrentData(current, AllCurrentData);
Here you pass this pointer as parameter to function getCurrentData. As a pointer is a variable, this variable is passed by value, meaning that the function receives a copy of that value (the number that represents an address).
When inside the function if you write
AllCurrentData = malloc...
you modify that copy of the pointer, so outside the function AllCurrentData will still be '\0'.
You need to pass a pointer to that pointer (Inception, I know).
getCurrentData(current, &AllCurrentData);
getCurrentData(.., CurrentData **p_AllCurrentData) {
*p_AllCurrentData = malloc(...);
}
Let me explain this concept on a simpler example:
int *v = NULL; // here v is a pointer. This pointer has value 0 (invalid address)
v = malloc(10 * sizeof(int)); // here the pointer is assigned a valid address, lets say 0x41A0
f(v);
void f(int *x) {
// here the pointer x receives a copy of the value of the pointer v, so x will be, like v, 0x41A0
x[0] = 4;
/*this is ok as you modify the memory at the address 0x41A0,
so this modification is seen from outside the function, as v points to the same address.*/
x = malloc(...);
/* this is NOT ok, as x receives a new address, lets say 0xCC12.
But because x has a copy of the value from v, v will still be unmodified.*/
}
so if you want to allocate a pointer inside a function this is not ok:
int *v = NULL; // here v is a pointer. This pointer has value 0 (invalid address)
f(v);
void f(int *x) {
// here the pointer x receives a copy of the value of the pointer v, so x will be, like v, NULL
x = malloc(...);
/*this is NOT ok, as x receives a new address, lets say 0xCC12.
But because x has a copy of the value from v, v will still be unmodified,
it will still have NULL.*/
}
The right way to do is:
int *v = NULL; // here v is a pointer. This pointer has value 0 (invalid address)
// as v is a variable (of type pointer to int), v has an address, lets say 0xAAAA.
f(&v);
void f(int **p_x) {
/* here the p_x is a pointer to (a pointer of int),
so this pointer receives a copy of the value the address of p, so p_x is 0xAAAA.*/
*p_x = malloc(...);
/* lets say malloc returns the address 0xBBBB. This will be the address of our vector.
*p_x= says we modify the value at the address p_x. So the value found at the adress 0xAAAA
will be 0XBBBB. But because 0xAAAA is the address of v, we effectively modified the value of v
to 0xBBBB. So now v has the address of our starting vector.*/
// if you want to modify values inside this vector you need:
(*p_x)[0] = ...
}
I'm trying to change where the pointers min and max are pointer to, but it seems that the "change" is not sticking outside the function's scope (after the function has run). Before running the function I set *min and *max to point to a "double m = 0". I'm kind of a NOOB so any advice would be appreciated.
int min_max(double * min , double * max , int size , double a[]){
int i;
printf("\n%lg\t%lg\n", *min, *max);
min = &a[0];
max = &a[0];
for (i = 1 ; i < size ; i++) {
if (a[i] > *max)
max = &a[i];
else if (a[i] < *min)
min = &a[i];
}
printf("\n%lg\t%lg\n", *min, *max);
return 0;
}
If you send a pointer to a double, you are allowing the contents of that double to change. If you want the pointer to change, you must send a pointer to the pointer (double**), which allows the contents of the pointer to change.
int min_max(double ** min , double ** max , int size , double a[]){
int i;
printf("\n%lg\t%lg\n", **min, **max);
*min = &a[0];
*max = &a[0];
for (i = 1 ; i < size ; i++) {
if (a[i] > **max)
*max = &a[i];
else if (a[i] < **min)
*min = &a[i];
}
printf("\n%lg\t%lg\n", **min, **max);
return 0;
}
With all the dereferencing going on here, it may make sense to keep two local pointers or even just the indices, and set the return values once at the end of the loop.
[edit]
Why is it that I can't change a pointer in a function? If I instead
send an array (a pointer like thing) to retain the min and max values,
say, minmax[0]=min, and minmax[1]=max, the values will change, no?
Well, sort of, but you're asking for a pointer to the array element that is min and max, not the actual value. So even if you passed an array to achieve that, it would have to be an array of pointers (double *minmax[2]). Now, that's actually just a double** that points to two double* values (which you index as element 0 and 1 respectively). So it's the same thing.
Now, why can't you change a pointer? You can! But your changes are confined within the scope of your function. You can't change the value back at the caller because the double* pointer is passed by value. You might need to do some reading on pass-by-value and pass-by-reference before I go confusing you, but the general idea is this:
Any data type that you send to a function is effectively copied. So if you are passing a double, that value is copied from the caller into a new memory location (a parameter to the function). The function now has no reference to the original location of that value.
void my_func( double val ) {
val = 42; // Does not affect caller's value because it was copied
}
double value = 1;
my_func( value );
// value is still 1
The same goes when you pass a double*. You are sending the address of a double value to the function but the actual address (the pointer) is a value that is copied into the double* supplied to your function.
void my_func( double* val ) {
*val = 42; // Stuff 42 into the memory location pointed to by 'val'.
}
double value = 1;
my_func( value );
// value is now 42
But your caller appears to want the actual address within the array of the max and min values (unless this was a mistake due to being new to pointers). In that case, a pointer is not enough, because you are copying the contents of your pointers. Here you need to take the address of the memory that holds your pointer and pass that to the function. That address is copied, and when you reference it you are able to write a pointer into that memory location.
void my_func( double** val ) {
*val = *val + 1; // Change the pointer pointed to by 'val'.
}
double values[4] = { 1, 2, 3, 42 };
double *value = &values[2]; // value points to '3'.
my_func( &value );
// value now points to 42
Whenever you're supplying a pointer to a value that you want to be changed by the function, it's referred to as passing by reference.
Your function should be
int min_max(double ** min , double ** max , int size , double a[]);
and the calling statement should be
int *min,*max;
min_max(&min,&max,...);
You can't change where the pointers are pointing and see those changes outside the function. Since you've passed pointers you can change what is being pointed to, but pointers themselves are passed-by-value: you're only changing copies.
To change the pointers themselves you'll need to pass pointers to pointers:
int min_max(double**, double**, int, double);
" Double pointers are also sometimes employed to pass pointers to functions by reference "
can somebody can explain me the above statement, what exactly does point to function by reference means ?
I believe this example makes it clearer :
//Double pointer is taken as argument
void allocate(int** p, int n)
{
//Change the value of *p, this modification is available outside the function
*p = (int*)malloc(sizeof(int) * n);
}
int main()
{
int* p = NULL;
//Pass the address of the pointer
allocate(&p,1);
//The pointer has been modified to point to proper memory location
//Hence this statement will work
*p=10;
//Free the memory allocated
free(p);
return 0;
}
It means that you have a function that takes a pointer pointer (type int ** for example). This allows you to modify the pointer (what data it is pointing to) much in the way passing a pointer by reference would allow.
void change (int *p) {*p = 7;}
void Really_Change (int **pp) {*pp = null;}
int p = 1;
int *pp = &p;
// now, pp is pointing to p. Let's say it has address 0x10;
// this makes a copy of the address of p. The value of &p is still 0x10 (points to p).
// but, it uses that address to change p to 7.
change(&p);
printf("%d\n", p); // prints 7;
// this call gets the address of pp. It can change pp's value
// much like p was changed above.
Really_Change(&pp);
// pp has been set to null, much like p was set to 7.
printf("%d\n", *pp); // error dereference null. Ka-BOOM!!!
So, in the same way that you can pass a pointer to an int and change the value, you can pass a pointer to a pointer and change its value (which changes what it points to.)
I'll try to explain with both code and plain english :). The explanation may get long, but it will be worth the while.
Suppose we have a program, running its main() function, and we make a call to another function that takes an int parameter.
Conceptually, When you pass a variable as a parameter to a function, you can do so in (roughly speaking) two ways: by value, or by reference.
"By value" means giving the function a copy of your variable. The function will receive its "content" (value), but it won't be able to change the actual variable outside its own body of code, because it was only given a copy.
"By reference", on the other hand, means giving the function the actual memory address of our variable. Using that, the function can find out the variable's value, but it can also go to that specified address and modify the variable's content.
In our C program, "by value" means passing a copy of the int (just taking int as argument), and "by reference" means passing a pointer to it.
Let's see a small code example:
void foo(int n) {
n = 10;
printf("%d\n", n);
}
int main() {
int n = 5;
foo(n);
printf("%d\n", n);
return 0;
}
What will the output of this program be? 10 10? Nope. 10 5! Because we passed a copy of the int, by value and not by reference, foo() only modified the number stored in its copy, unable to reach main()'s copy.
Now, if we do it this way:
void foo(int* n) {
*n = 10;
printf("%d\n", *n);
}
int main() {
int n = 5;
foo(&n);
printf("%d\n", n);
return 0;
}
This time we gave foo() our integer by reference: it's actual memory address. foo() has full power to modify it by accessing it's position in memory, foo() and main() are working with the same copy, and so the output will be 10 10.
As you see, a pointer is a referece,... but also a numerical position in memory. It's similar to an int, only the number contained inside is interpreted differently. Think of it this way: when we pass our int by reference, we're passing an int pointer by value!. So the same by value/by reference logic can be applied to pointers, even though they already are references.
If our actual variable was not an int, but an int reference (pointer), and we wanted main() and foo() to share the same copy of that reference so that foo() can modifiy it, what would we do? Why of course, we'd need a reference to our reference! A pointer to a pointer. That is:
int n; /* integer */
int* n; /* integer reference(pointer). Stores an int's position in memory */
int** n; /* reference to integer reference, or double pointer.
Stores int*'s memory address so we can pass int*s by reference. */
I hope this was useful.
?? fun()
{
int a[3]={3,3,4};
return &a;
}
what could be the compatible return type. Here the pointer is pointing to the array of 3 integers not just the pointer which points to integer array.
Aim is to return a pointer to array of 3 integers.
First, you really should not return the address of a local variable. When the function exits, the array a will get destroyed.
As for your question, the type of &a is int (*)[].
Don't do this.
You are returning a pointer to a local variable. When the function returns, that pointer points to a location that's no longer valid, so this exercise is pointless.
The return type would have been int (*)[3] though, but when you use that as a return type of a function, the prototype would be int (*fun(void))[3] (ugh, eew)
However
If a was static, you could do
int (*fun(void))[3]
{
static int a[3]={3,3,4};
return &a;
}
It's more common to return a pointer to the first element in an array - though you'll have to "know" in the caller that you can access 3 and only 3 elements of that pointer.
int *fun(void)
{
static int a[3]={3,3,4};
return &a[0]; // or just return a;
}
Since a is static in these cases, you'll have to worry about reentrancy
2 more common ways of achieving the same:
Pass in the array through the parameters and allocate it in the caller:
void fun(int *a)
{
a[0] = 3;
a[1] = 3;
a[2] = 4;
}
Call it like:
int a[3];
fun(a);
Dynamically allocate the memory:
int *fun(void)
{
int *a = malloc(3*sizeof *a);
if(a) {
a[0] = 3;
a[1] = 3;
a[2] = 4;
}
return a;
}
Call it like:
int *a;
a = fun();
if(a) {
///use a
free(a); // remember to free it when done
} else {
//out of memory
}
The return type would not be an int* or int** as others have suggested. The return type would be a pointer to an array. For example:
// we'll use a typedef so we can keep our sanity:
typedef int(*int3arrayptr)[3];
int3arrayptr fun()
{
int a[3]={3,3,4};
return &a;
}
While you can return a pointer to a local variable, you cannot use such a pointer after the function returns, so you cannot use the return value of fun().
The type would be int**
But your code is wrong because your table is on the stack.
Returning the pointer of an element in the stack make the reference pointing in nowhere when returning from the function.
Don't make the mistake. As soon as fun() loses scope, so does all it's local variables.
The address of a local variable cannot be returned from a function. Local variables are placed in the stack
a is a local variable. Don't return a pointer to it.
Back to the point. This is how you define a pointer-to-array-of-size-3 type in C:
int a[3] = { 1, 2, 3 };
typedef int (*p_arr_3)[3];
p_arr_3 fun() { return &a; }
Everyone else has already told you why you shouldn't do this as it is written, but here are the types you are interested in.
Given a declaration int a[3], the type of the expression &a is int (*)[3] (not int **), or "pointer to 3-element array of int", such as
void f()
{
int a[3] = {1,2,3};
int (*aptr)[3] = &a;
...
}
and the signature for a function returning that type would be int (*fun())[3] {...}.
One other option nos didn't show is this:
int (*fun())[3]
{
int (*aptr)[3] = malloc(sizeof *aptr);
if (aptr)
{
(*aptr)[0] = 1; // array pointer must be deferenced before applying
(*aptr)[1] = 2; // the subscript.
(*aptr)[2] = 3;
}
return aptr;
}
although this isn't terribly useful; you don't normally see allocations of single, fixed-size arrays like this. Somewhat more useful is allocating an array of those arrays:
int (*fun(size_t count))[3]
{
int (*aptr)[3] = malloc(sizeof *aptr * count);
if (aptr)
{
size_t i;
for (i = 0; i < count; i++)
{
aptr[i][0] = 1; // aptr[i] implicitly dereferences aptr, so
aptr[i][1] = 2; // there's no need for an explicit dereference
aptr[i][2] = 3; // here.
}
}
return aptr;
}
Even so, if somebody needs to allocate a fixed-size array type, they usually hide it behind a typedef:
typedef int fixedSizeRecord[SOME_SIZE];
...
fixedSizeRecord *fun(size_t count)
{
fixedSizeRecord *aptr = malloc(sizeof *aptr * count);
if (aptr)
{
// initialize contents as necessary
for (size_t i = 0; i < count; i++)
for (j = 0; j < sizeof *aptr / sizeof *aptr[0]; j++)
aptr[i][j] = ...;
}
return aptr;
}
Abstraction is a good thing.
I've put up several iterations of this table before; you might find it handy.
Declaration: T a[N];
Expression Type Decays To Value
---------- ---- --------- -----
a T [N] T * Address of first element in a
&a T (*)[N] n/a Address of a (same value as above,
but different type)
*a T n/a Same as a[0]
a[i] T n/a Value at index i
&a[i] T * n/a Address of value at index i
sizeof a size_t Total number of bytes in a
(N * sizeof T)
sizeof a /
sizeof *a size_t n/a Number of elements in a (N)
Declaration: T a[N][M];
Expression Type Decays To Value
---------- ---- --------- -----
a T [N][M] T (*)[M] Address of first element in a[0]
&a T (*)[N][M] n/a Address of a (same value as above,
but different type)
*a T [M] T * Same as a[0]
a[i] T [M] T * Address of first element in array
at index i
&a[i] T (*)[M] n/a Address of array at index i (same
value as above, but different
type)
*a[i] T n/a Same as a[i][0]
a[i][j] T n/a Value at a[i][j]
&a[i][j] T * n/a Address of value at index i,j
sizeof a size_t n/a Total number of bytes in a
(N * M * sizeof T)
sizeof a /
sizeof *a size_t n/a Number of subarrays in a (N)
sizeof a[i] size_t n/a Total number of bytes in a[i]
(M * sizeof T)
sizeof a[i] /
sizeof *a[i] size_t n/a Number of elements in a[i] (M)
If you want to return a pointer to an array, don't return the address of local variables. What you are returning here would be int**. What you want to do is allocate a new array of int, and return int*. What you want is probably something like:
int* fun()
{
int* a = malloc(sizeof(int) * 3);
a[0] = 3;
a[1] = 3;
a[2] = 4;
return a;
}
You then need to make sure to free the allocated array later.
Your function would have a return type of int * and you would call it like this:
int *array=fun();
printf("%d\n",array[0]); //print the first value in the array
Although! Keep in mind that this function is returning a reference to a locally created variable. There is no guarantee that the value in memory will be the same between inside and after the function call. You probably want to do something more like this:
int *more_fun(){
int *a=malloc(sizeof(int)*3);
a[0]=3;
a[1]=3;
a[2]=4;
return a;
}
Call it like:
int *array=more_fun();
printf("%d\n",array[0]); //print the first value in the array
But when you're done, make sure to free(array) so you don't leak any memory.
If you were to return a, the return type would be int *. I'm not entirely sure what &a means in this case, and my handy reference tells me that the only operation that can be applied to an array is sizeof, and I don't have the Standard handy. It may be flagged as illegal, or it may just return the value of a. The only thing a denotes is the array, and the only thing like a pointer to an array is a pointer to its first element. There is no address of the address.
In C, it's hard to pass around an array, since arrays decay to pointers on the slightest provocation. If you need to pass around an actual array, it's easiest to embed it in a struct. A struct containing int a[3]; can be passed around as a regular value.
I assume that you were just giving an example, because you're returning a reference to a local variable leads to all sorts of bad things. In most implementations, that memory will be used for other things with the next function call, which means that changing a value will stomp on who-knows-what, and referencing one will get who-knows-what.