doubt in USING POINTERS

L

lawrence.jones

In comp.std.c Kevin Bracey said:
And why are we only worried about structure returns here? Doesn't C99's new
lvalue definition also allow weird things like

int *x = &abs(1);
*&abs(3) = 2

No.

-Larry Jones

I always send Grandma a thank-you note right away. ...Ever since she
sent me that empty box with the sarcastic note saying she was just
checking to see if the Postal Service was still working. -- Calvin
 
T

thp

+ (e-mail address removed) wrote:
+> + (e-mail address removed) wrote:
+> +> [...]
+> +> + The way I prefer to describe situations involving arrays uses
+> +> + somewhat different terminology from that in the C standards. In
+> +> + my notation, we have "objects" and "values", rather than "lvalues"
+> +> + and "values".
+> +>
+> +> Agreed. C89/90 attempted to define an "lvalue" to be an object-valued
+> +> expression but ran afoul of the fact that to maintain sanity we must
+> +> accept "*0" as an lvalue.
+> +
+> + I don't see why. "*0" violates a constraint.
+>
+> The expression "*0" doesn't denote an object.
+
+ "*0" is not a valid expression at all. No C implementation is
+ required to translate a program containing such an expression, because
+ "0" is not an acceptable operand for unary "*". You may be thinking
+ of "*(int *)0" or similar.

Oops! Yes, that's what I meant.

Thanks,
Tom Payne
 
W

Wojtek Lerch

Not in C; it's only valid until the next sequence point.

The standard says that trying to *access* it after the next sequence point
produces undefined behaviour, but that's not exactly the same as saying that
that's when its lifetime ends. In particular, I don't think it's clear that
the pointer to such an object becomes indeterminate at the next sequence
point.

int main(void)
{
int *ptr = func().arr, a;
return &a == ptr; // Undefined?
}
 
C

CBFalconer

James said:
As I understand the argument, it only applies to the case where
the address being taken is the address of a member of structure.
It's only rarely possible to squeeze a structure into a register;
I don't think it's a major burden on code generators to
effectively prohibit that option.

Consider a machine with a stack and registers too small to hold
the return value (some form of struct). Where is it to place that
value? Local space is not allowed, since it goes out of scope.
It could malloc space and return a pointer, but that involves
special consideration after use by the caller.

The caller can allocate stack space at some agreed upon offset,
and the function can store the results there. This allows the
caller to purge it together with any passed parameters, for
"caller cleans up" protocols.

Having done this, that space goes out of scope slightly later that
the rest of the function variables, but it still goes. To save
the value it must be copied somewhere. No address of any portion
of the return can be taken, because that storage may shortly (next
instruction or so) be released.
 
T

thp

+ (e-mail address removed) wrote:
+> Agreed. C89/90 attempted to define an "lvalue" to be an object-valued
+> expression but ran afoul of the fact that to maintain sanity we must
+> accept "*0" as an lvalue. We might slip out of that embarrassment by
+> positing a "null object" that *0 designates, but what's its type?
+> Obviously, the matter gets even more difficult when there are
+> reference types.
+
+ That's completely wacky. "*0" is not allowed in strictly conforming

Oops, make that "*(int*)0".

+ programs, does not occur in any program I know of, and is perforce
+ irrelevant to the C standard.

Tom Payne
 
J

James Kuyper

Gabriel Dos Reis said:
| Keith Thompson wrote:
| ...
| > I still wonder about the semantics of this. I've just tried another
| > test program that assigns a value to *ptr and then prints it out.
| > This doesn't, of course, imply that doing so is valid; it could still
| > be undefined behavior.
| >
| > The question is, what is the lifetime of the int object that ptr
| > points to? It's part of the value returned by a function, so I
| > normally wouldn't expect it to outlive the expression containing the
| > call, but being able to grab a pointer to it makes it all very
| > confusing.
|
| You're correct. The lifetime of that int object is the same as the
| lifetime of the structure object it's a member of: the full-expression
| containing the function call. It outlasts the function call itself, and
| can therefore be used in parts of the same full-expression that are
| guaranteed to be evaluated after the function call, but it cannot be
| used in the next statement after the one containing the function call.

