typedef of a multidimensional array? - c

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.

Related

Reusing variable in function parameter list

int doSomething(int n, int arr[n])
What confuses me here is the reusing of the n variable inside the parameter list. Can anyone explain why this is valid and what are the use cases?
It is valid.
For this specific case it is equivalent to:
int doSomething(int n, int arr[]);
int doSomething(int n, int *arr);
because the array parameters are automatically transformed into pointers to arrays' elements. In general there are a few differences between array-like and pointer declarations of parameters. See link for more details.
IMO, the better usage should be:
int doSomething(int n, int arr[static n]);
This static n tell the compilers that at least n elements pointer by arr are valid. Moreover it makes the declaration visually different from a declaration of array what helps to avoid surprising issues when sizeof arr is used.
C allows several syntaxs for passing an array pointer including:
int* arr, int arr[] or int arr[10]
However ALL of these are equivalent to the first - that is the compiler sees only an int pointer and does not use any size that may have been specified in the array square brackets to enforce integrity on the size of the array passed. In all the above cases the compiler will generate:
void __cdecl foo(int * const)
The only way to specify the size of an array is, as you have done, pass a separate parameter indicating the size/length of the array.
In the example you cite the n in arr[n] is not used by the compiler to maintain any integrity on the array bounds - in the example it is only included as an indication that the first parameter is the size.
A less controversial form of the same code might be just to state that more explicitly:
int doSomething(int arr_len, int arr[])
In terms of what is the best convention or preference for passing an pointer and its array size see this question.

Passing array to a function

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.

Is array copied if given as an argument to a function in C

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.

C pointer notation compared to array notation: When passing to function

My question is base on the following code:
int myfunct(int ary[], int arysize)
int myfunct2(int *ary, int arysize)
int main(void){
int numary[10];
myfunct(numary, 10)
myfunct2(numary, 10)
return;
}
int myfunct(int ary[], int arysize) {
//Whatever work is done
}
int myfunct2(int *ary, int arysize) {
// Whatever work is done
}
Is there a reason to use one of these over the other? To elaborate, when concerned with numeric arrays, is there any reason one would want to use pointer notation over array notation. If one uses pointer notation then within the function pointer arithmetic would be used etc.. AND if one uses the [] array notation, one could work with the array as usual. I'm new to programming and I currently do not see any benefit to using the pointer notation.
My precise question, is there any reason to pass a numeric array to a function using pointer notation and therefore using pointer manipulations within the function.
When you declare a function parameter as an array, the compiler automatically ignores the array size (if any) and converts it to a pointer. That is, this declaration:
int foo(char p[123]);
is 100% equivalent to:
int foo(char *p);
In fact, this isn't about notation but about the actual type:
typedef char array_t[42];
int foo(array_t p); // still the same function
This has nothing to do with how you access p within the function. Furthermore, the [] operator is not "array notation". [] is a pointer operator:
a[b]
is 100% equivalent to:
*(a + b)
There is no real functional difference between the two notations. In C, when you pass an array variable to a function, it decays to a pointer regardless of the notation. However, in my opinion, the pointer notation is preferable. The problem with [] notation in function definitions is that, in my opinion, it is somewhat misleading:
void foo(int array[])
{
}
A ubiquitous mistake among novice C programmers is to assume that sizeof(array) will give you the number of elements in the array multiplied by sizeof(int), like it would if array were an array variable declared on the stack. But the reality is that array has been decayed to a pointer, despite the misleading [] notation, and so sizeof(array) is going to be sizeof(int*). array is really just a pointer to the first element, or possibly a pointer to a single integer allocated anywhere.
For example, we could call foo like this:
int x = 10;
foo(&x);
In which case the [] notation in the definition of foo is kind of misleading.
Those declarations are absolutely identical. To quote the standard:
A declaration of a parameter as "array of type" shall be adjusted to
"qualified pointer to type"
C99 standard section 6.7.5.3 paragraph 7
In modern C that has variable length arrays since C99, the array notation is preferable if is an array, I think. For one dimensional arrays, you can do things like
int myfunct(size_t size, int array[size]) {
... array[i] ..
}
and for two dimensional
int myfunct(size_t size, int array[size][size]) {
... array[i][j] ..
}
So array notation fits much better in the general picture. A sophisticated compiler could then even do bounds checking, but I don't know of any that does this yet.
In my opinion, the main reason to prefer pointer notation over empty array notation in function prototypes is that the latter is not consistent with structure definitions:
struct person {
char *firstname;
char *lastname;
};
void setperson(struct person *p, char firstname[], char lastname[])
{
p->firstname = firstname;
p->lastname = lastname;
}
In structures you will have to use the pointer notation anyway because empty array notation is only valid, at least since C99, for the last member when you want to make it a flexible array member.
You only need to use the array notation for multidimensional arrays. (You do not have to provide the size of the first dimension).

Pointer to array as function parameter

I wrote a function which takes a pointer to an array to initialize its values:
#define FIXED_SIZE 256
int Foo(int *pArray[FIXED_SIZE])
{
/*...*/
}
//Call:
int array[FIXED_SIZE];
Foo(&array);
And it doesn't compile:
error C2664: 'Foo' : cannot convert parameter 1 from 'int (*__w64 )[256]' to 'int *[]'
However, I hacked this together:
typedef int FixedArray[FIXED_SIZE];
int Foo(FixedArray *pArray)
{
/*...*/
}
//Call:
FixedArray array;
Foo(&array);
And it works. What am I missing in the first definition? I thought the two would be equivalent...
int Foo(int *pArray[FIXED_SIZE])
{
/*...*/
}
In the first case, pArray is an array of pointers, not a pointer to an array.
You need parentheses to use a pointer to an array:
int Foo(int (*pArray)[FIXED_SIZE])
You get this for free with the typedef (since it's already a type, the * has a different meaning). Put differently, the typedef sort of comes with its own parentheses.
Note: experience shows that in 99% of the cases where someone uses a pointer to an array, they could and should actually just use a pointer to the first element.
One simple thing is to remember the clockwise-spiral rule which can be found at
http://c-faq.com/decl/spiral.anderson.html
That would evaluate the first one to be an array of pointers . The second is pointer to array of fixed size.
An array decays to a pointer. So, it works in the second case. While in the first case, the function parameter is an array of pointers but not a pointer to integer pointing to the first element in the sequence.

Resources