473,397 Members | 2,099 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

C++ sizeof

Hello, if I have the following code that has an array of int*:

#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>

using namespace std;

int main(){
int x = 1;
int y = 2;
int z = 3;

int* a[] = {&x,&y,&z};
int* c[] = {&x,&y};

cout << sizeof(a) << endl;
cout << sizeof(c) << endl;

return 0;
}

The output is 12 and 8. "sizeof" is supposed to return the number of
bytes its argument occupies according to its argument type, i.e.
without actually evaluating its argument. Since both "a" and "c" have
type "int**", why does "sizeof" return different values?

Thanks.

Apr 26 '07 #1
42 6980
Jess wrote:
Hello, if I have the following code that has an array of int*:

#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>

using namespace std;

int main(){
int x = 1;
int y = 2;
int z = 3;

int* a[] = {&x,&y,&z};
int* c[] = {&x,&y};

cout << sizeof(a) << endl;
cout << sizeof(c) << endl;

return 0;
}

The output is 12 and 8. "sizeof" is supposed to return the number of
bytes its argument occupies according to its argument type, i.e.
without actually evaluating its argument. Since both "a" and "c" have
type "int**", why does "sizeof" return different values?
No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'. They
are _arrays_, not pointers. If your compiler supports decent typeid
information, you could output the type yourself

cout << typeid(a).name() << endl;

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 26 '07 #2
Jess wrote:
Since both "a" and "c" have
type "int**", why does "sizeof" return different values?
Wrong assumption. Both a and c are not of type int**.
--
Sumit Rajan <su*********@gmail.com>
Apr 26 '07 #3
On Apr 26, 8:28 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Jess wrote:
Hello, if I have the following code that has an array of int*:
#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>
using namespace std;
int main(){
int x = 1;
int y = 2;
int z = 3;
int* a[] = {&x,&y,&z};
int* c[] = {&x,&y};
cout << sizeof(a) << endl;
cout << sizeof(c) << endl;
return 0;
}
The output is 12 and 8. "sizeof" is supposed to return the number of
bytes its argument occupies according to its argument type, i.e.
without actually evaluating its argument. Since both "a" and "c" have
type "int**", why does "sizeof" return different values?

No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'. They
are _arrays_, not pointers. If your compiler supports decent typeid
information, you could output the type yourself
I thought sizeof when applied to an array gives the number of elements
in the array. Shouldn't the output be 3 and 2 ?

Apr 26 '07 #4
dragoncoder wrote:
On Apr 26, 8:28 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>Jess wrote:
>>Hello, if I have the following code that has an array of int*:
>>#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>
>>using namespace std;
>>int main(){
int x = 1;
int y = 2;
int z = 3;
>> int* a[] = {&x,&y,&z};
int* c[] = {&x,&y};
>> cout << sizeof(a) << endl;
cout << sizeof(c) << endl;
>> return 0;
}
>>The output is 12 and 8. "sizeof" is supposed to return the number of
bytes its argument occupies according to its argument type, i.e.
without actually evaluating its argument. Since both "a" and "c"
have type "int**", why does "sizeof" return different values?

No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'. They
are _arrays_, not pointers. If your compiler supports decent typeid
information, you could output the type yourself
I thought sizeof when applied to an array gives the number of elements
in the array.
Why would you think that?
Shouldn't the output be 3 and 2 ?
Yes, but only if sizeof(int) == 1.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 26 '07 #5
On 26 Apr 2007 08:50:13 -0700, dragoncoder <pk******@gmail.comwrote:

>I thought sizeof when applied to an array gives the number of elements
in the array. Shouldn't the output be 3 and 2 ?
sizeof, in general, gives the size of the object in bytes.

It is useful for when you do memset or memcmp or memcpy
which requires sizes in bytes...
Easy to use graphics effects:
http://www.ransen.com/
Apr 26 '07 #6
Owen Ransen wrote:
On 26 Apr 2007 08:50:13 -0700, dragoncoder <pk******@gmail.comwrote:

>I thought sizeof when applied to an array gives the number of
elements in the array. Shouldn't the output be 3 and 2 ?

sizeof, in general, gives the size of the object in bytes.

It is useful for when you do memset or memcmp or memcpy
which requires sizes in bytes...
It's useful in many other places, like 'write' or 'read' or 'malloc'...
They all operate in bytes, of course.

Generally speaking there is no sense to make 'sizeof' behave differently
depending on the argument's being an array versus a scalar object. It's
more important for 'sizeof' to be consistent. Since returning 1 or 0
for non-array object is useless, 'sizeof' was made to return byte count
and for consistency reasons it does the same for any type of argument.

If one needs to know the size of the array, one can always get it like
this:

sizeof(somearray) / sizeof(somearray[0])

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 26 '07 #7
Also remember that the sizof operator does it's thing at compile
time. If the compiler cannot correctly compute the size of the
arguement passed to the sizeof operator, it will not return the result
you may have been expecting. For example if you pass an array as an
arguement to a function, the sizeof operator will not return the size
of the array (when used in the function on the passed array), but
instead will return the size of the pointer which points to the array.