Do you have formal reference(s) for that claim?

Yes, I do: section 12.2p3. Unfortunately, it's from the C++ standard.
:-( Sorry!

The correct answer for C99 is that the returned structure remains
useable only until the next sequence point (6.5.2.2p5).
 
J

James Kuyper

Wojtek Lerch said:
The standard says that trying to *access* it after the next sequence point
produces undefined behaviour, but that's not exactly the same as saying that
that's when its lifetime ends. In particular, I don't think it's clear that
the pointer to such an object becomes indeterminate at the next sequence
point.

The purpose of the concept of "lifetime" is to describe the period of
time during which the object can be accessed. I don't think you can
make that distinction.
 
G

Gabriel Dos Reis

(e-mail address removed) (James Kuyper) writes:

| The correct answer for C99 is that the returned structure remains
| useable only until the next sequence point (6.5.2.2p5).

yep. Not very useful, IMO :-(

-- Gaby
 
W

Wojtek Lerch

The purpose of the concept of "lifetime" is to describe the period of
time during which the object can be accessed. I don't think you can
make that distinction.

No, the purpose of the concept of "lifetime" is to describe the period
of time *outside of which* you can't access the object and you can't
even have a pointer to the object. *During* that period, accessing
the object may or may not produce undefined behaviour, depending on
numerous details of how you try to access it, what its contents are,
whether restrict pointers to it exist, and so on. It's an important
distinction: just because trying to access an object produces
undefined behaviour for some reason, it doesn't mean that the object's
lifetime has ended and any pointer that used to point to it is not a
valid pointer any more. And 6.5.2.2p5 doesn't talk about the lifetime
-- it's just one of the many places that talk about undefined
behaviour.

In short, when an object's lifetime ends is not determined by whether
accessing the object produces undefined behaviour or not. It's
determined by the object's storage duration (6.2.4p1). Trouble is,
the C standard seems to have forgotten to define a type of storage
duration suitable for those temporary objects returned by a function.
If you assume that it must be one of the three defined storage
durations, the pointer should stay valid until at least the end of the
block, right?...
 
J

Joe Wright

Wojtek Lerch said:
(e-mail address removed) (James Kuyper) wrote in message

No, the purpose of the concept of "lifetime" is to describe the period
of time *outside of which* you can't access the object and you can't
even have a pointer to the object. *During* that period, accessing
the object may or may not produce undefined behaviour, depending on
numerous details of how you try to access it, what its contents are,
whether restrict pointers to it exist, and so on. It's an important
distinction: just because trying to access an object produces
undefined behaviour for some reason, it doesn't mean that the object's
lifetime has ended and any pointer that used to point to it is not a
valid pointer any more. And 6.5.2.2p5 doesn't talk about the lifetime
-- it's just one of the many places that talk about undefined
behaviour.

In short, when an object's lifetime ends is not determined by whether
accessing the object produces undefined behaviour or not. It's
determined by the object's storage duration (6.2.4p1). Trouble is,
the C standard seems to have forgotten to define a type of storage
duration suitable for those temporary objects returned by a function.
If you assume that it must be one of the three defined storage
durations, the pointer should stay valid until at least the end of the
block, right?...

I think not. Functions return values, not objects. The concept of an
address of a value or of a member of a value is foreign to me. Assign
the value returned by the function to a suitable object and operate on
the object.
 
M

Micah Cowan

+ (e-mail address removed) wrote:
+> Agreed. C89/90 attempted to define an "lvalue" to be an object-valued
+> expression but ran afoul of the fact that to maintain sanity we must
+> accept "*0" as an lvalue. We might slip out of that embarrassment by
+> positing a "null object" that *0 designates, but what's its type?
+> Obviously, the matter gets even more difficult when there are
+> reference types.
+
+ That's completely wacky. "*0" is not allowed in strictly conforming

Oops, make that "*(int*)0".

The above expression invokes UB, unless it is immediately the
operand of &.

-Micah
 
L

lawrence.jones

In comp.std.c CBFalconer said:
Having done this, that space goes out of scope slightly later that
the rest of the function variables, but it still goes. To save
the value it must be copied somewhere. No address of any portion
of the return can be taken, because that storage may shortly (next
instruction or so) be released.

"Slightly later" must be at least the next sequence point, since you
need to be able to assign the entire struct or access members. That
just happens to be exactly the same as the lifetime of the pointer you
get from a contained array. The only reason the pointer is allowed to
exist at all is so that it can be immediately dereferenced; there is no
point in storing it for later use since what it points to will, as you
say, no longer exist. It's just plain silly to allow f().x but not
allow f().a[0].

-Larry Jones

I always send Grandma a thank-you note right away. ...Ever since she
sent me that empty box with the sarcastic note saying she was just
checking to see if the Postal Service was still working. -- Calvin
 
W

Wojtek Lerch

Joe Wright said:
I think not. Functions return values, not objects. The concept of an
address of a value or of a member of a value is foreign to me. Assign
the value returned by the function to a suitable object and operate on
the object.

I see nothing wrong about a member of a value, provided that the value is a
struct or a union. The address of a value sounds at best suspicious to me,
too; but that's how the C standard is written.

Consider:

struct foo { int x, arr[2]; } fun( void );

int i = fun().x;
int j = fun().arr[0];

The expression "fun()" produces a value (not an lvalue) of type "struct foo"
(6.5.2.2p5).

The expression "fun().x" produces a value (not an lvalue) of type int
(6.5.2.3p3).

The expression "fun().arr" produces a value (not an lvalue) of type "int[2]"
(6.5.2.3p3).

That value is then converted to the pointer to the initial element of the
array (6.3.2.1p3). This is the funny part: the array is not an lvalue, but
for this conversion to happen, its elements must be objects that you can
take the address of.

Dereferencing that pointer produces an lvalue (even though the array wasn't
an lvalue). 6.4.2.2p5 specifically forbids us to modify that lvalue, but
converting it to a value is fine.
 
T

thp

+ (e-mail address removed) writes:
+
+> + (e-mail address removed) wrote:
+> +> Agreed. C89/90 attempted to define an "lvalue" to be an object-valued
+> +> expression but ran afoul of the fact that to maintain sanity we must
+> +> accept "*0" as an lvalue. We might slip out of that embarrassment by
+> +> positing a "null object" that *0 designates, but what's its type?
+> +> Obviously, the matter gets even more difficult when there are
+> +> reference types.
+> +
+> + That's completely wacky. "*0" is not allowed in strictly conforming
+>
+> Oops, make that "*(int*)0".
+
+ The above expression invokes UB, unless it is immediately the
+ operand of &.

Right, but not necessarily so at compile time since it can occur in
a context that is never executed:

if ( 0 ) *(int*)0;

Obviously the frivolity of that construct is obvious at compile time,
but one can construct a function f() such that determing whether f()
is 0 is equivalent to the halting problem. Then the frivolity of

if ( f() ) *(int*)0;

is not statically determinable.

Tom Payne
 
C

CBFalconer

In comp.std.c CBFalconer said:
Having done this, that space goes out of scope slightly later that
the rest of the function variables, but it still goes. To save
the value it must be copied somewhere. No address of any portion
of the return can be taken, because that storage may shortly (next
instruction or so) be released.

"Slightly later" must be at least the next sequence point, since you
need to be able to assign the entire struct or access members. That
just happens to be exactly the same as the lifetime of the pointer you
get from a contained array. The only reason the pointer is allowed to
exist at all is so that it can be immediately dereferenced; there is no
point in storing it for later use since what it points to will, as you
say, no longer exist. It's just plain silly to allow f().x but not
allow f().a[0].

But this is allowed IMO. It is selecting a component value, not
taking any address. The operation is part of the expression
containing the function call, so there is no sequence point before
it is used. This is allied with the fact that an array, as a
component of a structure, is returned by value as an array, not as
any form of pointer.

For the implementor, a must be characterized by an offset from the
start of the containing structure. Indexing that array is just a
matter of adding some multiple of the array element size to that
offset. The compiler knows these values. If the whole schmeer
can be in registers, the implementation must act appropriately.
 
L

lawrence.jones

In comp.std.c CBFalconer said:
But this is allowed IMO. It is selecting a component value, not
taking any address. The operation is part of the expression
containing the function call, so there is no sequence point before
it is used. This is allied with the fact that an array, as a
component of a structure, is returned by value as an array, not as
any form of pointer.

But for subscripting to work, the array must be converted into a pointer
to its first element. So it *is* taking an address, implicitly.
For the implementor, a must be characterized by an offset from the
start of the containing structure. Indexing that array is just a
matter of adding some multiple of the array element size to that
offset. The compiler knows these values. If the whole schmeer
can be in registers, the implementation must act appropriately.

Exactly. And since the lifetime of the "object" pointed to is so short,
it's no burden on the compiler to do the right thing. If a user is so
foolish as to try to store that pointer, the compiler is at liberty to
simply make up a value, since it can't possibly be used without invoking
undefined behavior.

-Larry Jones

Girls are so weird. -- Calvin
 
J

James Kuyper

[email protected] (Wojtek Lerch) wrote in message news: said:
In short, when an object's lifetime ends is not determined by whether
accessing the object produces undefined behaviour or not. It's
determined by the object's storage duration (6.2.4p1). Trouble is,
the C standard seems to have forgotten to define a type of storage
duration suitable for those temporary objects returned by a function.

I agree; storage duration was the first place I looked, and I was
rather annoyed to not find it covered. The C++ standard defines the
lifetime of what it calls "temporary objects"; the next C standard
could be improved by borrowing that concept, and perhaps a lot of the
relevant wording, as well.
If you assume that it must be one of the three defined storage
durations, the pointer should stay valid until at least the end of the
block, right?...

Each of the three defined storage durations has a description of the
circumstances under which it applies; none of them cover this case.
Therefore, the accessibility of the returned structure is controlled
only by the statement that which says that it can't be safely accessed
after the next sequence point. I'd prefer a positive statement that it
can be safely accessed, until the next sequence point.
 
W

Wojtek Lerch

James Kuyper said:
(e-mail address removed) (Wojtek Lerch) wrote in message
...
Each of the three defined storage durations has a description of the
circumstances under which it applies; none of them cover this case.

Still, 6.2.4p1 says that every object has a storage duration and that only
three storage durations exist to choose from. The list of cases in 6.2.4 is
not exactly exhaustive -- it doesn't cover compound literals, either. You
have to go to 6.5.2.5p6 to find out how compound literals fit into the
scheme of the three defined storage durations.

Since the storage duration of the result of a function isn't specified
anywhere, the safest choice seems to be to assume that it's unspecified; but
6.2.4p1 seems to imply that it must be one of the three anyway.
Therefore, the accessibility of the returned structure is controlled
only by the statement that which says that it can't be safely accessed
after the next sequence point. I'd prefer a positive statement that it
can be safely accessed, until the next sequence point.

Agreed.

BTW It just occured to me that structure assignment has the same problem --
or even worse, because as far as I can tell, the standard does not say
anywhere that you can't modify the value or access it after the next
sequence point:

struct { int arr[2]; } a, b;

( a = b ).arr[0] = 6;
int *p = ( a = b ).arr;
*p = 7;

In C++, the result of a simple assignment is an lvalue, and it's clear that
(a=b).arr[0] refers to a.arr[0]. In C, if feels more appropriate for the
result of a=b to be a third copy of the structure value, distinct from a and
b. But the standard doesn't say that anywhere, does it?...
 
A

Avinash

#include<stdio.h>
void main()
{
int x[5]={1,2,3,4,5};
printf("\naddr in x:%p",x);
printf("\nnumber in the addr stored in x is:%d",*x);
x=x+1;
printf("\naddr in x after incrementation is:%p",x);
printf("\nnumber in the addr stored in x is:%d",*x);
}

Hay Ambika,
What I understood from your problem is you want to print address of
some element in the array.
First thing, You are trying to increment the base address of array,
which is not allowed in c, See the problem is C compiler do not have
any kind of Array Bounds checking, It can work with array because it
know the base address of the array, and if you try to change the base
address of the array, then C compile will go in vague condition. So
never change the base address
rather than do one thing take another integer pointer and assign it
the base address of the array and then increment that you will get the
answeryou expect.

thanking you.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top