sizeof and arrays/pointers question
Author |
Message |
Russell Edwar #1 / 22
|
 sizeof and arrays/pointers question
Hello all... I am (still :-) a little confused about the sizeof() operator and arrays and pointers. consider the array char str[10]; normally if I refer to 'str', it 'decays' to a pointer (char *). for example, if I do printf("%ld", str) (probably not very portable or anything :) printf gets passed a pointer to an array. likewise, if I do long num = (long) str; then num is (attempted to be) set to the pointer to str. Thus for the assignment operator, str decays to a pointer. However, if I do int num = sizeof(str); the sizeof operator DOES NOT make str decay to a pointer, it returns the value 10. Exactly the same thing happens with string literals and arrays delcared like char str[]="Blah" although not for things like char *str = "blah" obviously because str already _is_ a pointer. So, how come some built in operators (eg =) make str[] decay to a pointer before they evaluate it and 'operate' on it, but some of them keep it as an array (eg sizeof) and 'operate' on that? Isn't that a bit inconsistent? Russell --
Student of Computer Science and Electrical and Computer Systems Engineering -\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/- "Errr. Six Hundred and Four, Toxteth O'Grady, USA."
|
Thu, 27 Nov 1997 03:00:00 GMT |
|
 |
Lars Wirzeni #2 / 22
|
 sizeof and arrays/pointers question
Quote: > So, how come some built in operators (eg =) make str[] decay to a pointer > before they evaluate it and 'operate' on it, but some of them keep it as an > array (eg sizeof) and 'operate' on that? Isn't that a bit inconsistent?
Inconsistent, but necessary (as long as you allow array decay at all). If sizeof allowed an array to decay, how would you get the size of one? (If the inconsistency was to be fixed, though I hope it will not, it should be fixed by removing array decay.) --
NEW: Publib version 0.5: ftp://ftp.cs.helsinki.fi/pub/Software/Local/Publib/
|
Fri, 28 Nov 1997 03:00:00 GMT |
|
 |
Nick Maclar #3 / 22
|
 sizeof and arrays/pointers question
|> |> I am (still :-) a little confused about the sizeof() operator and |> arrays and pointers. |> |> ... |> |> So, how come some built in operators (eg =) make str[] decay to a pointer |> before they evaluate it and 'operate' on it, but some of them keep it as an |> array (eg sizeof) and 'operate' on that? Isn't that a bit inconsistent? No, just unspeakably perverse. K&R C was inconsistent, but ANSI C 'cleaned up' the specification. However, the result is so bizarre that no right-minded person would believe it without proof. I shall not attempt to explain what is going on, except to comment that your model of what is going on isn't quite right. You need to put an ice-pack on your head, and study the actual standard, I am afraid. Remember also that sizeof() operates on TYPES and not VALUES, unlike any other construction in C, except possibly offsetof(). Nick Maclaren, University of Cambridge Computer Laboratory, New Museums Site, Pembroke Street, Cambridge CB2 3QG, England.
Tel.: +44 1223 334761 Fax: +44 1223 334679
|
Fri, 28 Nov 1997 03:00:00 GMT |
|
 |
Dan P #4 / 22
|
 sizeof and arrays/pointers question
Quote: > So, how come some built in operators (eg =) make str[] decay to a pointer >before they evaluate it and 'operate' on it, but some of them keep it as an >array (eg sizeof) and 'operate' on that? Isn't that a bit inconsistent?
Arrays decay into pointers when used in a value context. If you keep this simple rule in mind, everything is consistent. You can find more about this in Section 2 of the FAQ. Dan -- Dan Pop CERN, CN Division
Mail: CERN - PPE, Bat. 31 R-004, CH-1211 Geneve 23, Switzerland
|
Fri, 28 Nov 1997 03:00:00 GMT |
|
 |
John Powe #5 / 22
|
 sizeof and arrays/pointers question