Apr 26 '07 #8
blangela wrote:
Also remember that the sizof operator does it's thing at compile
time. If the compiler cannot correctly compute the size of the
arguement passed to the sizeof operator, it will not return the result
you may have been expecting. For example if you pass an array as an
arguement to a function, the sizeof operator will not return the size
of the array (when used in the function on the passed array), but
instead will return the size of the pointer which points to the array.
That all depends on how you pass it. The thing is, 'sizeof' always
calculates the size of the object (based on the static type), or of the
type, or the expression (with all promotions/conversions applied), and
it is only unable to do that in an illegal program, from, say incomplete
type. If the program compiles, 'sizeof' did what is asked of it. And
since references are not objects, if you pass the reference to 'sizeof',
you will get the size of the referred object; which brings us to

#include <cstddef>
template<class T>
size_t getsize(T &t) // passing by reference
{
return sizeof t;
}

int main()
{
int a[10];
size_t s = getsize(a); // s will be 10*sizeof(int)
}
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 26 '07 #9
No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'. They
are _arrays_, not pointers. If your compiler supports decent typeid
information, you could output the type yourself

cout << typeid(a).name() << endl;
Although "a" and "c" are arrays, when we use their names as a values,
they are effectively pointers, aren't they? so "a" is the pointer
pointing to the first element of the array. since each element in "a"
is a "int*", "a" should be "int**", where have I done wrong?
moreover, if we do: "*a", then it's "&x", isn't it? Thanks.

Apr 27 '07 #10
On Apr 27, 7:42 am, blangela <Bob_Langel...@telus.netwrote:
Also remember that the sizof operator does it's thing at compile
time. If the compiler cannot correctly compute the size of the
arguement passed to the sizeof operator, it will not return the result
you may have been expecting. For example if you pass an array as an
arguement to a function, the sizeof operator will not return the size
of the array (when used in the function on the passed array), but
instead will return the size of the pointer which points to the array.
do you mean in my problem:

#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>

using namespace std;

int main(){
int x = 1;
int y = 2;
int z = 3;

int* a[] = {&x,&y,&z};
cout << sizeof(a) << endl;

return 0;

}

since I pass "a" that is an array to sizeof, it will return the size
of the "int*"? This is what I expected but the result was 12, instead
of 1 or something else.

Apr 27 '07 #11
On Apr 27, 8:22 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
That all depends on how you pass it. The thing is, 'sizeof' always
calculates the size of the object (based on the static type),
what is "static type"?
or of the type, or the expression (with all promotions/conversions applied),
what kind of promotions/conversions?
and it is only unable to do that in an illegal program, from, say incomplete
type.
When could an incomplete type occur?
If the program compiles, 'sizeof' did what is asked of it. And
since references are not objects, if you pass the reference to 'sizeof',
you will get the size of the referred object;
if I pass a pointer (instead of a reference), then do I get the size
of the pointer? similarly, if I pass an object (pass-by-value), then
do I get the size of the object?

Thanks.

Apr 27 '07 #12
Jess wrote:
>No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'. They
are _arrays_, not pointers. If your compiler supports decent typeid
information, you could output the type yourself

cout << typeid(a).name() << endl;

Although "a" and "c" are arrays, when we use their names as a values,
they are effectively pointers, aren't they?
If they are used in an expression other than in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type.
so "a" is the pointer
pointing to the first element of the array. since each element in "a"
is a "int*", "a" should be "int**", where have I done wrong?
I don't understand the "where have I done wrong" question.
moreover, if we do: "*a", then it's "&x", isn't it? Thanks.
Again, you lost me here. What's 'x'?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 27 '07 #13
Jess wrote:
On Apr 27, 7:42 am, blangela <Bob_Langel...@telus.netwrote:
>Also remember that the sizof operator does it's thing at compile
time. If the compiler cannot correctly compute the size of the
arguement passed to the sizeof operator, it will not return the
result you may have been expecting. For example if you pass an
array as an arguement to a function, the sizeof operator will not
return the size of the array (when used in the function on the
passed array), but instead will return the size of the pointer which
points to the array.

do you mean in my problem:

#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>

using namespace std;

int main(){
int x = 1;
int y = 2;
int z = 3;

int* a[] = {&x,&y,&z};
cout << sizeof(a) << endl;

return 0;

}

since I pass "a" that is an array to sizeof, it will return the size
of the "int*"? This is what I expected but the result was 12, instead
of 1 or something else.
You got the result you were supposed to get: sizeof(int*) * 3
because 'a' is an array.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 27 '07 #14
Jess wrote:
On Apr 27, 8:22 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>That all depends on how you pass it. The thing is, 'sizeof' always
calculates the size of the object (based on the static type),

what is "static type"?
The type of the expression at compile time.
>or of the type, or the expression (with all promotions/conversions
applied),

what kind of promotions/conversions?
Standard promotions/conversions, for example when you say a+b, and
'a' is of type 'char' and 'b' is of type 'long', the expression
will have the type 'long'.
>and it is only unable to do that in an illegal program, from, say
incomplete type.

