I just don't know how to explain my question precisely. So I wrote that title above.
Here is my confusion about a very simple program. Exactly, the results.
#include <iostream>
using namespace std;
char * tmp[]={"aaa", "bbb", "ccc"};//there are 3 members
int main(int argc, char* argv[], char* env[])
{
cout << sizeof(env)/sizeof(char*) << endl;
cout << sizeof(tmp)/sizeof(char*) << endl;
}
Results:1 3
What I want is the length of env[]. How can this possible that I got number 1 of env[], while the length of 'tmp'(3) is absolutely rigth.
There's no way that the length of env is 1, cause I tested it and the number is 47.
Why this happened?
Thanks!
The difference is that tmp is an array, whereas env is a pointer. Arrays and pointers are different. It's a bit confusing because array syntax in a function formal parameter list is actually a pointer in disguise.
There is no way to get the number of elements pointed to by env using sizeof. You have to go through them until you find the NULL element terminating the list.
The important thing to remember is that argv and env are pointers, not arrays. In the context of a function parameter declaration, T a[] and T a[N] are interpreted as T *a, so the types of both argv and env are char **, not char *[N].
The only way to determine how many elements each points to is by iterating through them until you find a NULL pointer:
size_t i;
for ( i = 0; argv[i] != NULL; i++ )
; // empty loop body
printf( "There are %zu elements in argv\n", i );
for ( i = 0; env[i] != NULL; i++ )
; // empty loop body
printf( "There are %zu elements in env\n", i );
The language C has certain syntactical features that are convenient for the experienced programmer, but confusing for the new learner. While the syntax T * X[] looks the same in your two cases, they actually mean two very different things:
int a[] = { 1, 2, 3}; is the same as int a[3] = { 1, 2, 3 };. Here a is an array, and the size of the array is deduced from the initializer.
void f(int b[]) is the same as void f(int * b). Here b is a pointer, and the notation is merely suggestive of the fact that you should call f with a pointer to an element of an array. For instance, you could call f(a), or equivalently f(&a[0]), or even f(a + 2). But the declarator syntax is purely a cosmetic convenience, and b is not an array, but a pointer.
This has little to do with these being parameters to main, sizeof anything is a compile time expression. Obviously, the environment and arguments passed to your program aren't. sizeof(array)/sizeof(element_type) is only the length of the array if that array was declared with a static size. Otherwise, sizeof(array) will be equivalent to sizeof(element*) (and because sizeof(char**) == sizeof(char*) you get 1 in your program).
Related
Sorry if this seems like a basic question. I've been studying for a midterm I have coming up and I can't seem to wrap my head around this. I understand that argv can be used in the command line when you need to send it arguments, but none of the answers my professor gave us seems to make sense.
The parameter argv in the function main(int argc, char *argv[]) is:
A. An array of characters
B. A string
C. An array of pointers to character
D. A character pointer
E. None of the above
I feel like it is none of the above, but it could be because I don't fully understand the concept of argv. Any help would be appreciated!
The correct answer is E, none of the above. Although the parameter declaration looks like an array of pointer to char, the rules of C adjust it to pointer to pointer to char, and so do the rules of C++.
Either your instructor mistakenly intended choice C or your instructor designed a question inappropriately tricky for an introductory class, unless it is extra credit.
I think your professor wants C, even though the pedanticly correct answer is E. The data referred to by argv is an array, but the variable itself is a pointer. I think it's worth exploring why, because it has nothing to do with the type of array or main.
Consider an array of integers,
int a[] = { 1, 2, 3 };
This allocates 3 adjacent integers. The size of the array is sizeof(int) * 3.
Now let's write a function to double the values of each member,
void F( int m[], size_t n ) {
for( int i=0; i < n; i++ ) {
m[i] *= 2;
}
int main( int argc, char *argv[] ) {
F(a, sizeof(a)/sizeof(a[0]));
return EXIT_SUCCESS;
}
What is m? It's declared to be an array, but it's really a pointer: sizeof(m) == sizeof(int*). That's because C doesn't pass arrays as function arguments. The term of art in C is that an array argument decays to a pointer.
It sorta kinda doesn't matter, because C syntax hides a host of sins, er, differences. You can use the subscript notation with both arrays and pointers. For that reason, our function F can treat m almost like an array, except that it requires the length, because it can't derive the length from the size, because the size is the size of the pointer.
Let me say that a different way. When F is called, the "arguments on the stack" are not the values of a, namely 1, 2, and 3. There is just one such argument, a pointer to the first element of a (often thought of as the address of the first element). You can use that pointer as an array partly because the name of an array also refers to the address of the first element.
Now let's back up to your friend argv. Array, or pointer? Let's say your program foo is invoked on the command line:
$ foo sam I am
What does the operating system do? Somehow, it has to pass those 4 strings (character arrays) to your program. Somewhere, it has to allocate contiguous space for them. Conceptually, the shell might do something like:
char **args = calloc(5, sizeof(char*));
args[0] = "foo";
args[1] = "sam";
args[2] = "I";
args[3] = "am";
or,
char args[5] = { "foo", "sam", "I", "am" };
Either way, it could pass args to execv(3), invoking your main, and passing you a ... pointer. After all, it can't pass you an array, right?
Please note args must be an array. If it weren't argv[1] would be meaningless.
(Why 5 elements, you ask, when there are only 4 arguments? There's a rule -- C or Posix, i don't remember -- that the last element in the array (!) must be a NULL pointer.)
Array or pointer? Wave or particle? Where you stand depends on where you sit. argv is pointer a to char*, certainly. By definition, though, it's a pointer to the start of an array of char*.
Here are two lines of code:
int (*parry)[10] = &arr // Line # 1
int *(&arrRef)[10] = ptrs // Line # 2
Line # 1:
parry is a pointer that points to an int array of size 10.
So does it mean:
parray[1] points to the address of arr,
parray[2] points to address of arr
...
parray[10] points to address or arr?
When would I use Line # 1?
Solution:
#include <iostream>
int main(
{
int arr[10] = { 3, 54 };
int (*parry)[10] = &arr;
std::cout << (*parry)[0] << " " << (*parry)[1] << " " << (*parry)[3] << " " << parry[4] << std::endl;
return 0;
}
Output:
3, 54, 0, hex address of arr at index 4.
It seems like what inside parry[0] is a pointer that points to arr associated with the index. So, parry[0] ---> arr[0].
Line # 2:
arrRef is a reference to an int array of size ten pointers. arrRef is referred to by ptrs.
So does it mean:
arry[1] is an int pointer? ...
arry[10] is an int pointer?
What example can this been used in?
When in doubt, see the Clockwise/Spiral Rule.
int (*parry)[10] = &arr;
parry is a pointer to an array of 10 ints.
int *(&arrRef)[10] = ptrs;
arrRef is a reference to an array of 10 pointers to int.
Example:
int main()
{
int arr[10];
int* ptrs[10];
int (*parry)[10] = &arr;
int *(&arrRef)[10] = ptrs;
}
Now I've cleaned up your question, I can see it wasn't what I originally thought. You say:
parray is a pointer that points to an int array of size 10
so clearly you figured out the clockwise/spiral/cdecl stuff already.
So does it mean: ... parray[10] points to address of arr
Firstly, arrays in C++ are indexed starting from zero, so you can access arr[0] .. arr[9] if there are 10 elements; arr[10] would be the eleventh, so is out of bounds.
Now, let's take your sentence apart:
parray is a pointer
right, it isn't an array, it's a pointer. Now, let's consider what it is a pointer to:
an int array of size 10
ok, if it points to that, then *parray must be (a reference to) the original array.
So, (*parray)[0] is the first element of the array, etc.
Note that you can easily test your intuition about all this by just printing things out, and seeing what you get. You'll either see pointers, and be able to compare the addresses, or you'll see integer values, or you'll get (hopefully informative) compile errors. Try it out!
Oh, and:
When would I use line 1?
Only if you need to re-seat it, in general. For example, if you want to choose one of two different arrays based on some logic, and then ... perform further logic on whichever was selected.
Next, you said
arrRef is a reference to an int array of size ten pointers.
Correct!
arrRef is refer to by ptrs
No, arrRef refers to an array, the array has size 10, and its 10 elements are pointers-to-int. Note this is not the same type as the first array!
Since references can be used with the same syntax as the thing they refer to, we can use arrRef as an array.
So, arrRef[0] is the first element of the array, and it is a pointer-to-int.
What example can this been used in?
The only common reason for using reference-to-array is to avoid pointer decay, allowing templates to deduce the number of elements.
I think that in this statement
//line1// int (*parry)[10] = $arr
^^^ ^^
there is a typo
There must be
//line1// int (*parry)[10] = &arr;
^^^ ^^
It is assumed that arr is an array of type int[10]. For example
int arr[10];
And this declaration
int (*parry)[10] = &arr;
declares a pointer to this entire array.
As for this declaration
//line2// int *(&arrRef)[10] = ptrs;
^^^
then it is assumed that ptrs is an array of type int *[10] That is elements of the array have type int *. They are pointers.
And this declaration
int * (&arrRef)[10] = ptrs;
declares a reference to this array. A reference is in fact is an alias of an array.
In C++ 2014 you could define a reference to an array simpler.
For example
decltype( auto )arrRef = ( ptrs );
Here is a demonstrative program
#include <iostream>
int main()
{
int a[10];
decltype( auto )ra = ( a );
std::cout << sizeof( a ) << std::endl;
std::cout << sizeof( ra ) << std::endl;
ra[0] = 10;
std::cout << a[0] << std::endl;
std::cout << ra[0] << std::endl;
}
The program output is
40
40
10
10
For parsing C declarations it is valuable to remember, in the words of Kernighan and Ritchie, that "the syntax is an attempt to make the declaration and the use agree" (K&R, TCPL, 5.12). In other words, you can treat a declaration as an expression and simply apply the operators in the proper order. That will show you what type the declared identifier must have.
For example, in int (*parry)[10] you first apply the * operator, because it is in parentheses. This indicates that parray is a pointer. Then you apply the [] operator, indicating that the result of the dereferencing was an array; the 10 indicates the number of elements. The obtained element is of type int. Summing up: parray was a pointer to an array of int.
Declarations of references in C++ can not be solved that way because there is actually no operator which would create a reference, or dereference one; both operations are implicit in C++. The & symbol is used to signify references in declarations only (perhaps somewhat confusingly, because in expressions it's used to take an address). But if you think of the & in declarations as a * substitute to signify a reference instead of a pointer you should still be able to parse any declaration.
What is the difference between the following declarations:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
What is the general rule for understanding more complex declarations?
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
The third one is same as the first.
The general rule is operator precedence. It can get even much more complex as function pointers come into the picture.
Use the cdecl program, as suggested by K&R.
$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>
It works the other way too.
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
I don't know if it has an official name, but I call it the Right-Left Thingy(TM).
Start at the variable, then go right, and left, and right...and so on.
int* arr1[8];
arr1 is an array of 8 pointers to integers.
int (*arr2)[8];
arr2 is a pointer (the parenthesis block the right-left) to an array of 8 integers.
int *(arr3[8]);
arr3 is an array of 8 pointers to integers.
This should help you out with complex declarations.
int *a[4]; // Array of 4 pointers to int
int (*a)[4]; //a is a pointer to an integer array of size 4
int (*a[8])[5]; //a is an array of pointers to integer array of size 5
The answer for the last two can also be deducted from the golden rule in C:
Declaration follows use.
int (*arr2)[8];
What happens if you dereference arr2? You get an array of 8 integers.
int *(arr3[8]);
What happens if you take an element from arr3? You get a pointer to an integer.
This also helps when dealing with pointers to functions. To take sigjuice's example:
float *(*x)(void )
What happens when you dereference x? You get a function that you can call with no arguments. What happens when you call it? It will return a pointer to a float.
Operator precedence is always tricky, though. However, using parentheses can actually also be confusing because declaration follows use. At least, to me, intuitively arr2 looks like an array of 8 pointers to ints, but it is actually the other way around. Just takes some getting used to. Reason enough to always add a comment to these declarations, if you ask me :)
edit: example
By the way, I just stumbled across the following situation: a function that has a static matrix and that uses pointer arithmetic to see if the row pointer is out of bounds. Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))
int *
put_off(const int newrow[2])
{
static int mymatrix[3][2];
static int (*rowp)[2] = mymatrix;
int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);
memcpy(rowp, newrow, sizeof(*rowp));
rowp += 1;
if (rowp == border) {
rowp = mymatrix;
}
return *rowp;
}
int
main(int argc, char *argv[])
{
int i = 0;
int row[2] = {0, 1};
int *rout;
for (i = 0; i < 6; i++) {
row[0] = i;
row[1] += i;
rout = put_off(row);
printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
}
return 0;
}
Output:
0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]
Note that the value of border never changes, so the compiler can optimize that away. This is different from what you might initially want to use: const int (*border)[3]: that declares border as a pointer to an array of 3 integers that will not change value as long as the variable exists. However, that pointer may be pointed to any other such array at any time. We want that kind of behaviour for the argument, instead (because this function does not change any of those integers). Declaration follows use.
(p.s.: feel free to improve this sample!)
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
As a rule of thumb, right unary operators (like [], (), etc) take preference over left ones. So, int *(*ptr)()[]; would be a pointer that points to a function that returns an array of pointers to int (get the right operators as soon as you can as you get out of the parenthesis)
I think we can use the simple rule ..
example int * (*ptr)()[];
start from ptr
" ptr is a pointer to "
go towards right ..its ")" now go left its a "("
come out go right "()" so
" to a function which takes no arguments " go left "and returns a pointer " go right "to
an array" go left " of integers "
Here's an interesting website that explains how to read complex types in C:
http://www.unixwiz.net/techtips/reading-cdecl.html
Here's how I interpret it:
int *something[n];
Note on precedence: array subscript operator ([]) has higher priority than
dereference operator (*).
So, here we will apply the [] before *, making the statement equivalent to:
int *(something[i]);
Note on how a declaration makes sense: int num means num is an int, int *ptr or int (*ptr) means, (value at ptr) is
an int, which makes ptr a pointer to int.
This can be read as, (value of the (value at ith index of the something)) is an integer. So, (value at the ith index of something) is an (integer pointer), which makes the something an array of integer pointers.
In the second one,
int (*something)[n];
To make sense out of this statement, you must be familiar with this fact:
Note on pointer representation of array: somethingElse[i] is equivalent to *(somethingElse + i)
So, replacing somethingElse with (*something), we get *(*something + i), which is an integer as per declaration. So, (*something) given us an array, which makes something equivalent to (pointer to an array).
I guess the second declaration is confusing to many. Here's an easy way to understand it.
Lets have an array of integers, i.e. int B[8].
Let's also have a variable A which points to B. Now, value at A is B, i.e. (*A) == B. Hence A points to an array of integers. In your question, arr is similar to A.
Similarly, in int* (*C) [8], C is a pointer to an array of pointers to integer.
int *arr1[5]
In this declaration, arr1 is an array of 5 pointers to integers.
Reason: Square brackets have higher precedence over * (dereferncing operator).
And in this type, number of rows are fixed (5 here), but number of columns is variable.
int (*arr2)[5]
In this declaration, arr2 is a pointer to an integer array of 5 elements.
Reason: Here, () brackets have higher precedence than [].
And in this type, number of rows is variable, but the number of columns is fixed (5 here).
In pointer to an integer if pointer is incremented then it goes next integer.
in array of pointer if pointer is incremented it jumps to next array
What is the difference between the following declarations:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
What is the general rule for understanding more complex declarations?
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
The third one is same as the first.
The general rule is operator precedence. It can get even much more complex as function pointers come into the picture.
Use the cdecl program, as suggested by K&R.
$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>
It works the other way too.
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
I don't know if it has an official name, but I call it the Right-Left Thingy(TM).
Start at the variable, then go right, and left, and right...and so on.
int* arr1[8];
arr1 is an array of 8 pointers to integers.
int (*arr2)[8];
arr2 is a pointer (the parenthesis block the right-left) to an array of 8 integers.
int *(arr3[8]);
arr3 is an array of 8 pointers to integers.
This should help you out with complex declarations.
int *a[4]; // Array of 4 pointers to int
int (*a)[4]; //a is a pointer to an integer array of size 4
int (*a[8])[5]; //a is an array of pointers to integer array of size 5
The answer for the last two can also be deducted from the golden rule in C:
Declaration follows use.
int (*arr2)[8];
What happens if you dereference arr2? You get an array of 8 integers.
int *(arr3[8]);
What happens if you take an element from arr3? You get a pointer to an integer.
This also helps when dealing with pointers to functions. To take sigjuice's example:
float *(*x)(void )
What happens when you dereference x? You get a function that you can call with no arguments. What happens when you call it? It will return a pointer to a float.
Operator precedence is always tricky, though. However, using parentheses can actually also be confusing because declaration follows use. At least, to me, intuitively arr2 looks like an array of 8 pointers to ints, but it is actually the other way around. Just takes some getting used to. Reason enough to always add a comment to these declarations, if you ask me :)
edit: example
By the way, I just stumbled across the following situation: a function that has a static matrix and that uses pointer arithmetic to see if the row pointer is out of bounds. Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))
int *
put_off(const int newrow[2])
{
static int mymatrix[3][2];
static int (*rowp)[2] = mymatrix;
int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);
memcpy(rowp, newrow, sizeof(*rowp));
rowp += 1;
if (rowp == border) {
rowp = mymatrix;
}
return *rowp;
}
int
main(int argc, char *argv[])
{
int i = 0;
int row[2] = {0, 1};
int *rout;
for (i = 0; i < 6; i++) {
row[0] = i;
row[1] += i;
rout = put_off(row);
printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
}
return 0;
}
Output:
0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]
Note that the value of border never changes, so the compiler can optimize that away. This is different from what you might initially want to use: const int (*border)[3]: that declares border as a pointer to an array of 3 integers that will not change value as long as the variable exists. However, that pointer may be pointed to any other such array at any time. We want that kind of behaviour for the argument, instead (because this function does not change any of those integers). Declaration follows use.
(p.s.: feel free to improve this sample!)
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
As a rule of thumb, right unary operators (like [], (), etc) take preference over left ones. So, int *(*ptr)()[]; would be a pointer that points to a function that returns an array of pointers to int (get the right operators as soon as you can as you get out of the parenthesis)
I think we can use the simple rule ..
example int * (*ptr)()[];
start from ptr
" ptr is a pointer to "
go towards right ..its ")" now go left its a "("
come out go right "()" so
" to a function which takes no arguments " go left "and returns a pointer " go right "to
an array" go left " of integers "
Here's an interesting website that explains how to read complex types in C:
http://www.unixwiz.net/techtips/reading-cdecl.html
Here's how I interpret it:
int *something[n];
Note on precedence: array subscript operator ([]) has higher priority than
dereference operator (*).
So, here we will apply the [] before *, making the statement equivalent to:
int *(something[i]);
Note on how a declaration makes sense: int num means num is an int, int *ptr or int (*ptr) means, (value at ptr) is
an int, which makes ptr a pointer to int.
This can be read as, (value of the (value at ith index of the something)) is an integer. So, (value at the ith index of something) is an (integer pointer), which makes the something an array of integer pointers.
In the second one,
int (*something)[n];
To make sense out of this statement, you must be familiar with this fact:
Note on pointer representation of array: somethingElse[i] is equivalent to *(somethingElse + i)
So, replacing somethingElse with (*something), we get *(*something + i), which is an integer as per declaration. So, (*something) given us an array, which makes something equivalent to (pointer to an array).
I guess the second declaration is confusing to many. Here's an easy way to understand it.
Lets have an array of integers, i.e. int B[8].
Let's also have a variable A which points to B. Now, value at A is B, i.e. (*A) == B. Hence A points to an array of integers. In your question, arr is similar to A.
Similarly, in int* (*C) [8], C is a pointer to an array of pointers to integer.
int *arr1[5]
In this declaration, arr1 is an array of 5 pointers to integers.
Reason: Square brackets have higher precedence over * (dereferncing operator).
And in this type, number of rows are fixed (5 here), but number of columns is variable.
int (*arr2)[5]
In this declaration, arr2 is a pointer to an integer array of 5 elements.
Reason: Here, () brackets have higher precedence than [].
And in this type, number of rows is variable, but the number of columns is fixed (5 here).
In pointer to an integer if pointer is incremented then it goes next integer.
in array of pointer if pointer is incremented it jumps to next array
This question already has answers here:
When a function has a specific-size array parameter, why is it replaced with a pointer?
(3 answers)
Closed 8 years ago.
I have the following function in C
int func(char* param1[], int param2[])
{
//Want to calculate size of param1 array
}
I tried
n = sizeof(param1)/sizeof(char*);
but this doesnt give me the correct answer.
Note that the function prototype
int func(char* param1[], int param2[]);
is equivalent to
int func(char **param1, int *param2);
This means the function parameters param1 and param2 are pointers, not arrays. Pointers and arrays are different types.
sizeof(param1) / sizeof(char*);
// equivalent to
sizeof(char **) / sizeof(char *) // always 1
The above expression always evaluates to 1 because size of all pointer types is the same (except for a function pointer on which sizeof operator may not be applied).
That's because you cannot pass an array to a function. What's actually gets passed is a pointer to the first element of the array. The pointer has no size information of the array passed to the function. Therefore, you must explicitly pass the array lengths to your function. It should have the prototype
int func(char *param1[], int param2[], int len_param1, int len_param2);
There are two ways of doing this:
Simplest and most obvious, pass the length in the function argument
Have a NULL at the end of the array (NULL-terminator):
char arr[] = { "what", "so", "ever", NULL }; Then loop:
int i;
for (i = 0; arr[i] != NULL; i++)
...
However, if you're passing an array like the example above to that function (a static one), just pass the length as an argument by using same logic...
func(arr, sizeof(arr) / sizeof(arr[0]);
C isn't smart enough to know the size of an array at runtime. It can only tell you the size of a data type, which is determined at compile-time.
The solution to this is to add a size parameter to the function, like this:
int func(char* param1[], int param2[], int n)
or to use a null-terminated array, so that you can use a loop to iterate through the array:
int func(char* param1[], int param2[]){
int size;
for(size = 0; param1[size] != NULL; size++);
...
The point is, an array in C is just a block of memory that you can happen to treat as a bunch of variables next to each other. There's no built-in way to figure out how many variables are in the block, since there's no built-in way to mark the beginning or end of the block.
char* param1[]
will make param a pointer of type char ** so the result of
n = sizeof(param1)/sizeof(char*);
is sizeof pointer by size of pointer i.e. 1. and its not size of array