Quote:
>Hello all... > I am (still :-) a little confused about the sizeof() operator and >arrays and pointers. > consider the array > char str[10]; > normally if I refer to 'str', it 'decays' to a pointer (char *). for >example, if I do printf("%ld", str) (probably not very portable or anything :) >printf gets passed a pointer to an array. likewise, if I do > long num = (long) str; > then num is (attempted to be) set to the pointer to str. Thus for >the assignment operator, str decays to a pointer. However, if I do > int num = sizeof(str); > the sizeof operator DOES NOT make str decay to a pointer, it returns the >value 10. Exactly the same thing happens with string literals and >arrays delcared like > char str[]="Blah" > although not for things like > char *str = "blah" > obviously because str already _is_ a pointer. > So, how come some built in operators (eg =) make str[] decay to a pointer >before they evaluate it and 'operate' on it, but some of them keep it as an >array (eg sizeof) and 'operate' on that? Isn't that a bit inconsistent?
Perhaps this confusion arises because the sizeof operator generates no runtime code on compliant compilers. The quantity is determined at compile time. Most other operators must have parameters evaluated at run-time. Quote: >Russell
John Powell
|
Fri, 28 Nov 1997 03:00:00 GMT |
|
 |
Tanmoy Bhattachar #6 / 22
|
 sizeof and arrays/pointers question
Quote: Sonnack) writes:
|> |> > I am (still :-) a little confused about the sizeof() operator and |> > arrays and pointers. |> |> My way of looking at it is that sizeof() returns the actual amount |> of memory allocated for the object in question. In terms of their |> //type//, examples A and B are the same, but in terms of the amount That is wrong, if by //type// you mean anything usual. Only the type of the decayed value of A (e.g. the type of A+0) is the same as the type of B. Because of the many automatic type transformations that go on in C, this is not actually unusual: e.g. after `char x;' x has type char, but +x has type int. |> of allocated memory (for the variables), they are very different: |> |> example A: char A [] = "Poohbear"; |> example B: char* B = "Poohbear"; I tend to look upon array decay as happening in a _value_ context: i.e. whenever a non-register lvalue array needs to be converted to an rvalue; as opposed to when it merely refers to an object i.e. _is_ an lvalue. sizeof gives the size of the result of an expression thought of as an object (even if it is not an lvalue), which because of the fixed typing scheme of C is indeed the size of the _type_ of the result of the expression which is, therefore, not evaluated at all. (Of course sizeof can operate directly on a type name in parantheses as well). The same rule shows why &A gives a result of a different type than &B above. The operand of & is logically an lvalue (one wants the address of the object: not of its value, surely), and so the array does not decay. The former is a pointer to an array, the latter a pointer to a pointer. Similar rules apply to functions: except that functions are not objects, and so sizeof gives an error when applied to them. Cheers Tanmoy --
Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87544-0285,USA H:#3,802,9 St,NM87545 Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>, <http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/ internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html> fax: 1 (505) 665 3003 voice: 1 (505) 665 4733 [ Home: 1 (505) 662 5596 ]
|
Fri, 28 Nov 1997 03:00:00 GMT |
|
 |
Chris Sonna #7 / 22
|
 sizeof and arrays/pointers question
Quote:
> I am (still :-) a little confused about the sizeof() operator and > arrays and pointers.
My way of looking at it is that sizeof() returns the actual amount of memory allocated for the object in question. In terms of their //type//, examples A and B are the same, but in terms of the amount of allocated memory (for the variables), they are very different: example A: char A [] = "Poohbear"; example B: char* B = "Poohbear"; The (memory use) size of A is 9 bytes; of B it's only sizeof(char*). From: this! Newsgroups: comp.lang.c.moderated Both variables have the same //type//, because C treats an array name as a 'pointer to X'. But there are subtle distinctions because they are different things. -- Chris Sonnack | 3M/Information Technology/Engineering Info Svcs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "The whole earth is in jail and we're plotting this incredible jailbreak."
|
Fri, 28 Nov 1997 03:00:00 GMT |
|
 |