When could an incomplete type occur?
When you only declare it (like this

struct A;

) and don't define it.
>If the program compiles, 'sizeof' did what is asked of it. And
since references are not objects, if you pass the reference to
'sizeof', you will get the size of the referred object;

if I pass a pointer (instead of a reference), then do I get the size
of the pointer?
Sure.
similarly, if I pass an object (pass-by-value), then
do I get the size of the object?
Yes.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 27 '07 #15
On Apr 27, 10:42 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
If they are used in an expression other than in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type.
By "template argument" do you mean something like this?
template<class X>
void foo(X* a);

where "a" is an array, each of its elements has type "X"?

Can you please elaborate a bit on "as an initialiser of a reference of
the array type"? :)
so "a" is the pointer
pointing to the first element of the array. since each element in "a"
is a "int*", "a" should be "int**", where have I done wrong?

I don't understand the "where have I done wrong" question.
I meant my deduction tells me "a" should have type "int**", but
instead, it's an array of int*.
moreover, if we do: "*a", then it's "&x", isn't it? Thanks.

Again, you lost me here. What's 'x'?
I defined "a" in this program:

#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>

using namespace std;

int main(){
int x = 1;
int y = 2;
int z = 3;

int* a[] = {&x,&y,&z};
int* c[] = {&x,&y};

cout << sizeof(a) << endl;
cout << sizeof(c) << endl;

return 0;

}

Thanks.

Apr 27 '07 #16
On Apr 27, 10:44 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Jess wrote:
On Apr 27, 8:22 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
That all depends on how you pass it. The thing is, 'sizeof' always
calculates the size of the object (based on the static type),
what is "static type"?

The type of the expression at compile time.
or of the type, or the expression (with all promotions/conversions
applied),
what kind of promotions/conversions?

Standard promotions/conversions, for example when you say a+b, and
'a' is of type 'char' and 'b' is of type 'long', the expression
will have the type 'long'.
and it is only unable to do that in an illegal program, from, say
incomplete type.
When could an incomplete type occur?

When you only declare it (like this

struct A;

) and don't define it.
If the program compiles, 'sizeof' did what is asked of it. And
since references are not objects, if you pass the reference to
'sizeof', you will get the size of the referred object;
if I pass a pointer (instead of a reference), then do I get the size
of the pointer?

Sure.
similarly, if I pass an object (pass-by-value), then
do I get the size of the object?

Yes.
Thanks a lot. :)

Apr 27 '07 #17
Jess wrote:
On Apr 27, 10:42 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>If they are used in an expression other than in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type.

By "template argument" do you mean something like this?
template<class X>
void foo(X* a);

where "a" is an array, each of its elements has type "X"?
No. In this case, if 'foo' is called like 'foo(a)' and 'a' is, in
fact an array, the X will be deduced as the element type because 'a'
will decay. However, if you drop the asterisk, and then call 'foo'
with a true array, 'X' is likely to be deduced as "an array of N of
blah".
Can you please elaborate a bit on "as an initialiser of a reference of
the array type"? :)
int (&ra)[10] = a;

here 'a' does not decay.
>
>>so "a" is the pointer
pointing to the first element of the array. since each element in
"a" is a "int*", "a" should be "int**", where have I done wrong?

I don't understand the "where have I done wrong" question.

I meant my deduction tells me "a" should have type "int**", but
instead, it's an array of int*.
What deduction? You only provide the conclusion, not the path that
you took to reach it. How could I point out the mistake somewhere
on that path when you only indicate the destination?
>
>>moreover, if we do: "*a", then it's "&x", isn't it? Thanks.

Again, you lost me here. What's 'x'?

I defined "a" in this program:

#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>

using namespace std;

int main(){
int x = 1;
int y = 2;
int z = 3;

int* a[] = {&x,&y,&z};
int* c[] = {&x,&y};

cout << sizeof(a) << endl;
cout << sizeof(c) << endl;

return 0;

}

Thanks.
Alright, even though I've lost your trail of thought, the
answer is 'yes', *a equals &x.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 27 '07 #18
On Apr 27, 12:50 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
By "template argument" do you mean something like this?
template<class X>
void foo(X* a);
where "a" is an array, each of its elements has type "X"?

No. In this case, if 'foo' is called like 'foo(a)' and 'a' is, in
fact an array, the X will be deduced as the element type because 'a'
will decay. However, if you drop the asterisk, and then call 'foo'
with a true array, 'X' is likely to be deduced as "an array of N of
blah".
If foo's signature is

void foo(X* a);

Then when I call foo(a), then the compiler knows foo is expecting a
pointer-type argument and hence array "a" decays to a pointer. Is this
what happens? If the signature of foo becomes

void foo(X a);

Then when I pass an array "a" to foo like "foo(a)", then does the
compiler always forbid "a" to decay? Why does a compiler do that? Is
array the only data structure with this behaviour?

This reminds me of another question. What I've learned before is that
if we have a function whose argument is not a pointer type or
reference type, then it's always pass-by-value. Following this
reasoning, it seems if we do "foo(a)", then the compiler will copy "a"
to "foo". Now the problem arises. What does it mean to copy an
array? Do we copy its contents or the address of its first element?

