Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!aioe.org!.POSTED!not-for-mail From: Thomas David Rivers Newsgroups: comp.lang.c++ Subject: Re: Problem with array objects Date: Fri, 27 May 2011 19:34:44 -0400 Organization: Aioe.org NNTP Server Lines: 359 Message-ID: <4DE03514.7080802@dignus.com> References: <846dndOds94DPEbQnZ2dnUVZ8ridnZ2d@giganews.com> <5cadnQfIzuppjUHQnZ2dnUVZ8kidnZ2d@giganews.com> <805Dp.26220$7H.26163@newsfe08.ams2> <4DDD0AE0.9080001@dignus.com> <4DDD34A8.6030005@dignus.com> <4VdDp.17340$h35.4417@newsfe19.ams2> <4DDD9893.9060502@dignus.com> <4DDE50C0.1080402@dignus.com> <8ktDp.17767$h35.800@newsfe19.ams2> <4DDE9FCD.9050005@dignus.com> <4DDFA87C.9060808@dignus.com> <4DDFF65B.8010007@dignus.com> <21UDp.11231$5C7.1331@newsfe10.ams2> NNTP-Posting-Host: 5vmandCOS2XnoG0+Ic8whg.user.speranza.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: Mozilla/5.0 (X11; U; FreeBSD i386; en-US; rv:1.7.13) Gecko/20061027 X-Accept-Language: en-us, en X-Notice: Filtered by postfilter v. 0.8.2 Xref: x330-a1.tempe.blueboxinc.net comp.lang.c++:5740 Paul wrote: > > "Thomas David Rivers" wrote in message > news:4DDFF65B.8010007@dignus.com... > >> Paul wrote: >> >>>>>> >>>>>>> >>>>>>>> >>>>>>>> So - do we agree that an array is a contigous set of like-typed >>>>>>>> elements, >>>>>>>> where the elements are accessed via the []-operator? >>>>>>>> >>>>>>> Yes I aggree with that. >>>>>>> >>>>>> >>>>>> So - next let's examine a rather simple declaration of an array >>>>>> in C/C++. >>>>>> >>>>>> int arr[5]; >>>>> >>>>> >>>>> >>>>> >>>>> No do a dynamic array like so: >>>>> int* arr = new int[5]; >>>>> >>>>> Then there is no confusion about array objects, an array is simply >>>>> the region of memory storing the integer objects and nothing more. >>>>> >>>>> Having read ahead you seem to be slowly introducing this "arr" >>>>> object into the equation without first aggreeing on a definition >>>>> of what exactly "arr" is. And that is what was the original argument. >>>>> >>>>> In the above example of a dynamic array there is no confusion that >>>>> "arr" is a pointer. >>>>> >>>>> >>>> >>>> You are correct - what you have declared there is a pointer to an >>>> integer, >>>> (the `int *arr' portion), and that pointer is initialized with >>>> some dynamically >>>> allocated space (the `new' portion.) The dynamically allocated >>>> space is a >>>> contiguous set of 5 'int' elements (the `int[5]' portion.) The >>>> pointer's name is 'arr'. >>>> >>>> That's all well and good, but it is very different from what I was >>>> talking about. >>>> >>>> What I'd like to focus on is this simple declaration: >>>> >>>> int arr[5]; >>>> >>>> Can we agree that the declaration of >>>> >>>> int arr[5]; >>>> >>>> represents, at runtime, a set of 5 contiguous 'int' elements. The >>>> name of the set of 5 contiguous elements it 'arr'. The name 'arr' >>>> refers to the runtime location of the set of 5 contiguous elements. >>>> >>>> If we can, I'd like to restrict the conversation to just that for the >>>> moment... we can get to the other stuff soon enough... but, one >>>> thing at a time. >>>> >>> Yes I agree with this, but before we can proceed any further we need >>> to agree on what exactly "arr" is. >>> You are calling it a name that refers to the contiguous sequence of >>> elements here. >>> I would like to establish just what exactly it is because it seems >>> to store a memory address as can be show with: >>> int arr[5]; >>> int* p = arr; >>> >>> So lets try to agree about what exactly arr is. >>> As you know I have been calling it an array type object. >>> >>> >> >> That would basically be the next step... >> >> However, I want to hold to the definition; 'arr' is simply the name >> of the 5 contiquous int elements. >> >> Now - let's take up the problem of assignment to a pointer... >> >> Let's consider this snippet: >> >> int i; >> int *ip; >> >> ip = &i; >> >> would you agree that the semantics of that would be that >> 'i' is the name of an `int'. `ip' is the name of a pointer to an `int'. >> The expression: >> >> &i >> >> denotes "the address of the `int' named `i'" >> >> And the expression: >> >> ip = &i; >> >> denotes "compute the address of the `int' named 'i', store that >> value into the pointer-to-`int' named `ip'." >> >> Does that sound correct? >> >> If so, then we can begin to look at your example involving `arr'; >> and - we can compare the two with considerations toward just >> what it means to assign a value to the `int' pointer named `ip'. >> > Yes this is agreeable. You may continue to the next step :) > OK - let's review - so we know we're on the same page: int arr[5]; 'arr' is the name of the set of 5 contiguous `int'-typed elements. int *ip; `ip' is the name of a variable that can contain the address of an `int', it is a "pointer to int". And: int i; `i' is the name of an `int'-tpe variable. The expression: ip=&i; computes the address of `i', and places that value into the variable `ip'. This is what we've agreed to thus far... right? This establishes that `ip' is not the same type as `arr'. `arr' is the contiguous set of 5 `int' elements, `ip' can contain the address of an `int', it can "point to" an `int'. There is nothing new in that statement; it is a re-statement of the preceeding items we've agreed to (in that `arr' is the set, `ip' is a single pointer.) Now - in a programming language like C/C++, typically the language might enforce rules regarding assignent. One such rule is that assignments can only be made from a value of the destination type, and that if the types are not the same, then some mechanism is employed to convert from oen type to another (if possible). As an example: double d; int i; d = i; The variable `i' is an `int'; `d' is a `double'. You might decide, in a programming language, that such an assignment not be allowed - but it is in C/C++ because the `int' value contained in `i' will be, at runtime, converted to a `double' and then stored in the variable `d'. In this instance, would you say there was a "magic"/secret object of type `double' that was created along with `i' to contain the converted result before assigning the value to `d'? Or, would you say that the conversion simply occurs as a matter-of-course? I think, most people would say that the compiler generates code which effects the conversion at runtime, so that `i' is, at runtime, converted to a double, and the temporary value that results from that conversion is stored in `d'. But; this is a well-defined conversion... does the C/C++ language definition provide any such mechanism for this snippet: int *ip; int arr[5]; ip = arr; Given the definitions (to which we've all agreed), `ip' is a pointer to an `int', and `arr' is a contigous set of 5 `int' elements. How could those two types be reconciled to allow this assignment??? What is going on here?? As it so happens, the designers of C (and, by extension, C++) considered this problem, and provide a mechanism by which such an assignment is accomplished. This mechanism has been written down in the various standard documents, so that everyone can read it and truly understand what is meant by that assignment. First - recall, as you have agreed, that arr' is an array of 5 `int' elements. (we clearly cannot assign 5 `int' elements in-toto to a pointer to a single `int', in a reasonable type-system, at least.) So - given that `arr' is an array, I will quote from the C standard, which might be a little more clear than the C++ one (simply for this discussion, the C++ definition is similar): Section 6.3.2.1 Lvalues, arrays, and function designators Paragraph #1: An lvalue is an expression with an object type or an incomplete type other than void. (that is, `arr' is an "lvalue", it is an "lvalue" with an object type of int[5]. An "lvalue" in C is basically what can appear on the left-hand-side of the assignment operator, the opposing "rvalue" appears on the right-hand-side. That is, you assign the rvalue to the lvalue. In this case, `arr' is an lvalue, until you get to the next step.) Paragraph #3: Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression "pointer to type" that points to the initial element of the array object and it is not an lvalue. In this example, `arr' is not the operand of sizeof(), nor the unary &, an it is not a string literal to initialize an array. Thus, the conversion applies. So... what do we have in this: int *ip; int arr[5]; ip = arr; Let's take the expression 'arr', which is the value being assigned. According to the rules, it is an "lvalue".. it's type (as we agreed) is an array of 5 int elements. When such an expression is used, the language definition indicates that it should be converted to an expression that is a pointer to the element type. The value of that expression is a pointer to the first element. After that, the expression is no longer an "lvalue" (it can't be assigned to, hence it is not `modifiable'). [As an aside, the effect of not being an "lvalue" is that it can't appear on the left-hand-side of the assignment operator, thus you cannot have: arr = ; because 'arr' would be converted to the non-lvalue expression.] So, following that logic; the semantics of the expression `arr', are completely the same as if this was this expression: ip = (&arr[0]); Do you not agree that the expression "&arr[0]" is the address of the first element of `arr'? Clearly the type of "&arr[0]" (the address of the first `int' element of `arr') is the address of a single `int'. Thus, the assignment is valid, and the program is valid. Now. did the C/C++ language definition provide a separate object to compute "&arr[0]"? I believe, we agreed before that there was no separate object in this snippet: int *ip; int i; ip = &i; I recall we both agreed that the semantics of that were that the address of `i' was computed, and that value was placed in `ip'. Similarly, this snippet: int *ip; int arr[5]; ip = (&arr[0]); would simply compute the address of the first (0th) element of `arr' and place that value in `ip'. There would be no separate object required to be a pointer to the array... there is simply the array and the fact that we can compute its address when needed. And, because of the rule I cited above, this snippet: int *ip; int arr[5]; ip = arr; is equivalent to the previous one (in that `arr' is an lvalue expression of an array type, and it is therefor converted to a pointer to the array's first element.) So, you see, there is no separate "object" of any kind defined by the language, nor required in the implementation. It's simply a matter of following the rules set out in the C/C++ definition. If you agree with all of this, then I'd like to discuss how the []-operator (indexing) is defined... it simply "falls out" from this very simple approach. And, it is frequently why people confuse pointers-and-arrays. To recap: 1) An array is a contigous set of same-typed elements. 2) A pointer to a variable that contains an address. 3) A pointer is not an array, an array is not a pointer. 4) The C/C++ languages provide for situations where implicit conversions occur. 5) One such situation is that when an expression is an lvalue, and the type of that expression is an array; the expression is converted to an expression that is a pointer to the first element of the array. So - you see - it's really rather simple, no actual "magic" behind this at all.. no magic 'array type object' or anything like that. Just some basic definitions on which to build... If you agre with all of this, then, as I mentioned above, I'd like to explore how the indexing operator [] works; especially its relationship to pointer arithmetic. And, we should explore the caveats mentioned in the conversion rule (particularly, the & operator when applied to an expression of array type.) - Dave Rivers - -- rivers@dignus.com Work: (919) 676-0847 Get your mainframe programming tools at http://www.dignus.com