Chris Tore #8 / 22
|
 sizeof and arrays/pointers question
Quote:
> So, how come some built in operators (eg =) make str[] decay to a pointer >before they evaluate it and 'operate' on it, but some of them keep it as an >array (eg sizeof) and 'operate' on that? Isn't that a bit inconsistent?
Consider the statement: int a, b; a = 3; b = a; One can equally say: So, how come some built in operators (eg =) make a variable decay to its value before they evalute it and 'operate' on it, but some of them keep it as a variable? That is, in `b = a', how come we got the *value* of `a' (the `3' from the first assignment) and stuck it in the *object* `b'? To anyone who has been programming for a while, the reason is obvious: some contexts call for an object, and some call for a value. If you put an object where you need a value, the compiler fetches the current value stored in the object. What C does (which is not inconsistent, merely unusual) is to say that the `value' of an array is the address of its first element. Where the array has type `array N of T' (for some integer constant N and valid element type T), the `value' of the array has type `pointer to T'. This does make it virtually impossible to obtain the aggregate value of the array (the values of all the elements) for use in function calls, return statements, and so on, which is one reason other languages treat arrays as first-class citizens. -- In-Real-Life: Chris Torek, Berkeley Software Design Inc
|
Sat, 29 Nov 1997 03:00:00 GMT |
|
 |
Chris Sonna #9 / 22
|
 sizeof and arrays/pointers question
Quote:
>>> I am (still :-) a little confused about the sizeof() operator and >>> arrays and pointers. >> My way of looking at it is that sizeof() returns the actual amount >> of memory allocated for the object in question. In terms of their >> //type//, examples A and B are the same, but in terms of the amount > That is wrong, if by //type// you mean anything usual. Only the type of > the decayed value of A (e.g. the type of A+0) is the same as the type of > B.
Huh? I don't really understand your first sentence there, but your second one has to be in error. Here's the examples from my post: Quote: >> example A: char A [] = "Poohbear"; >> example B: char* B = "Poohbear";
Isn't it true that //both// A and B have the type (char*)? And isn't the type of A+0 a (char), so how can it be the same as B? I don't follow what you're trying to say. I know that I can pass A or B to any function that takes a (char*). They are //not// the same in that B may be an lvalue, A may not, and also in the amount of memory they use. Quote: > Because of the many automatic type transformations that go on in C, this > is not actually unusual: e.g. after `char x;' x has type char, but +x has > type int.
Well, (char) is just a {*filter*}y-tiny (int), afterall. But few compilers will sit still for an attempt to auto-convert between (int) and (int*). There is a big difference there! Quote: > I tend to look upon array decay as happening in a _value_ context: i.e. > whenever a non-register lvalue array needs to be converted to an rvalue; > as opposed to when it merely refers to an object i.e. _is_ an lvalue.
Huh? If I could see through this opaque pedantry, I think I'd disagree. I'm still stuck trying to imagine an IS-register lvalue array... I'm not sure I understand the term "array decay" (an array has the type (X*) where X is the type of the array members??). But I do know that an array name (alone) can //never// BE an lvalue. Does //that// have something to do with your point? Quote: > sizeof gives the size of the result of an expression thought of as an > object (even if it is not an lvalue), which because of the fixed typing > scheme of C is indeed the size of the _type_ of the result of the > expression which is, therefore, not evaluated at all.
Well, I understand the first part, because: int a=1, b=2, c=3; sizeof (a) == sizeof (int); sizeof (a+b) == sizeof (int); sizeof (a+b+c) == sizeof (int); ...but you lost me after the first clause. Yes, C has fixed typing, and, yes, you get the //type// of the expression, and, yes, the expression is not evaluated. And, so...?? Quote: > The same rule shows why &A gives a result of a different type than &B > above. The operand of & is logically an lvalue (one wants the address > of the object: not of its value, surely), and so the array does not decay. > The former is a pointer to an array, the latter a pointer to a pointer.
Do we have different meanings for a lvalue? My understanding is that an "lvalue" is something that can be on the "left side" of an operator. It is something to which you can assign a value. By my understanding, A is //not// an lvalue. Only the second example is valid: char A [] = "Hello"; char* B = "Sailor!"; A = "Good-Night"; /* invalid */ B = "Irene"; /* valid */ Of course &A and &B give different results: the former is the address of an array of (in this case) 6 chars; the latter is the address of a pointer to a(n array of) char(s). A & B //are// different, but I still say that, for most uses, they have the same type. regards, -- Chris Sonnack | 3M/Information Technology/Engineering Info Svcs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "The first duty of a revolutionary is to get away with it."
|
Wed, 03 Dec 1997 03:00:00 GMT |
|
 |