Can you please elaborate a bit on "as an initialiser of a reference of
the array type"? :)

int (&ra)[10] = a;

here 'a' does not decay.
Why does compiler do that? The different treatments to arrays are
very complicated, why would C++ compilers make things so hard? I
imagine there must be some reason behind it. more likely to do with
the way compilers work. Can you please tell me the reason behind all
of these complications, as it helps me to understand the strange
behaviour?

What deduction? You only provide the conclusion, not the path that
you took to reach it. How could I point out the mistake somewhere
on that path when you only indicate the destination?
I skipped my deduction path, sorry. :) But I understand what you mean
now. :)
Thanks,
Jess

Apr 27 '07 #19
On Apr 26, 7:29 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
If one needs to know the size of the array, one can always get it like
this:
sizeof(somearray) / sizeof(somearray[0])
Note that this is very error prone, as it will silently give
wrong results when applied to a pointer. In C++, a much better
solution is:

template< typename T, size_t N >
inline size_t
size( T (&array)[ N ] )
{
return N ;
}

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 27 '07 #20
On Apr 27, 2:11 am, Jess <w...@hotmail.comwrote:
No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'. They
are _arrays_, not pointers. If your compiler supports decent typeid
information, you could output the type yourself
cout << typeid(a).name() << endl;
Although "a" and "c" are arrays, when we use their names as a values,
they are effectively pointers, aren't they?
No. They convert implicitly to pointers in contexts where an
array would be illegal. (Double's will implicitly convert to
char, as well. You wouldn't say that they are effectively
char's, I hope.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 27 '07 #21
On Apr 27, 7:52 pm, James Kanze <james.ka...@gmail.comwrote:
Note that this is very error prone, as it will silently give
wrong results when applied to a pointer.
When we give an array name "a" to sizeof, "a" won't be treated as a
pointer. so when will 'sizeof' be wrongly applied to a pointer? can
you please give an example? thanks
Apr 27 '07 #22
On Apr 27, 7:54 pm, James Kanze <james.ka...@gmail.comwrote:
No. They convert implicitly to pointers in contexts where an
array would be illegal.
But how do we know when an array is legal? since an array is treatd
as an array by "sizeof", then I guess it is legal to have an array for
"sizeof". As Victor has pointed out, an array's name is always
regarded as a pointer except when it is used in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type. Therefore, it seems arrays are illegal for most of the
situations. Under what circumstances are arrays illegal? this still
confuses me.
(Double's will implicitly convert to
char, as well. You wouldn't say that they are effectively
char's, I hope.)
Do you mean an array of doubles is converted to a pointer pointing to
chars?
Thanks

Apr 27 '07 #23
On Apr 27, 4:50 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Jess wrote:
On Apr 27, 10:42 am, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
If they are used in an expression other than in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type.
By "template argument" do you mean something like this?
template<class X>
void foo(X* a);
where "a" is an array, each of its elements has type "X"?
No. In this case, if 'foo' is called like 'foo(a)' and 'a' is, in
fact an array, the X will be deduced as the element type because 'a'
will decay. However, if you drop the asterisk, and then call 'foo'
with a true array, 'X' is likely to be deduced as "an array of N of
blah".
No.

First, there are only two contexts where using the name of an
array is relevant to template instantiation. The first is as a
template argument. In that context, it cannot match a type
argument (since the name of an array is not a type), and
templates cannot have non-type array arguments. In such cases,
it is matched more or less as it would be if it were a function
argument. The second is when it is an argument to a function,
one (or more) of whose overloads is a template, and type
deduction is applied. In such cases, the rules are such that if
the template function paramter is not a reference, an array type
will be converted to a pointer. The final result is that
template functions work pretty much like non template functions,
e.g.:

template< typename T >
void f( T x ) ;

int array[ 20 ] ;
f( array ) ;
instantiates:
void f( int* x ) ;

but

template< typename T >
void f( T& x ) ;

int array[ 20 ] ;
f( array ) ;
instantiates:
void f( int (&x)[20] ) ;

Note that template argument deduction can handle even more
complex cases. I can't imagine a professional programmer in C++
today, for example, who doesn't have something like the
following in his toolkit:

template< typename T >
T*
begin( T (&array)[ N ] )
{
return array ;
}

template< typename T >
T*
end( T (&array)[ N ] )
{
return array + N ;
}

template< typename T >
size_t
size( T (&array)[ N ] )
{
return N ;
}

They fournish C style arrays with some of the main functionality
of standard containers.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 27 '07 #24
On 27 Apr 2007 02:52:19 -0700, James Kanze <ja*********@gmail.com>
wrote:
>On Apr 26, 7:29 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>If one needs to know the size of the array, one can always get it like
this:
> sizeof(somearray) / sizeof(somearray[0])

Note that this is very error prone, as it will silently give
wrong results when applied to a pointer. In C++, a much better
solution is:

template< typename T, size_t N >
inline size_t
size( T (&array)[ N ] )
{
return N ;
}
Out of curiosity, is the lack of const-qualification on the parameter
intentional?

In my code, I'm using the following for quite some time now:

#include <cstddef>

namespace breeze {

template< typename T, std::size_t n >
std::size_t
count( const T ( & )[ n ] )
{
return n;
}

template< typename T >
typename T::size_type
count( const T & t )
{
return t.size();
}

}

And I've similar mini-templates for begin and end. Together, they
allow you to write things such as begin( a ), end( a ), count( a ),
regardless of whether a is a built-in array or a standard container:
that's one less thing to change if, for instance, you replace a
built-in array with tr1::array<>.

--
Gennaro Prota
https://sourceforge.net/projects/breeze/
Apr 27 '07 #25
Jess wrote:
>No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'. They
are _arrays_, not pointers. If your compiler supports decent typeid
information, you could output the type yourself

cout << typeid(a).name() << endl;

Although "a" and "c" are arrays, when we use their names as a values,
they are effectively pointers, aren't they?
No when you use their names, they are effectively arrays. This is a
grand misconception. What they do have is an implicit conversion to
pointer type. This is coupled with some rather long term C stupidities
that never got corrected in that arrays can not be assigned, passed by
value, or returned by value. The language provides a ghastly crutch
where an array type in a parameter of a function is silently changed
to pointer type.

? so "a" is the pointer
pointing to the first element of the array.
Untrue.
Apr 27 '07 #26
On Apr 27, 12:03 pm, Jess <w...@hotmail.comwrote:
On Apr 27, 7:52 pm, James Kanze <james.ka...@gmail.comwrote:
Note that this is very error prone, as it will silently give
wrong results when applied to a pointer.
When we give an array name "a" to sizeof, "a" won't be treated as a
pointer. so when will 'sizeof' be wrongly applied to a pointer?
Why on earth should it? An array name is the name of an array.
In an expression, it has the type array[] of whatever; its value
is the contents of the array.

There aren't many things you can do with an array in C++, but
taking their size (or typeid) is one.
can you please give an example?
The classical example would be:

void
func( char array[10] )
{
std::cout << sizeof( array ) / sizeof( array[ 0 ] ) <<
std::endl ;
}

On my system, this outputs 0. It's an easy trap to fall into,
because it *looks* like the argument of the function is an
array. In fact, of course, C++ doesn't allow arrays to be
parameters of functions, and this is exactly equivalent to:

void
func( char* array )
{
std::cout << sizeof( array ) / sizeof( array[ 0 ] ) <<
std::endl ;
}

There is simply no array anywhere around.

My alternative version takes advantage of template argument
deduction. Since it requires an array, any attempt to use it on
a pointer will result in a compile time error.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 27 '07 #27
On Apr 27, 12:58 pm, Gennaro Prota <address@spam_this.comwrote:
On 27 Apr 2007 02:52:19 -0700, James Kanze <james.ka...@gmail.com>
wrote:
On Apr 26, 7:29 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
If one needs to know the size of the array, one can always get it like
this:
sizeof(somearray) / sizeof(somearray[0])
Note that this is very error prone, as it will silently give
wrong results when applied to a pointer. In C++, a much better
solution is:
template< typename T, size_t N >
inline size_t
size( T (&array)[ N ] )
{
return N ;
}
Out of curiosity, is the lack of const-qualification on the parameter
intentional?
More or less:-). In fact, I rarely use this one, and only added
it for completeness' sake. In the ones I do use, begin() and
end(), the lack of const is very intentional; if the array is
const, the compiler will add it automatically, and if it's not,
I want non const pointers to be returned, so that I can use them
as arguments to e.g. std::transform. The reason why this one
isn't const is simply parallelism with the other two.
In my code, I'm using the following for quite some time now:
#include <cstddef>
namespace breeze {
template< typename T, std::size_t n >
std::size_t
count( const T ( & )[ n ] )
{
return n;
}
template< typename T >
typename T::size_type
count( const T & t )
{
return t.size();
}
}
And I've similar mini-templates for begin and end.
But without the const, I imagine:-).

