When we pass an array as an argument we accept it as a pointer, that is:
func(array);//In main I invoke the function array of type int and size 5
void func(int *arr)
or
void fun(int arr[])//As we know arr[] gets converted int *arr
Here the base address gets stored in arr.
But when the passed array is accepted in this manner:
void func(int arr[5])//Works fine.
Does the memory get allocated for arr[5]?
If yes, then what happens to it?
If no, why isn't the memory allocated?
Does the memory gets allocated for arr[5]?
No, it doesn't.
If no,why memory is not allocated?
Because it's not necessary. The array, when passed to a function, always decays into a pointer. So, while arrays are not pointers and pointers are not arrays, in function arguments, the following pieces of code are equivalent:
T1 function(T2 *arg);
T1 function(T2 arg[]);
T1 function(T2 arg[N]);
void func(int *arr)
void func(int arr[])
void func(int arr[5])
are all equivalent in C.
C says a parameter of an array of type is adjusted to a pointer of type.
When you place an array size in a parameter declaration the number is totally ignored. In other words
void foo(int x[5]);
is exactly the same as
void foo(int *x);
Hope the following code/comments helps. When coding C the programmer must ensure that many items agree in various programs. This is both the fun and the bane of programming in C.
Note. Defining int arr[5] in a parameter list does NOT allocate storage for the data that is being passed. The declaration is valid and endorsed but only because it lets the compiler perform its type checking. Although, the compiler does allocate storage when a function is called that storage does not store YOUR data. You must allocate your data either through an explicit declaration (as in main in the following example) or you need to issue an malloc statement.
I ran the following code in Eclipse/Microsoft C compiler and NO statements were flagged with a warning or an error.
//In main invoke the functions all referring the same array of type int and size 5
void func1(int *arr)
{ // arr is a pointer to an int. The int can be the first element
// of an array or not. The compiler has no way to tell what the truth is.
}
void func2(int arr[])
{ // arr is a pointer to an array of integers, the compiler can check this
// by looking at the caller's code. It was no way to check if the number
// of entries in the array is correct.
}
void func3(int arr[5])
{ // arr is a pointer to an array of 5 integers. The compiler can
// check that it's length is 5, but if you choose to overrun the
// array then the compiler won't stop you. This is why func1 and func2
// will work with arr as a pointer to an array of ints.
}
void main()
{
int data_array[5] = {2,3,5,7,11};
func1(data_array);
func2(data_array);
func3(data_array);
}
Hope this helps, please ask for more info.
Related
Question from a past exam paper:
"Which of the following:
int a[4][4], (*b)[4], *c[4], **d;
Could you pass into a function expecting a pointer to a pointer to an int
ie
int funct(int **);
Explain your answer."
The answer is c and d i believe?
I am just struggling to understand why the rest arn't allowed?
Any help would be appreciated.
funct expects an int ** - that is, a pointer-to-a-pointer-to-an-int. d is literally that, so no problem. c works too, since it's an array of pointers-to-int, which will therefore decay into a pointer-to-a-pointer-to-an-int when used in a function call context.
a and b won't work, since they're not compatible types. a is an array-of-arrays-of-int, and b is a a pointer-to-array-of-int. a will decay into a pointer-to-array-of-int when passed as a parameter.
in general if you pass an array to a function it is passed as pointer to first element of the array...
int a[4][4] to a function i.e. fun(a); it is passed as int (*p)[4] so fun parameter must be fun(int (*p)[])
here first element itself is an array of 4 integers
fun(a) ---> fun(int (*p)[])
int (*b)[4] is a pointer to array of 4 integers so calling fun(b) requires parameter must be fun(int (*pt)[])
fun(b) ---> fun(int (*pt)[])
int *c[4] is an array of 4 integer pointers ..so calling fun(c) requires parameter must
be pointer to first element of array. here first element is itself an int pointer..so fun(int **p)
fun(c) ---> fun(int **p)
int **d is double pointer to an int..so calling fun(d) requires parameter must be
fun(int **p)
fun(d) ---> fun(int **p)
If I can add some information on the difference between the above answers.
This - [] has higher precedence than this * when declaring an array. That combined with the assumption that arrays and pointers are always interchangeable (they are not) catches a lot of people out.
Naively one would assume that int *arr[] would be a pointer to an array because read from left to right this is a natural assumption.
However it is actually an array of integer pointers. You want a pointer to an array? Tell C so:
int (*arr)[array_size];
by setting your own precedence.
As Carl has explained only answers c and d are applicable because in the d case you already have a pointer to a pointer and in the c case the array of pointers will decay to a pointer to a pointer when passed as an argument to a function.
If you want a function that will read a and b, the signature needs to change to the following:
int funct(int (*array_name)[array_size]);
Note that in the above here you will need to specify the size of the array that the pointer will point to.
Some good answers on two dimensional arrays and pointers to pointers here and here.
I'm curious if I give an n-dimensional array for n>1 as an argument to a function, are the contents of whole array copied or just the pointer to the address of the first element.
Assume function signature is something like this:
int someFunction(int n, int arr[n][n]);
[Where I just re-learned this yesterday]
This is a C99 extension that is not widely known. The array is still passed by reference as they always have been, but the compiler is able to interpret it as an array similar to the way it handles Variable-Length Arrays.
This won't give you bound-checking, of course. C doesn't have that.
In your function signature,
int someFunction(int n, int arr[n][n]);
The final n doesn't really buy you anything, it just gets ignored. But int arr[n][] is new. That's what C89 didn't have. Previously, the only option was to calculate indices manually off of the base pointer, arr[n*x+y].
In Ansi-C (C89), you'd have to declare the function as,
int someFunction(int n, int arr[]);
which is equivalent to
int someFunction(int n, int *arr);
and calculate the two dimensions as a single index.
The new C99 magic, reduces the original to this:
int someFunction(int n, int *arr[n]);
I'd describe the process more as array adoption, than passing. It just mitigates some of the losses that were incurred by the original decision to pass arrays as pointers.
It's important to understand that second two examples are sort-of internalized equivalents. Figurative illustrations. In the final one, the array is not converted into an array of pointers, but the bounds of the lowest dimension is dropped. Perhaps it's better illustrated like this:
int someFunction(int n, int arr[n][]);
The only way to copy an array as a function argument is to wrap it in a struct. But then you cannot have variable dimensions.
struct arr {int n; int arr[n][n];}; //Nope, won't compile!
enum { n = 3 };
struct arr { int arr[n][n]; };
struct arr someFunction( struct arr ); //argument and return value are copied.
And this has been legal since 1989.
That's an illegal signature for a function, as arrays in function signatures must have constant dimensions (other than the final dimension).
The reason that arrays must have constant sizes as function parameters is because they aren't actually copied in the function call -- only a pointer is passed.
Is there a difference between &array[0] and &array when passed to a C Function. This array is a void* array which currently takes integer as data.
Added the test code
#include <iostream>
#include <conio.h>
using namespace std;
int read_buffer[10] = {0,0,0,0,0,0,0,0,0,0};
int write_buffer[10] = {0,1,2,3,4,5,6,7,8,9};
void WriteBlock(void* SrcPtr)
{
//WriteBlock will use SrcPtr and store the data to a common memory block which ReadBlock will access.
}
void ReadBlock(void* DstPtr)
{
//ReadBlock function will fetch data from readBuffer and put the data back into the *DstPtr.
}
void main()
{
WriteBlock((int*)&write_buffer);
//Is there a difference between these two below calls.
ReadBlock(&read_buffer[0]);
ReadBlock(&read_buffer);
}
Yes, there's a big difference, and it depends on context.
Consider this:-
char arrayA[10];
char *arrayB;
&arrayA[0] and &arrayB[0] both have type char *.
But &arrayA has type char (*)[10] while &arrayB has type char ** - the address of the pointer.
For arrayA, these point to the same address - but for arrayB, they do not! There's a common C misconception that "pointers and arrays are the same". This is a great example of where they are absoluelty not,
See this : http://ideone.com/OcbuXZ
Assuming array is declared
void *array[N];
then the expressions &array[0] and &array will yield the same value (the address of the first element of the array is the same as the address of the array itself), but will have different types.
Expression Type
---------- ----
&array void *(*)[10] -- pointer to 10-element array of `void *`
&array[0] void ** -- pointer to pointer to void
Your function prototype will need to match up with whichever expression you pass. If you call the function as
func(&array);
then the function prototype needs to be
void func(void *(*arrp)[10]) {...}
If you call the function as
func(&array[0]);
then the function prototype needs to be
void func(void **arrp) {...}
although in that case you should pass the size of the array as a separate parameter.
Now, assuming array is declared
void **array = malloc(sizeof *array * N);
then the expressions &array and &array[0] will yield different values and different types.
Expression Type
---------- ----
&array void ***
&array[0] void **
&array will give you the address of the array variable itself, which is different from the address of the heap memory that's been allocated for the array. Again, your function prototype will need to match up with the type of the expression you use.
If array is really an array, then
&array[0] is the pointer to element 0 of array[]
&array is the pointer to the entire array[]
So, these two expressions are of different types. And that's the main difference that may cause your code to fail to compile if you pass the wrong one of the two.
At the low level, however, the two pointers are going to hold the same address.
Yes there is a big different
&array[0]==>void**
AND
&array==>void***
This won't compile, you are using a void * and try to get the first element of it. But what size does it have? The compiler doesn't know. Using int * may compile, if you are not trying something like this:
int main (void) {
int *arr = malloc( 10 );
arr = &arr[0]; // this is ok
arr = &arr; // wrong data type
}
&array returns an int **, &array[0] returns int *. These are different data types.
typedef int array [x][];
What does that means. What will happen if we have such a typedef. It was my interview question.
Let's assume you have somewhere:
#define x 3
As others point out, typedef int array [3][]; will not compile. You can only omit the most significant (ie first) element of an array length.
But you can say:
typedef int array [][3];
This means that array is an int array (of as-yet unspecified length) of length 3 arrays.
To use it, you need to specify the length. You can do this by using an initialiser like so:
array A = {{1,2,3,},{4,5,6}}; // A now has the dimensions [2][3]
But you CAN'T say:
array A;
In this case, A's first dimension isn't specified, so the compiler doesn't know how much space to allocate for it.
Note that it's also fine to use this array type in a function definition - as arrays in function definitions are always converted to pointers to their first element by the compiler:
// these are all the same
void foo(array A);
void foo(int A[][3]);
void foo(int (*A)[3]); // this is the one the compiler will see
Note that in this case:
void foo(int A[10][3]);
The compiler still sees
void foo(int (*A)[3]);
So, the 10 part of A[10][3] is ignored.
In summary:
typedef int array [3][]; // incomplete type, won't compile
typedef int array [][3]; // int array (of as-yet unspecified length)
// of length 3 arrays
You'll get a compilation error. For multidimensional arrays, at most the first dimension may be omitted. So for example, int array[][x] would be valid instead.
You'll get a diagnostic.
int [x][] is an incomplete array type that cannot be completed.
File 1.c
int a[10];
File main.c:
extern int *a;
int main()
{
printf("%d\n", a[0]);
return 0;
}
Gives me a segfault! What's going wrong?
Arrays decompose, or are implicitly converted to pointers when passed to a function as an argument, or when converted to an r-value on the right-hand-side of the assignment operator. So something like:
int array[10];
int* a = array; //implicit conversion to pointer to type int
void function(int* a);
function(array); //implicit conversion to pointer to type int
works just fine. But that does not mean that arrays themselves are pointers. So if you treat an array like a pointer as you've done, you're actually treating the array type as-if it was a pointer that held the address to an int object. Since your array is actually a sequence of int objects, and not pointers to int objects, you're actually trying to dereference to some memory location that isn't pointing to anywhere valid (i.e., the first slot in array is a numerical integer value like 0 which would be like dereferencing a NULL). So that is why you're segfaulting. Note that if you had done something like this:
int array[] = { 1, 2, 3, 4, 5};
int b = *array;
That still works, since array is again implicitly converted to a pointer to the memory block that is holding a sequence of integer values and is then dereferenced to get the value in the first sequence. But in your case, by declaring your array to the current code module as an externally defined pointer, and not an array, it will skip over the implicit conversion to a pointer that is normally done, and just use the array object as-if it were a pointer to an object itself, not an array of objects.
Well explained in the C FAQ. And there is a followup. The picture in the second link is worth a million bucks.
char a[] = "hello";
char *p = "world";
Short answer: use extern int a[].
A bit late, a duplicate of this problem was just entered (and closed). The answers here don't mention header files...
The problem would be caught at compile time if you put the declaration of array a in a header file, where it belongs, instead of putting it in the .c file. The header file should then be included into both .c files and the compiler can see that what you have declared is wrong.
Your header file would contain:
extern int myarray[];
You will get something like "error: conflicting types for a" if you declare a as a pointer instead.
Basically you'd need to write your main.c like this:
extern int a[];
int main()
{
printf("%d\n", a[0]);
return 0;
}
Check out the output of the following code.
File1.c
#include <stdio.h>
extern int* my_arr;
void my_print()
{
printf("%d", my_arr);
}
main.c
#include <stdio.h>
int my_arr[2] = {1,2};
extern void my_print();
void main()
{
my_print();
}
output
1
inside File1.c my_arr is a pointer variable that has the value of 1. meaning the 1st element of my_arr[] was assigned to it. Then if you use *my_arr to access memory location ox1, you get seg fault because you are not allowed to access ox01.
Why my_arr pointer was assigned 1 (the first element of my_arr[])?
Has to do with how assembler works. Read this article
Why your code can't access 0x01 ?
I know it has to do with the operating system not allowing some address space to be accessed by user code. Thats all I know. google it if you want more info.