Russell Edwar #10 / 22
|
 sizeof and arrays/pointers question
Quote:
>> So, how come some built in operators (eg =) make str[] decay to a pointer >>before they evaluate it and 'operate' on it, but some of them keep it as an >>array (eg sizeof) and 'operate' on that? Isn't that a bit inconsistent? >Consider the statement: > int a, b; > a = 3; > b = a; >One can equally say: > So, how come some built in operators (eg =) make a variable > decay to its value before they evalute it and 'operate' on > it, but some of them keep it as a variable?
You're absolutely right :-) I hadn't thought of that. Quote: >What C does (which is not inconsistent, merely unusual) is to say >that the `value' of an array is the address of its first element. >Where the array has type `array N of T' (for some integer constant >N and valid element type T), the `value' of the array has type >`pointer to T'. >This does make it virtually impossible to obtain the aggregate >value of the array (the values of all the elements) for use in >function calls, return statements, and so on, which is one reason >other languages treat arrays as first-class citizens.
Yeah that was the conclusion I had reached. Some kind of system where you could pass an array by value, or an pointer to an array of however many dimensions specified in the prototype, with an internal header that contains some internal info like the width of the rows, etc so that both the sizeof() operator and normal indexing will work within a function that is passed to it. (by value or simulated reference) I guess you could do this with structs, but still, full language level support would be good. Russell --
Student of Computer Science and Electrical and Computer Systems Engineering -\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/- "Errr. Six Hundred and Four, Toxteth O'Grady, USA."
|
Wed, 03 Dec 1997 03:00:00 GMT |
|
 |
Henry C. Schoe #11 / 22
|
 sizeof and arrays/pointers question
sizeof() is determined at compile time, not run-time. When you say char str_buf[]="blah" sizeof(str_buf) will be 5, because that is the size of the array. If you say char *str_ptr = "blah" sizeof(str_ptr) returns the size of a pointer. The reason why char *ptr; char *buf = "blah"; ptr=buf; is legal is because of the way computers work. This happens at run time, not compile time. At run time, computers cannot hold arrays internal to the CPU and access them in the way strings are frequently accessed. Hank
|
Wed, 03 Dec 1997 03:00:00 GMT |
|
 |
hgul.. #12 / 22
|
 sizeof and arrays/pointers question
Quote: >My way of looking at it is that sizeof() returns the actual amount >of memory allocated for the object in question. In terms of their >//type//, examples A and B are the same,
I disagree. The data being stored is the same but the types are different. Quote: >but in terms of the amount >of allocated memory (for the variables), they are very different: >example A: char A [] = "Poohbear"; >example B: char* B = "Poohbear"; >The (memory use) size of A is 9 bytes; of B it's only sizeof(char*). >From: this! >Newsgroups: comp.lang.c.moderated >Both variables have the same //type//, because C treats an array >name as a 'pointer to X'.
I disagree. A programmer can use them the same sometimes, but C treats them different. Quote: >But there are subtle distinctions because >they are different things.
When an operator returns different values, I don't cosider that subtle. Quote: >-- >Chris Sonnack | 3M/Information Technology/Engineering Info Svcs
-- Harold Guller
|
Wed, 03 Dec 1997 03:00:00 GMT |
|
 |
Jim Hi #13 / 22
|
 sizeof and arrays/pointers question
Quote:
>Some kind of system where you could pass an array by value, or an pointer >to an array of however many dimensions specified in the prototype, with an >internal header that contains some internal info like the width of the rows
That's getting into PL/I and Algol68 and Ada(?) territory, but if you do know the bounds of an array it's imo very worthwhile to specify them wherever possible, e.g. char (*pbname)[32]; First, and perhaps most valuable, it highlights the array-value semantics at every turn, and second it's potentially very useful for static checks or really studly alias optimizations. I do this myself, and it's caught several buffersize mismatches that would have turned into really, really {*filter*} bugs. mho, Jim -- Jim Hill Contents public domain and worth $.02 more than you paid.
|
Wed, 03 Dec 1997 03:00:00 GMT |
|
 |
Lawrence Kir #14 / 22
|
 sizeof and arrays/pointers question
> sizeof() is determined at compile time, not run-time. It is true that the semantics of sizeof mean it is always determinable at compile time. A compiler isn't required to do this but it would be a poor one that didn't. > When you say > > char str_buf[]="blah" > > sizeof(str_buf) will be 5, because that is the size of the array. More explicitly the definition above gives str_buf type (char [5]) and sizeof returns the size of that type. > > If you say > > char *str_ptr = "blah" > > sizeof(str_ptr) returns the size of a pointer. Yes, here str_ptr has type (char *) and sizeof returns the size of that type. > The reason why > > char *ptr; > char *buf = "blah"; > > ptr=buf; > > is legal is because of the way computers work. This happens at run time, not > compile time. At run time, computers cannot hold arrays internal to the CPU and > access them in the way strings are frequently accessed. No, the reason is the C language definition. "The way computers work" is not relevant (evidence being that most other languages don't work like this). The standard says (in section 6.2.2.1): "Except where it is the operand of the sizeof operator or the unary & operator, or is a character string literal used to initialise an array of character type, or is a wide string literal used to initialise an array with element type compatible with wchar_t, an lvalue that has type ``array of type'' is converted to an expression that has type ``pointer to functions returning type.'' " -- -----------------------------------------
-----------------------------------------
|
Thu, 04 Dec 1997 03:00:00 GMT |
|
 |
Lawrence Kir #15 / 22
|
 sizeof and arrays/pointers question
> > >>> I am (still :-) a little confused about the sizeof() operator and > >>> arrays and pointers. > >> > >> My way of looking at it is that sizeof() returns the actual amount > >> of memory allocated for the object in question. In terms of their > >> //type//, examples A and B are the same, but in terms of the amount > > > > That is wrong, if by //type// you mean anything usual. Only the type of > > the decayed value of A (e.g. the type of A+0) is the same as the type of > > B. > > Huh? I don't really understand your first sentence there, but your > second one has to be in error. Here's the examples from my post: It is correct. > >> example A: char A [] = "Poohbear"; > >> example B: char* B = "Poohbear"; > > Isn't it true that //both// A and B have the type (char*)? And isn't the > type of A+0 a (char), so how can it be the same as B? I don't follow > what you're trying to say. A has type (char [9]) B has type (char *) A+0 has type (char *) A[0], *A, B[0], and *B all have type (char) A is not a pointer (and no pointer exists anywhere in the memory it is stored in). However in C whenever you try to take the value of an array the compiler gives you the address of (i.e. a pointer to) of its first element. That is why A+0 has type (char *). Of course you have to know that when you add an integer to a pointer you get a pointer with the same type. > I know that I can pass A or B to any function that takes a (char*). They > are //not// the same in that B may be an lvalue, A may not, and also in > the amount of memory they use. When passing an array as a function argument you are trying to take its value hence the rule above applies. > > Because of the many automatic type transformations that go on in C, this > > is not actually unusual: e.g. after `char x;' x has type char, but +x has > > type int. > > Well, (char) is just a {*filter*}y-tiny (int), afterall. But few compilers will > sit still for an attempt to auto-convert between (int) and (int*). There > is a big difference there! True, but no such conversion is implied here. > > I tend to look upon array decay as happening in a _value_ context: i.e. > > whenever a non-register lvalue array needs to be converted to an rvalue; > > as opposed to when it merely refers to an object i.e. _is_ an lvalue. > > Huh? If I could see through this opaque pedantry, I think I'd disagree. > I'm still stuck trying to imagine an IS-register lvalue array... I'm not > sure I understand the term "array decay" (an array has the type (X*) > where X is the type of the array members??). It's just another way of stating (perhaps more formally) what I said above. Don't treat it as pedantry, it is a simple rule and when you understand it everything clicks into place. > But I do know that an array name (alone) can //never// BE an lvalue. > Does //that// have something to do with your point? The C standard complicated things slightly by splitting lvalue into modifiable and non-modifiable lvalues. An array is an example of a non-modifiable lvalue. Another example is a const variable. You might think of an lvalue as something with storage duration i.e. can cross statement boundaries whereas an rvalue cannot (that is maybe a somewhat curious definition which just occurred to me, I'm sure others will consider whether it is valid or not!) > > sizeof gives the size of the result of an expression thought of as an > > object (even if it is not an lvalue), which because of the fixed typing > > scheme of C is indeed the size of the _type_ of the result of the > > expression which is, therefore, not evaluated at all. > > Well, I understand the first part, because: > > int a=1, b=2, c=3; > > sizeof (a) == sizeof (int); > sizeof (a+b) == sizeof (int); > sizeof (a+b+c) == sizeof (int); > > ...but you lost me after the first clause. Yes, C has fixed typing, and, > yes, you get the //type// of the expression, and, yes, the expression is > not evaluated. And, so...?? So sizeof(A+0) == sizeof(char *) > > The same rule shows why &A gives a result of a different type than &B > > above. The operand of & is logically an lvalue (one wants the address > > of the object: not of its value, surely), and so the array does not decay. > > The former is a pointer to an array, the latter a pointer to a pointer. > > Do we have different meanings for a lvalue? My understanding is that an > "lvalue" is something that can be on the "left side" of an operator. It > is something to which you can assign a value. By my understanding, A is > //not// an lvalue. Only the second example is valid: A footnote in the standard suggests you think of lvalue to mean "locator value". There are lvalues (i.e. non-modifiable) in C which may not be used on the LHS of an assignment operator. > char A [] = "Hello"; > char* B = "Sailor!"; > > A = "Good-Night"; /* invalid */ > B = "Irene"; /* valid */ > > Of course &A and &B give different results: the former is the address > of an array of (in this case) 6 chars; the latter is the address of a > pointer to a(n array of) char(s). Here A has type (char [6]) and that is the only type it has. That is why &A gives you the address of an array with type (char (*)[6]) > A & B //are// different, but I still > say that, for most uses, they have the same type. The type of A is a property of A which is independent of its use. When you take the value of A the compiler gives you a pointer to its first element with type (char *) but that is no longer A. I realise this is what you're getting at - when you take the value of either A or B you get a (char *) value, but in over-generalising this you easily fall into the trap of assuming pointer and array equivalence and it becomes much more difficult to understand the cases where this falls apart. -- -----------------------------------------
-----------------------------------------
|
Thu, 04 Dec 1997 03:00:00 GMT |
|
|
Page 1 of 2
|
[ 22 post ] |
|
Go to page:
[1]
[2] |
|