Note that about all the const buys you is that if you
instantiate once on int[10], and a second type on int const[10],
you only get one function, not two. As my functions are inline,
and I can't think of a case where the address (identity) would
be important, that doesn't bother me.
Together, they allow you to write things such as begin( a ),
end( a ), count( a ), regardless of whether a is a built-in
array or a standard container: that's one less thing to change
if, for instance, you replace a built-in array with
tr1::array<>.
Good point. I don't have the second versions, but then, I don't
write much generic code.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 27 '07 #28
On 27 Apr 2007 04:56:54 -0700, James Kanze <ja*********@gmail.com>
wrote:
>On Apr 27, 12:58 pm, Gennaro Prota <address@spam_this.comwrote:
>On 27 Apr 2007 02:52:19 -0700, James Kanze <james.ka...@gmail.com>
wrote:
>On Apr 26, 7:29 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>If one needs to know the size of the array, one can always get it like
this:
> sizeof(somearray) / sizeof(somearray[0])
>Note that this is very error prone, as it will silently give
wrong results when applied to a pointer. In C++, a much better
solution is:
template< typename T, size_t N >
inline size_t
size( T (&array)[ N ] )
{
return N ;
}
>Out of curiosity, is the lack of const-qualification on the parameter
intentional?

More or less:-). In fact, I rarely use this one, and only added
it for completeness' sake. In the ones I do use, begin() and
end(), the lack of const is very intentional; if the array is
const, the compiler will add it automatically, and if it's not,
I want non const pointers to be returned, so that I can use them
as arguments to e.g. std::transform.
Yes. I had const and non-const overloads for begin() and end(), until
I posted my previous reply and realized that was pretty useless :-) So
I immediately updated the code:
<http://breeze.svn.sourceforge.net/viewvc/breeze/trunk/breeze/iteration/>

