Would coding:
char *argv[]
would be the same as:
char **argv
Or would:
char *string1;
int *int_array;
be exactly the same than:
char string1[];
int int_array[];
Absolutely not. One is a pointer, the other one is an array.
However, when it comes to parameters, char *param is equivalent to char param[] or char param[16], for example.
From the C11 draft N1570, §6.7.6.3/7:
A declaration of a parameter as "array of type" shall be adjusted to
"qualified pointer to type" [...]
There are several contexts where [] could be used. It gets a different treatment depending on the context:
Function parameter declaration - here char *argv[] is equivalent to char **argv
Array declarations with initialization - here int x[] = {1, 2, 3} is a way to have the compiler count array elements for you
Declaration at translation unit scope - here int x[] is treated as a tentative declaration, with storage provided at some other place
Last member of a struct - this is a flexible member declaration, which lets you "embed" arrays of variable size into a struct
Compound literals - (const int []) {1, 2, 3} lets you construct arrays "on the fly" without declaring a special variable.
As you can see, * and [] get the same treatment only in the first context; in all other contexts the treatment is different.
No! Well, it depends on the context but explicitly they aren’t the same type.
* is a pointer whereas [] is an array.
A pointer is a variable whose value is the address of another variable, i.e., direct address of the memory location. Like any variable or constant, you must declare a pointer before using it to store any variable address. The general form of a pointer variable declaration is * before the varname
Where an array is a list of objects.
I recommend looking up what pointers are as they are a strong part of C and C++.
Here is a good place to learn about them https://www.tutorialspoint.com/cprogramming/c_pointers.htm (also the place I got the quote from above)
No.
The concept of arrays is related to that of pointers. In fact, arrays work very much like pointers to their first elements, and, actually, an array can always be implicitly converted to the pointer of the proper type.
Pointers and arrays support the same set of operations, with the same meaning for both. The main difference being that pointers can be assigned new addresses, while arrays cannot.
Read more at cplusplus.
Related
This question already has answers here:
C difference between *[] and **
(8 answers)
Closed 2 years ago.
I thought that char *ptrs[]; and char **strs; should be the same thing.
At least I can use both as string arrays.
When I try to compile char **strs, it's fine, but *ptrs[] want to be initialized or at least it want a fixed size for some reason.
char ptrs[];
char **strs;
I get the error:
gcc: "error: array size missing in ‘ptrs’"
I thought that char *ptrs[]; and char **strs; should be he same thing.
You thought wrong. First is an array of unspecified size of pointers. The second is a pointer to a pointer. An array is not a pointer and a pointer is not an array.
You may have been confused by function parameters. Function parameters cannot be arrays and if you write an array parameter, it is adjusted to be a pointer to an element of such array. As such, in a parameter declaration the first is adjusted to be the same as the second. This adjustment only occurs in parameter declarations and nowhere else.
Arrays and pointers are two different derived types.
If you declare an object with automatic storage duration then it shall have a complete type. For arrays it means that the number of elements in the array shall be known (either explicitly specified or calculated according to provided initializes).
So the compiler issue the error
gcc: "error: array size missing in ‘ptrs’"
for this declaration of an array with the automatic storage duration
char *ptrs[];
(I think you mean the type specifier char * instead of char when you are comparing these two declarations char *ptrs[]; and char **strs;) because it is unable to determine how much memory to allocate for the array.
On the other hand, pointers are always complete object types. From the C Standard (6.2.5 Types, p.#20)
A pointer type is a complete object type.
As a result the compiler always knows the size of a pointer.
If this declaration
char *ptrs[];
has file scope then such an incomplete declaration is allowed and is named as a tentative definition. the compiler will interpret it like this declaration
char *ptrs[1];
is present at the end of a translation unit.
Arrays used in expressions are implicitly (with rare exceptions) are converted to pointers to their first elements. So this array designator ptrs used in expressions as for example a function argument is converted to rvalue of the type char **.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
3 Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object and is not an lvalue. If the array object
has register storage class, the behavior is undefined.
I thought that char *ptrs[]; and char **strs; should be the same thing. At least I can use both as string arrays.
Your assumption is not true and neither of those two can be used as "arrays of strings". An array of strings (if this term is anyhow in any manner appropriate) is after my opinion, an array of array of chars, where a string can be stored in each array of chars which is therefore again an element of the array of arrays. A pointer cannot store a string. It can only point to one.
char **strs; - strs is a pointer to pointer to char.
char *ptrs[]; - ptrs is an array of pointer to char with unspecified amount of elements. That is not permissible anywhere else than as function parameter.
As function parameter char *ptrs[] is equal to char **ptrs and denotes a pointer to pointer to char, but again it stores no strings itself.
If you use char *ptrs[] as usual declaration, the compiler needs to know the amounts of pointer elements in the array.
This is why you get the error message
"error: array size missing in ‘ptrs’"
with GCC.
The two declarations are equivalent only as function parameter declarations:
void foo( char *ptrs[], char **strs ) { ... }
because any parameter of type T a[N] or T a[] is "adjusted" to T *a. This is due to the fact that array expressions "decay" to pointer expressions under most circumstances - when you pass an array expression as a function argument, what the function actually receives is a pointer expression.
As regular variable declarations, however, the two are not equivalent. An array definition must either specify a size or have an initializer:
char *ptrs[] = {"foo", "bar", "bletch", "blurga", ... };
In this case, the array size will be taken from the number of elements in the initializer.
The main method argument uses an undefined array argv[]
int main(int argc, char *argv[])
{
.... Do stuff....
}
Why is it undefined arrays are only allowed in the main() method?
In fact this declaration
int main(int argc, char *argv[])
is equivalent to
int main(int argc, char **argv)
It is the host environment that supplies an array of strings and passes the pointer to the first string in the array as an argument for the parameter argv.
From the C Standard (5.1.2.2.1 Program startup)
— If the value of argc is greater than zero, the array members argv[0]
through argv[argc-1] inclusive shall contain pointers to strings,
which are given implementation-defined values by the host environment
prior to program startup. The intent is to supply to the program
information determined prior to program startup from elsewhere in the
hosted environment. If the host environment is not capable of
supplying strings with letters in both uppercase and lowercase, the
implementation shall ensure that the strings are received in lowercase
As for the comment
The argv array has no size, how is this possible?
then a function parameter declared as an array of type T is adjusted to pointer to T.
So for example these function declarations
void f( int a[100] );
void f( int a[10] );
void f( int a[] );
declare the same one function and the all declarations are adjusted to the declaration
void f( int *a );
The same way when an argument of an array type is passed to a function then the array is implicitly converted to pointer to its first element.
So for example the function above can be called like
int a[100];
f( a );
or
int a[10];
f( a );
or
int *a;
f( a );
Nothing is special about main here. An array declaration such as char *argv[] or int example[] has incomplete type, which is valid in certain contexts but not others. However, in the declaration of arguments to a function, the final type cannot be an array type; the array notation acts as a stand-in for a pointer to the first member of an array of that type. The actual type of argv in main is char **.
Why is it undefined arrays are only allowed in the main() method?
By "undefined arrays" you appear to mean arrays with unspecified size. There are several different cases to consider.
Function parameters declared with array syntax in fact do not have array type after all, whether a bound is specified or not. Rather, such a parameter has a pointer type. It is not necessary to specify a bound (for the first dimension), and if one is specified then it is insignificant. This matches up with the automatic conversion from array to pointer ("decay") that would happen in the caller if the corresponding argument were an array, but in the called function the parameter is a pointer, a whole pointer, and nothing but a pointer.
This applies to any function, not just main().
Any variable can be declared at file or block scope as an array without an explicit bound but with an initializer; in this case, the array bound is established implicitly as the minimum necessary to accommodate all elements initialized by the initializer.
Example:
int some_primes[] = { 2, 3, 5, 7, 11 }; // dimension 5
A file-scope (outside any function) variable or one that otherwise has linkage can be declared as an array without explicit bounds and without an intializer to establish the bound implicitly. The type of such a variable is "incomplete" until and unless another, compatible declaration of the same variable completes it by providing the bound, but many array operations can be performed on it at points in the source where it remains incomplete.
Only local variables of array type and without initializers must be declared with an explicit bound. ("Local variables" are those declared at block scope and with no linkage.) These are a fairly common case, though, so I suppose the need to declare a size for them was part of the inspiration for the question.
I'm a little confused about this question. argc is the number of commandline arguments passed into the executable. argv is an array of those arguments. Neither are undefined.
Both argc and argv are simply parameter names, and you can change them to whatever you'd like. They are simply called argc and argv by convention.
Consider this code snippet:
void foo(int a[], int b[]){
static_assert(sizeof(a) == sizeof(int*));
static_assert(sizeof(b) == sizeof(int*));
b = a;
printf("%d", b[1]);
assert(a == b); // This also works!
}
int a[3] = {[1] = 2}, b[1];
foo(a, b);
Output (no compilation error):
2
I can't get the point why b = a is valid. Even though arrays may decay to pointers, shouldn't they decay to const pointers (T * const)?
They can't.
Arrays cannot be assigned to. There are no arrays in the foo function. The syntax int a[] in a function parameter list means to declare that a has type "pointer to int". The behaviour is exactly the same as if the code were void foo(int *a, int *b). (C11 6.7.6.3/7)
It is valid to assign one pointer to another. The result is that both pointers point to the same location.
Even though arrays may decay to pointers, shouldn't they decay to const pointers (T * const)?
The pointer that results from array "decay" is an rvalue. The const qualifier is only meaningful for lvalues (C11 6.7.3/4). (The term "decay" refers to conversion of the argument, not the adjustment of the parameter).
Quoting C11, chapter §6.7.6.3, Function declarators (including prototypes)
A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. [...]
So, a and b are actually pointers, not arrays.
There's no assignment to any array type happennning here, hence there's no problem with the code.
Yes, it would have made sense for array parameters declared with [] to be adjusted to const-qualified pointers. However, const did not exist when this behavior was established.
When the C language was being developed, it made sense to pass an array by passing its address, or, more specifically, the address of the first element. You certainly did not want to copy the entire array to pass it. Passing the address was an easy way to make the array known to the called function. (The semantics for the reference types we see in C++ had not been invented yet.) To make that easy for programmers, so that they could write foo(ArrayA, ArrayB) instead of foo(&Array[0], &ArrayB[0]), the mechanism of converting an array to a pointer to its first element was invented. (Per M.M. and The Development of the C Language by Dennis M. Ritchie, this notation for parameters already existed in C’s predecessor language, B.)
That is fine, you have hidden the conversion. But that is only where the function is called. In the called routine, the programmer who is thinking about passing an array is going to write void foo(int ArrayA[], int ArrayB[]). But since we are actually passing pointers, not arrays, these need to be changed to int *ArrayA and int *ArrayB. So the notion that parameters declared as arrays are automatically adjusted to pointers was created.
As you observe, this leaves the programmer able to assign values to the parameters, which changes the apparent base address of the array. It would have made sense for a parameter declared as int ArrayA[] to be adjusted to int * const ArrayA, so that the value of the parameter ArrayA could not be changed. Then it would act more like an array, whose address also cannot be changed, so this better fits the goal of pretending to pass arrays even though we are passing addresses.
However, at the time, const did not exist, so this was not possible, and nobody thought of inventing const at that time (or at least did work on it enough to get it adopted into the language).
Now there is a large amount of source code in the world that works with the non-const adjustment. Changing the specification of the C language now would cause problems with the existing code.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is array name a pointer in C?
If I define:
int tab[4];
tab is a pointer, because if I display tab:
printf("%d", tab);
the code above will display the address to the first element in memory.
That's why i was wondering why we don't define an array like the following:
int *tab[4];
as tab is a pointer.
Thank you for any help!
tab is a pointer
No, tab is an array. An int[4] to be specific. But when you pass it as an argument to a function (and in many other contexts) the array is converted to a pointer to its first element. You can see the difference between arrays and pointers for example when you call sizeof array vs. sizeof pointer, when you try to assign to an array (that won't compile), and more.
int *tab[4];
declares an array of four pointers to int. I don't see how that is related to the confusion between arrays and pointers.
tab is not a pointer it's an array of 4 integers when passed to a function it decays into a pointer to the first element:
int tab[4];
And this is another array but it holds 4 integer pointers:
int *tab[4];
Finally, for the sake of completeness, this is a pointer to an array of 4 integers, if you dereference this you get an array of 4 integers:
int (*tab)[4];
You are not completely wrong, meaning that your statement is wrong but you are not that far from the truth.
Arrays and pointers under C share the same arithmetic but the main difference is that arrays are containers and pointers are just like any other atomic variable and their purpose is to store a memory address and provide informations about the type of the pointed value.
I suggest to read something about pointer arithmetic
Pointer Arithmetic
http://www.learncpp.com/cpp-tutorial/68-pointers-arrays-and-pointer-arithmetic/
Considering the Steve Jessop comment I would like to add a snippet that can introduce you to the simple and effective world of the pointer arithmetic:
#include <stdio.h>
int main()
{
int arr[10] = {10,11,12,13,14,15,16,17,18,19};
int pos = 3;
printf("Arithmetic part 1 %d\n",arr[pos]);
printf("Arithmetic part 2 %d\n",pos[arr]);
return(0);
}
arrays can behave like pointers, even look like pointers in your case, you can apply the same exact kind of arithmetic by they are not pointers.
int *tab[4];
this deffinition means that the tab array contains pointers of int and not int
From C standard
Coding Guidelines
The implicit conversion of array objects to a
pointer to their first element is a great inconvenience in trying to
formulate stronger type checking for arrays in C. Inexperienced, in
the C language, developers sometimes equate arrays and a pointers much
more closely than permitted by this requirement (which applies to uses
in expressions, not declarations). For instance, in:
file_1.c
extern int *a;
file_2.c
extern int a[10];
the two declarations of a are sometimes incorrectly assumed by
developers to be compatible. It is difficult to see what guideline
recommendation would overcome incorrect developer assumptions (or poor
training). If the guideline recommendation specifying a single point
of declaration is followed, this problem will not 419.1 identifier
declared in one file occur. Unlike the function designator usage,
developers are familiar with the fact that objects having an array
function designator converted to typetype are implicitly converted to
a pointer to their first element. Whether applying a unary & operator
to an operand having an array type provides readers with a helpful
visual cue or causes them to wonder about the intent of the author
(“what is that redundant operator doing there?”) is not known.
Example
static double a[5];
void f(double b[5])
{
double (*p)[5] = &a;
double **q = &b; /* This looks suspicious, */
p = &b; /* and so does this. */
q = &a;
}
If the array object has register storage class, the behavior is undefined
Under most circumstances, an expression of array type will be converted ("decay") to an expression of pointer type, and the value of the expression will be the address of the first element in the array. The exceptions to this rule are when the array expression is an operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize another array in a declaration.
int tab[4];
defines tab as a 4-element array if int. In the statement
printf("%d", tab); // which *should* be printf("%p", (void*) tab);
the expression tab is converted from type "4-element array of int" to "pointer to int".
I was very surprised when I saw this notation. What does it do and what kind of C notion is it?
This is a compound literal as defined in section 6.5.2.5 of the C99 standard.
It's not part of the C++ language, so it's not surprising that C++ compilers don't compile it. (or Java or Ada compilers for that matter)
The value of the compound literal is that of an unnamed object initialized by the
initializer list. If the compound literal occurs outside the body of a function, the object
has static storage duration; otherwise, it has automatic storage duration associated with
the enclosing block.
So no, it won't destroy the stack. The compiler allocates storage for the object.
Parenthesis are put around the type and it is then followed by an initializer list - it's not a cast, as a bare initialiser list has no meaning in C99 syntax; instead, it is a postfix operator applied to a type which yields an object of the given type. You are not creating { 0, 3 } and casting it to an array, you're initialising an int[2] with the values 0 and 3.
As to why it's used, I can't see a good reason for it in your single line, although it might be that a could be reassigned to point at some other array, and so it's a shorter way of doing the first two lines of:
int default_a[] = { 0, 2 };
int *a = default_a;
if (some_test) a = get_another_array();
I've found it useful for passing temporary unions to functions
// fills an array of unions with a value
kin_array_fill ( array, ( kin_variant_t ) { .ref = value } )
This is a c99 construct, called a compound literal.
From the May 2005 committee draft section 6.5.2.5:
A postfix expression that consists of
a parenthesized type name followed by
a brace- enclosed list of initializers
is a compound literal. It provides an
unnamed object whose value is given by
the initializer list.
...
EXAMPLE 1 The file scope definition
int *p = (int []){2, 4};
initializes p
to point to the first element of an
array of two ints, the first having
the value two and the second, four.
The expressions in this compound
literal are required to be constant.
The unnamed object has static storage
duration.
Allocates, on the stack, space for [an array of] two ints.
Populates [the array of] the two ints with the values 0 and 2, respectively.
Declares a local variable of type int* and assigns to that variable the address of [the array of] the two ints.
(int[2]) tells the compiler that the following expression should be casted to int[2]. This is required since {0, 2} can be casted to different types, like long[2]. Cast occurs at compile time - not runtime.
The entire expression creates an array in memory and sets a to point to this array.
{0, 2} is the notation for an array consisting of 0 and 2.
(int[2]) casts it to an array (don't know why).
int * a = assigns it to the int pointer a.