can we declare a function in a header file in following way?
extern int ap( char[][] );
can we use char[][] in function?
No, you need to specify the last N-1 dimensions for an array.
extern int ap( char[][DIMENSION] );
For more information look here
For a two dimensional array, you have to supply a size for the last dimension otherwise the compiler doesn't know how to use it. (it's fine to omit the name though.)
like this:
extern int ap( char[][10] );
char[][] is not a valid array type because you cannot have arrays of an incomplete type, and char[] is incomplete. I know that's confusing because you really have two array types, so here's another example with the same problem: char a[3][]. The array a has length 3 and element type of char[], but char[] is, again, incomplete and this is invalid.
When you have a "multidimentional array", you really have an array of arrays. For example, typedef int U[3][5]; makes U an array of length 3 of arrays of length 5 of ints and is equivalent to typedef int H[5]; typedef H U[3];.
The reason you may omit the leftmost dimension with function parameters is because, with function parameters only, array types of the form T[N] are transformed into T*, and N can be left out, giving T[] to T*. This only applies at the "topmost" or "outermost" level.
So, all these function declarations are identical:
int f1(int a[3][5]);
int f2(int a[][5]);
int f3(int (*a)[5]);
typedef int T[5];
int f4(T a[3]);
int f5(T a[]);
int f6(T* a);
You can, of course, delete the parameter name a in any of the above declarations without changing them.
Yet, it is perfectly valid to omit parameter names in function declarations. When you define the function, however, you must give the array a name, and then you can refer to it by this name.
No, this is not allowed - it attempts to declare the parameter as a pointer to an incomplete array type.
The array type must be completed with a size, like this:
extern int ap( char[][10] );
Related
How can I pass the location of an array of pointers in a function in c i.e.
I have an int* array[10]; and through a function I want to assign the array[0] to be the location of a particular number say, 5. What should the argument of the function look like. I have tried:
void insert(int* array);
but it didn't work.
Arrays are always passed as a pointer pointing to the beginning of the array, even if you don't write it explicitly. So given this declaration of an array from your question:
int *array[10];
Both the following functions will accept a pointer to such an array:
int foo(int *array[]);
int foo(int **array);
They are just equivalent and I would suggest you use the second form, because it makes it explicit what type really is passed to the function.
inside the function, you can access any element, because the indexers are define the same way on a pointer to an array as on the array itself:
int foo(int **array)
{
int *sixthElement = array[5];
// [...]
}
Additional stylistic note: In C, it's common practice to attach the * when declaring a pointer to the identifier, not to the type, ie better write
int *array[10];
instead of
int* array[10];
This is because in a C declaration, there's no such thing as a pointer type, there's a pointer declarator (consisting of the *, optional qualifiers and the identifier) and this declarator declares a variable to be a pointer to the specified type. It's a subtle difference, but if you ever try to declare more than one variable in one line (don't do this, it's just for explanation here), you will notice it:
int *a, b; // <- declares a as a pointer to int, b just as an int
In C, it's possible to typedef an array, using this construction :
typedef int table_t[N];
Here, table_t is now defined as an array of N int. Any variable declared such as table_t t; will now behave as a normal array of int.
The point of such construction is to be used as an argument type in a function, such as :
int doSomething(table_t t);
A relatively equivalent function prototype could have been :
int doSomething(int* t);
The merit of the first construction is that it enforces N as the size of the table. In many circumstances, it's safer to enforce this property, rather than relying on the programmer to properly figure out this condition.
Now it's all good, except that, in order to guarantee that the content of table will not be modified, it's necessary to use the const qualifier.
The following statement is relatively simple to understand :
int doSomething(const int* t);
Now, doSomething guarantee that it will not modify the content of the table passed as a pointer.
Now, what about this almost equivalent construction ? :
int doSomething(const table_t t);
What is const here ? the content of the table, or the pointer to the table ?
If it's the pointer which is const, is there another way (C90 compatible) to retain the ability to define the size of the table and to tell that its content will be const ?
Note that it's also necessary sometimes to modify the content of the table, so the const property cannot be embedded into the typedef definition.
[Edit] Thanks for the excellent answers received so far.
To summarize :
The initial assumption of typedef enforcing size N was completely wrong. It basically behaves the same as a normal pointer.
The const property will also behave the same as if it was a pointer (in stark contrast with a typedef to a pointer type, as underlined by #random below)
To enforce a size (which was not the initial question, but end up being quite important now...), see Jonathan's answer
First, you are mistaken, the function prototypes
int doSomething(table_t t);
int doSomething(int* t);
are exactly equivalent. For function parameters, the first array dimension is always rewritten as a pointer. So there is no guarantee for the size of the array that is received.
const-qualification on arrays always applies to the base type of the array, so the two declarations
const table_t a;
int const a[N];
are equivalent, and for functions parameters we have
int doSomething(const table_t t);
int doSomething(int const* t);
The content of the table will be constant. Easily checked with this code.
#include<stdio.h>
typedef int table_t[3];
void doSomething(const table_t t)
{
t++; //No error, it's a non-const pointer.
t[1]=3; //Error, it's a pointer to const.
}
int main()
{
table_t t={1,2,3};
printf("%d %d %d %ld",t[0],t[1],t[2],sizeof(t));
t[1]=5;
doSomething(t);
return 0;
}
Array types and pointer types are not 100% equivalent, even in this context where you do ultimately get a pointer type for the function parameter. Your mistake is in assuming that const would have acted the same way if it were a pointer type.
To expand on ARBY's example:
typedef int table_t[3];
typedef int *pointer_t;
void doSomething(const table_t t)
{
t++; //No error, it's a non-const pointer.
t[1]=3; //Error, it's a pointer to const.
}
void doSomethingElse(const pointer_t t)
{
t++; //Error, it's a const pointer.
t[1]=3; //No error, it's pointer to plain int
}
It does act similarly to const int *, but const pointer_t is instead equivalent to int * const.
(Also, disclaimer, user-defined names ending with _t are not allowed by POSIX, they're reserved for future expansion)
The merit of the first construction is that it enforces N as the size of the table.
I'm not sure what you mean here. In what contexts would it "enforce" it? If you declare a function as
int doSomething(table_t t);
array size will not be enforced. I order to enforce the size, you'd have to go a different route
int doSomething(table_t *t); // equivalent to 'int (*t)[N]'
What is const here ?
As for const... When const is applied to array type it "drops down" all the way to array elements. This means that const table_t is an array of constant ints, i.e. it is equivalent to const int [N] type. The end result of this is that the array becomes non-modifiable. In function parameter declaration context const table_t will be converted into const int *.
However, note one peculiar detail that is not immediately obvious in this case: the array type itself remains non-const-qualified. It is the individual elements that become const. In fact, it is impossible to const-qualify the array type itself in C. Any attempts to do so will make const-qualification to "sift down" to individual elements.
This peculiarity leads to rather unpleasant consequences in array const-correctness. For example, this code will not compile in C
table_t t;
const table_t *pt = &t;
even though it looks quite innocently from the const-correctness point of view and will compile for any non-array object type. C++ language updated its const-correctness rules to resolve this issue, while C continues to stick to its old ways.
The standard 6.7.6.3 says:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’
Meaning that when you declare a function parameter as a const int array type, it decays into a pointer to const int (first element in array). Equivalent to const int* in this case.
Also note that because of the above mentioned rule, the array size specified adds no additional type safety! This is one big flaw in the C language, but that's how it is.
Still, it is good practice to declare the array with fixed width like you have, because static analysers or clever compilers may produce a diagnostic about different types.
I've attempted to write a program that will take an array of numbers, and produce a new array
containing the squares of the entries of the first array. Here is the function which is supposed to do this;
void square_entires(numbers, squares){
for (int i=0; i<5; ++i) {
squares[i]=numbers[i]*numbers[i];
}
}
Now I get 3 errors on the squares[i]... line saying
"Subscripted value is neither array nor pointer".
Why on earth would I want i to be an array or a pointer!? Shouldn't it simply be an index for the loop to make sense? I've seen other examples of functions which loop over array elements this way and they work fine.. just my function doesn't work properly! Can somebody please explain why this is? thanks it advance.
Your functions declaration is wrong. You must have to specify the types of the arguments in a function. It should be
void square_entires(int numbers[], int squares[])
{
Without specifying type of parameters, it will be considered int by default which is allowed in C89.
n1570: 6.5.2.2 Function calls
Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
Now I get 3 errors on the squares[i]... line saying
"Subscripted value is neither array nor pointer".
Why on earth would I want i to be an array or a pointer!? Shouldn't it simply be an index for the loop to make sense?
Clearly this warning is about the variables squares and numbers which should be declared either an array or pointer. Only then subscripted value is used.
Given A[B], the "subscripted value" is A. B is the subscript.
And, what others said about the missing type specifiers and declarator bits.
When you write:
int foo(a, b)
/* <- nothing here */
{
}
you're writing an old-style function. It's how C was written before some improvements took place in the 1980's which became standardized as ANSI C. The types for a and b are declared between the function declarator and body. If they are not declared, evidently they default to int. There are two ways out. The much preferred one is to use the modern style:
int square_entries(int *numbers, int *squares) // or some other type: double?
{
}
The obsolete style, not recommended, would have looked like:
int square_entries(numbers, squares)
int *numbers;
int *squares;
{
}
[] is the Subscript operator. The expression within the brackets is referred to as a subscript. A postfix expression followed by an expression in [ ] (brackets) specifies an element of an array.
You have not specified the types for numbers, squares in
void square_entires(numbers, squares) // Defaults to type int (where actually you need type int array
This (is valid in C89) main() implicitly meant (previously) int main(void). However the default return type rule has been abandoned in C99.
I think you need this:
void square_entires(int numbers[], int squares[])
or
void square_entires(int * numbers, int * squares)
Cause array decay into pointers in functions, hence you cannot calculate the size of the array in the function - so pass the sizes as well (if required), like this:
void square_entires(int numbers[], int squares[], int sizenumbers, int sizesquares)
By definition, the expression a[b] is equivalent to the expression *((a) + (b)), and, because addition is associative, it is also equivalent to b[a].
When you pass an argument to a function, the argument should represent the type of the parameter you are going to pass. Here, when you see your passed arguments i.e. numbers and squares, it doesn't make it clear that what is the type of the data you are going to pass to your function.
Well, you are going to pass an array which contains the int data type, that is the reason why you need to declare your argument as an int array i.e. int numbers[] (where in the subscript [] represents that your argument is going to be an array and "int" represents that the array contains the data of int type".)
so, your code should be like :
void square_entires(int numbers[], int squares[])
{
This is my function
int mkvCopyWord(uint8_t *pBuffer, UINT8 temp):
main()
{
uint8_t a[10];
mkvCopyWord(&a,10);
}
its says warning : note: expected ‘uint8_t *’ but argument is of type ‘uint8_t (*)[10]’
how to remove this warning..?
Your syntax for passing a pointer-to-array is fine. But you are trying to pass it to something that doesn't want a pointer-to-array. It just wants a pointer to the beginning element. The simplest way to get that is to allow the array name to decay to a pointer, thus mkvCopyWord(a, 10). The function will assume that the pointer you give it is pointing to some sequence of uint8_ts somewhere - that is why you have to pass the array size as another parameter, because it does not know about the array, it only has some address in memory where the array is.
You don't need to take the address of the array as it implicitly converts to a pointer:
int mkvCopyWord(uint8_t *pBuffer, UINT8 temp):
main()
{
uint8_t a[10];
mkvCopyWord(a,10);
}
int main(void) //main() without return type isn't a good practice
{
uint8_t a[10];
mkvCopyWord(&a,10);
return 0;
}
Here you pass a parameter of type "pointer to array of 10 uint8_t". Your function, however, is declared to take pointer to int. In order to make this syntax work, you'd have to change the declaration of your function to take a pointer to an array of 10 uint8_t's
void mkvCopyWord(uint8_t (*parr)[10], int n)
This is all about syntax and type system. As for your actual problem, you need to pass a pointer to the first element of your array.
mkvCopyWord(&a[0],10);
However, an array is implicitly converted to that anyway, so you don't need to bother. You use the following:
mkvCopyWord(a,10);
HTH
Remove the ampersand in mkvCopyWord(&a,10):
int mkvCopyWord(uint8_t *pBuffer, UINT8 temp):
main()
{
uint8_t a[10];
mkvCopyWord(a,10); /* <<< removed the ampersand */
}
There is quite a lot of information on the equivalence of pointers and arrays in the C FAQ.
I think that it is because the former is an array of pointers to char and the latter is a pointer to an array of chars, and we need to properly specify the size of the object being pointed to for our function definition. In the former;
function(char * p_array[])
the size of the object being pointed to is already included (its a pointer to char), but the latter
function(char (*p_array)[])
needs the size of the array p_array points to as part of p_array's definition?
I'm at the stage where I've been thinking about this for too long and have just confused myself, someone please let me know if my reasoning is correct.
Both are valid in C but not C++. You would ordinarily be correct:
char *x[]; // array of pointers to char
char (*y)[]; // pointer to array of char
However, the arrays decay to pointers if they appear as function parameters. So they become:
char **x; // Changes to pointer to array of pointer to char
char (*y)[]; // No decay, since it's NOT an array, it's a pointer to an array
In an array type in C, one of the sizes is permitted to be unspecified. This must be the leftmost one (whoops, I said rightmost at first). So,
int valid_array[][5]; // Ok
int invalid_array[5][]; // Wrong
(You can chain them... but we seldom have reason to do so...)
int (*convoluted_array[][5])[][10];
There is a catch, and the catch is that an array type with [] in it is an incomplete type. You can pass around a pointer to an incomplete type but certain operations will not work, as they need a complete type. For example, this will not work:
void func(int (*x)[])
{
x[2][5] = 900; // Error
}
This is an error because in order to find the address of x[2], the compiler needs to know how big x[0] and x[1] are. But x[0] and x[1] have type int [] -- an incomplete type with no information about how big it is. This becomes clearer if you imagine what the "un-decayed" version of the type would be, which is int x[][] -- obviously invalid C. If you want to pass a two-dimensional array around in C, you have a few options:
Pass a one-dimensional array with a size parameter.
void func(int n, int x[])
{
x[2*n + 5] = 900;
}
Use an array of pointers to rows. This is somewhat clunky if you have genuine 2D data.
void func(int *x[])
{
x[2][5] = 900;
}
Use a fixed size.
void func(int x[][5])
{
x[2][5] = 900;
}
Use a variable length array (C99 only, so it probably doesn't work with Microsoft compilers).
// There's some funny syntax if you want 'x' before 'width'
void func(int n, int x[][n])
{
x[2][5] = 900;
}
This is a frequent problem area even for C veterans. Many languages lack intrinsic "out-of-the-box" support for real, variable size, multidimensional arrays (C++, Java, Python) although a few languages do have it (Common Lisp, Haskell, Fortran). You'll see a lot of code that uses arrays of arrays or that calculates array offsets manually.
NOTE:
The below answer was added when the Q was tagged C++, and it answers from a C++ perspective. With tagged changed to only C, both the mentioned samples are valid in C.
Yes, Your reasoning is correct.
If you try compiling the error given by compiler is:
parameter ‘p_array’ includes pointer to array of unknown bound ‘char []’
In C++ array sizes need to be fixed at compile time. C++ standard forbids Variable Lenght Array's(VLA) as well. Some compilers support that as an extension but that is non standard conforming.
Those two declarations are very different. In a function parameter declaration, a declarator of [] directly applied to the parameter name is completely equivalent to a *, so your first declaration is exactly the same in all respects as this:
function(char **p_array);
However, this does not apply recursively to parameter types. Your second parameter has type char (*)[], which is a pointer to an array of unknown size - it is a pointer to an incomplete type. You can happily declare variables with this type - the following is a valid variable declaration:
char (*p_array)[];
Just like a pointer to any other incomplete type, you cannot perform any pointer arithmetic on this variable (or your function parameter) - that's where you error arises. Note that the [] operator is specified as a[i] being identical to *(a+i), so that operator cannot be applied to your pointer. You can, of course, happily use it as a pointer, so this is valid:
void function(char (*p_array)[])
{
printf("p_array = %p\n", (void *)p_array);
}
This type is also compatible with a pointer to any other fixed-size array of char, so you can also do this:
void function(char (*p_array)[])
{
char (*p_a_10)[10] = p_array;
puts(*p_a_10);
}
...and even this:
void function(char (*p_array)[])
{
puts(*p_array);
}
(though there is precious little point in doing so: you might as well just declare the parameter with type char *).
Note that although *p_array is allowed, p_array[0] is not.
Because,
(1) function(char * p_array[])
is equivalent to char **p_array; i.e. a double pointer which is valid.
(2) function(char (*p_array)[])
You are right, that p_array is pointer to char array. But that needs to be of fixed size in the case when it appears as function argument. You need to provide the size and that will also become valid.