As to size() (or count(), as it's called in my library) the const
doesn't buy anything either. Stylistically, I like to have it, so I
asked whether your omission was unintentional or due to a different
view on style issues.
>The reason why this one
isn't const is simply parallelism with the other two.
>In my code, I'm using the following for quite some time now:
> #include <cstddef>
> namespace breeze {
> template< typename T, std::size_t n >
std::size_t
count( const T ( & )[ n ] )
{
return n;
}
> template< typename T >
typename T::size_type
count( const T & t )
{
return t.size();
}
}
>And I've similar mini-templates for begin and end.

But without the const, I imagine:-).
Er... see above :-)

--
Gennaro Prota
https://sourceforge.net/projects/breeze/
Apr 27 '07 #29
On Apr 27, 12:11 pm, Jess <w...@hotmail.comwrote:
On Apr 27, 7:54 pm, James Kanze <james.ka...@gmail.comwrote:
No. They convert implicitly to pointers in contexts where an
array would be illegal.
But how do we know when an array is legal?
The same way you know when anything is legal: the language
definition says what can and cannot be done with each type.
since an array is treatd as an array by "sizeof", then I guess
it is legal to have an array for "sizeof".
Right.
As Victor has pointed out, an array's name is always
regarded as a pointer except when it is used in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type.
I'm not sure Victor really knows the language. Some of his
posts seem to show great knowledge, and others contain blatent
misconceptions. In this case: an array's name is *never*
regardes as a pointer. *Never*, *ever*. An array's name is the
name of an array. When used in an expression, it has type
array[] of X. Always. Without exception.

Of course, C++ is noted for its lack of type safety, and it's
lossy conversions. Try something like:

double d = 3.14159 ;
std::string s ;
s = d ;

for example. Or for more fun:

int i = 0 ;
int const c = 0 ;
std::string s ;
s += i ;
s += c ;

The first is---surprisingly---fully defined and legal, although
it probably doesn't do what one might expect. (Actually, any
reasonable person would expect it to be illegal.) The second
has undefined behavior, and will generally result in a core
dump.

The problem isn't that d doesn't have type double, or that i or
c don't have type int. The problem is that C++ is just full of
unexpected and unintuitive implicit conversions. One of those
unexpected, unintuitive conversions is that an array implicitly
converts to a pointer. And in this case, two additional
"defects" in the language add to the conversion. The first is
that there are really very few things you can legally do with an
array---even indexation isn't legal on an array (but it is on a
pointer!). Which means that the implicit conversion occurs a
lot more often than one might like. The second is that
functions cannot have array types as parameters. If the
declaration of the parameter looks like an array, the compiler
automatically converts it into a pointer. Thus:

void f( int array[10] ) ;

declares a function which takes a pointer to an int as argument
(and not an array!), and the name array, within the function, is
not the name of an array, but of a pointer.
Therefore, it seems arrays are illegal for most of the
situations. Under what circumstances are arrays illegal?
I think you're approaching the problem backwards. C++ defines a
set of operators. For each operator, it defines what types are
legal as operands. Unless a type is defined as legal for a
specific operand, it is illegal.
this still confuses me.
It's one of the first things you have to learn, however. In any
statically typed language.
(Double's will implicitly convert to
char, as well. You wouldn't say that they are effectively
char's, I hope.)
Do you mean an array of doubles is converted to a pointer pointing to
chars?
No. Doubles are converted to chars. Arrays of doubles are
arrays of doubles.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 27 '07 #30
Jess wrote:
On Apr 27, 12:50 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>>By "template argument" do you mean something like this?
template<class X>
void foo(X* a);
>>where "a" is an array, each of its elements has type "X"?

No. In this case, if 'foo' is called like 'foo(a)' and 'a' is, in
fact an array, the X will be deduced as the element type because 'a'
will decay. However, if you drop the asterisk, and then call 'foo'
with a true array, 'X' is likely to be deduced as "an array of N of
blah".

If foo's signature is

void foo(X* a);

Then when I call foo(a), then the compiler knows foo is expecting a
pointer-type argument and hence array "a" decays to a pointer. Is this
what happens? If the signature of foo becomes

void foo(X a);

Then when I pass an array "a" to foo like "foo(a)", then does the
compiler always forbid "a" to decay? Why does a compiler do that? Is
array the only data structure with this behaviour?

This reminds me of another question. What I've learned before is that
if we have a function whose argument is not a pointer type or
reference type, then it's always pass-by-value. Following this
reasoning, it seems if we do "foo(a)", then the compiler will copy "a"
to "foo". Now the problem arises. What does it mean to copy an
array? Do we copy its contents or the address of its first element?
Yes, you're right. Arrays have no pass-by-value semantics, so I was
incorrect assuming that (X a) would cause 'X' to be deduces as 'array of'.
See James' reply as well. He elaborated on template argument deduction
well enough even for me to understand.
>>Can you please elaborate a bit on "as an initialiser of a reference
of the array type"? :)

int (&ra)[10] = a;

here 'a' does not decay.

Why does compiler do that?
Because the type of 'ra' is "a reference to an array". If 'a' were to
decay, there would be no way to verify the size. And I assume 'a' has
the size 10, otherwise it won't compile. IOW, for your original example
this would have to change to

int (&ra)[3] = a;

(since 'a' has size 3).
The different treatments to arrays are
very complicated, why would C++ compilers make things so hard?
I am guessing it's in attempts to make arrays (which are very, very
delapidated entities in C++ language) conform a bit more to the rest
of the language.
I
imagine there must be some reason behind it. more likely to do with
the way compilers work. Can you please tell me the reason behind all
of these complications, as it helps me to understand the strange
behaviour?
Again, I am not sure. I am guessing that there was the need to make
it work one way or another, and the designers just picked the way that
would work in the majority of cases. Simplicity is not always the
primary concern. In most problems you and I solve we just need to
remember that arrays decay into pointers, and if we need their size,
we just pass it along. Or better yet, don't use arrays, use standard
containers.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 27 '07 #31
what is the example of how I would call this templated function?

Apr 27 '07 #32
liam_herron wrote:
what is the example of how I would call this templated function?
Which function is that?
Apr 27 '07 #33
Victor Bazarov wrote:
Jess wrote:
No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'.
They are arrays, not pointers. If your compiler supports decent
typeid information, you could output the type yourself
>
cout << typeid(a).name() << endl;
Although "a" and "c" are arrays, when we use their names as a
values, they are effectively pointers, aren't they?

If they are used in an expression other than in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type.
Also, rather importantly, when used with the address-of (&) operator.
So if you have:

int a[2];
Then &a, is NOT a pointer to pointer to int, but a pointer to array 2
of int.
I know you know that, of course.


Brian
Apr 27 '07 #34
Default User wrote:
Victor Bazarov wrote:
>Jess wrote:
>>>No, 'a' has the type 'int*[3]', and 'c' has the type 'int*[2]'.
They are arrays, not pointers. If your compiler supports decent
typeid information, you could output the type yourself

cout << typeid(a).name() << endl;

Although "a" and "c" are arrays, when we use their names as a
values, they are effectively pointers, aren't they?

If they are used in an expression other than in 'sizeof' or 'typeid',
or as a template argument, or as an initialiser of a reference of the
array type.

Also, rather importantly, when used with the address-of (&) operator.
So if you have:

int a[2];
Then &a, is NOT a pointer to pointer to int, but a pointer to array 2
of int.
I know you know that, of course.
No, you're right, I had forgotten about it. Thanks for reminding.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 27 '07 #35
Victor Bazarov wrote:
Default User wrote:
Victor Bazarov wrote:
Jess wrote:
No, 'a' has the type 'int*[3]', and 'c' has the type
'int*[2]'. They are arrays, not pointers. If your compiler
supports decent typeid information, you could output the type
yourself
>
cout << typeid(a).name() << endl;

Although "a" and "c" are arrays, when we use their names as a
values, they are effectively pointers, aren't they?
>
If they are used in an expression other than in 'sizeof' or
'typeid', or as a template argument, or as an initialiser of a
reference of the array type.
Also, rather importantly, when used with the address-of (&)
operator. So if you have:

int a[2];
Then &a, is NOT a pointer to pointer to int, but a pointer to array
2 of int.
I know you know that, of course.

No, you're right, I had forgotten about it. Thanks for reminding.

Sure. You don't see the explicit use of addressing with arrays all that
often, but the implicit use comes up and causes significant confusion
(I think elsewhere here, in fact).

People often wonder about this:
void f(int **p)
{
}

int a[2][2];

f(a); // bzzzzzzt, not allowed.
That's because, of course, the conversion of array to pointer gives a
pointer to the first element, which in the above case is the same as
what I mentioned above.

Brian
Apr 27 '07 #36
On Apr 26, 3:06 pm, Jess <w...@hotmail.comwrote:
Hello, if I have the following code that has an array of int*:

#include<iostream>
#include<string>
#include<cstring>
#include<cstddef>

using namespace std;

int main(){
int x = 1;
int y = 2;
int z = 3;

int* a[] = {&x,&y,&z};
int* c[] = {&x,&y};

cout << sizeof(a) << endl;
cout << sizeof(c) << endl;

return 0;

}

The output is 12 and 8. "sizeof" is supposed to return the number of
bytes its argument occupies according to its argument type, i.e.
without actually evaluating its argument. Since both "a" and "c" have
type "int**", why does "sizeof" return different values?
Hi all
I will contribute with an exercise. I hope you will find it pleasant.

Fill the following table:
sizeof("Jess") = ?
sizeof(*"Jess") = ?
sizeof(&*"Jess") = ?

How many hits did you have?
Regards
Kostas

Apr 27 '07 #37
kostas wrote:

Fill the following table:
sizeof("Jess") = ?
5
sizeof(*"Jess") = ?
1
sizeof(&*"Jess") = ?
Implementation specific.

Brian

Apr 27 '07 #38
Which function is that?
> template< typename T, size_t N >
inline size_t
size( T (&array)[ N ] )
{
return N ;
}


Apr 30 '07 #39
On Apr 27, 11:49 pm, James Kanze <james.ka...@gmail.comwrote:
The classical example would be:

void
func( char array[10] )
{
std::cout << sizeof( array ) / sizeof( array[ 0 ] ) <<
std::endl ;
}

On my system, this outputs 0.
Is your system a Pentium 66? ;)

Apr 30 '07 #40
* Old Wolf:
On Apr 27, 11:49 pm, James Kanze <james.ka...@gmail.comwrote:
>The classical example would be:

void
func( char array[10] )
{
std::cout << sizeof( array ) / sizeof( array[ 0 ] ) <<
std::endl ;
}

On my system, this outputs 0.

Is your system a Pentium 66? ;)
I think perhaps James was heading for bed (or perhaps already in bed,
late in the evening) when he wrote the article you responded to here.
For he's well aware that sizeof(char) cannot be greater than 1, and
also, that arrays can be passed by reference in C++. Not exactly
typo's, nor exactly thinko's, but just drowso's, sort of.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Apr 30 '07 #41
On Apr 27, 12:11 pm, Jess <w...@hotmail.comwrote:
>
Although "a" and "c" are arrays, when we use their names as a values,
they are effectively pointers, aren't they? so "a" is the pointer
pointing to the first element of the array.
NO

"a" and "c" are arrays. They are never anything else.
In fact "a" is an array of 3 elements and "c" is an array
of 2 elements. This never changes.
since each element in "a" is a "int*", "a" should be "int**",
where have I done wrong?
You are confusing arrays with pointers.
An array of N elements of type T, has type "array[N] of T".
moreover, if we do: "*a", then it's "&x", isn't it? Thanks.
Yes, because *a means the same as a[0] , i.e. selecting
the first element of the array.

You might find this page helps to clarify the situation for you:
http://www.torek.net/torek/c/expr.html#therule

Apr 30 '07 #42
On Apr 30, 11:37 pm, "Alf P. Steinbach" <a...@start.nowrote:
* Old Wolf:
On Apr 27, 11:49 pm, James Kanze <james.ka...@gmail.comwrote:
The classical example would be:
void
func( char array[10] )
{
std::cout << sizeof( array ) / sizeof( array[ 0 ] ) <<
std::endl ;
}
On my system, this outputs 0.
Is your system a Pentium 66? ;)
I think perhaps James was heading for bed (or perhaps already in bed,
late in the evening) when he wrote the article you responded to here.
For he's well aware that sizeof(char) cannot be greater than 1, and
also, that arrays can be passed by reference in C++. Not exactly
typo's, nor exactly thinko's, but just drowso's, sort of.
Very much so (and it was probably in the morning, before I'd had
my second coffee).

Change char to double in the function definition, and you'll
often get 0.

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 1 '07 #43

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Sunil Menon | last post by:
Dear All, A class having no member variables and only a method sizeof(object) will return 1byte in ANSI and two bytes in Unicode. I have the answer for this of how in works in ANSI. But I don't...
2
by: Xiangliang Meng | last post by:
Hi, all. What will we get from sizeof(a class without data members and virtual functions)? For example: class abnormity { public: string name() { return "abnormity"; }
19
by: Martin Pohlack | last post by:
Hi, I have a funtion which shall compute the amount for a later malloc. In this function I need the sizes of some struct members without having an instance or pointer of the struct. As...
9
by: M Welinder | last post by:
This doesn't work with any C compiler that I can find. They all report a syntax error: printf ("%d\n", (int)sizeof (char)(char)2); Now the question is "why?" "sizeof" and "(char)" have...
7
by: dam_fool_2003 | last post by:
#include<stdio.h> int main(void) { unsigned int a=20,b=50, c = sizeof b+a; printf("%d\n",c); return 0; } out put: 24
42
by: Christopher C. Stacy | last post by:
Some people say sizeof(type) and other say sizeof(variable). Why?
8
by: junky_fellow | last post by:
Consider the following piece of code: #include <stddef.h> int main (void) { int i, j=1; char c; printf("\nsize =%lu\n", sizeof(i+j));
90
by: pnreddy1976 | last post by:
Hi, How can we write a function, which functionality is similar to sizeof function any one send me source code Reddy
32
by: Abhishek Srivastava | last post by:
Hi, Somebody recently asked me to implement the sizeof operator, i.e. to write a function that accepts a parameter of any type, and without using the sizeof operator, should be able to return...
5
by: Francois Grieu | last post by:
Does this reliably cause a compile-time error when int is not 4 bytes ? enum { int_size_checked = 1/(sizeof(int)==4) }; Any better way to check the value of an expression involving sizeof...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.