Author |
Message |
riha #1 / 18
|
 pointer comparisons
Hi there, 1st question (easy) can a char * reference the byte past the '\0' in a string? 2nd question (extra credit) having the following semi-pseudo snippet: char *c = malloc(10 * sizeof *c); int *i = malloc(10 * sizeof *i); struct s *s = malloc(10 * sizeof *s); iterate(c); iterate(i); iterate(s); void iterate(anytype *p) { for (anytype *pp = p; pp < p + 10; pp++) use(pp); Quote: }
I get the feeling that pointer comparison for at least one of the three given anytype *'s is undefined, because here's what it says in kazlib 1.20 (list.c:316): /* * Determine whether the given pool is from this pool. */ int lnode_pool_isfrom(lnodepool_t *pool, lnode_t *node) { listcount_t i; /* this is carefully coded this way because ANSI C forbids pointers to different objects from being subtracted or compared other than for exact equality */ for (i = 0; i < pool->size; i++) { if (pool->pool + i == node) return 1; } return 0; Quote: }
(I apologize iff these are not the same thing, but I'm equally confused :)) On the other hand, char * comparisons are all to common that I'm hesitating to think of them as invoking undefined behaviour :) -- rihad
|
Sat, 26 Jun 2004 21:42:11 GMT |
|
 |
Joona I Palast #2 / 18
|
 pointer comparisons
Quote: > Hi there, > 1st question (easy) > can a char * reference the byte past the '\0' in a string?
I don't see why not. A pointer is allowed to point (but not dereference) 1 byte past the end of an allocated space. --
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++| | http://www.helsinki.fi/~palaste W++ B OP+ | \----------------------------------------- Finland rules! ------------/ "I am not very happy acting pleased whenever prominent scientists overmagnify intellectual enlightenment." - Anon
|
Sat, 26 Jun 2004 21:53:12 GMT |
|
 |
Richard B #3 / 18
|
 pointer comparisons
Quote:
> 1st question (easy) > can a char * reference the byte past the '\0' in a string?
If there's referable memory there, yes, why not? If there isn't, no, why should it? Note that it is always possible to _point_ one byte past the '\0', because of the one-byte-past-a-memory-block rule; but it is only legal to dereference that pointer if the block is larger than the string it contains. For example: char astr[7]="abcde"; char bstr[6]="abcde"; char *ptr; char chr; ptr=astr+6; /* Legal. */ chr=*ptr; /* Dubious. Illegal only if a char can trap after all, but I'll assume it can't; which means chr now contains garbage, but legal garbage. */ ptr=bstr+6; /* Legal. You're now pointing one past the array. */ chr=*ptr; /* Illegal. You may point one beyond a memory block, but not read whatever may or may not be there. */ Quote: > 2nd question (extra credit) > having the following semi-pseudo snippet: > char *c = malloc(10 * sizeof *c); > int *i = malloc(10 * sizeof *i); > struct s *s = malloc(10 * sizeof *s); > iterate(c); > iterate(i); > iterate(s); > void iterate(anytype *p)
What is anytype? Quote: > { > for (anytype *pp = p; pp < p + 10; pp++) > use(pp); > } > I get the feeling that pointer comparison for at least one of the > three given anytype *'s is undefined,
Depends on what anytype is. If it's any kind of char, it's guaranteed to be defined, as far as the pointer comparison goes. It's dubious practice in any case, though, unless you figure out a way to tell iterate how large your buffer is. Richard
|
Sat, 26 Jun 2004 22:42:54 GMT |
|
 |
Richard B #4 / 18
|
 pointer comparisons
Quote:
> char astr[7]="abcde"; > char bstr[6]="abcde"; > char *ptr; > char chr; > ptr=astr+6; /* Legal. */ > chr=*ptr; /* Dubious. Illegal only if a char can trap after all, but > I'll assume it can't; which means chr now contains > garbage, but legal garbage. */
Doh. I initialised it. It contains '\0', guaranteed. So it's guaranteed to be legal, too. The comment in the quoted bit only goes if it's uninitialised memory into which I've written "abcde", and no more, like this: char astr[7]; /* Assuming block scope. */ strcpy(astr, "abcde"); Richard
|
Sat, 26 Jun 2004 22:46:08 GMT |
|
 |
riha #5 / 18
|
 pointer comparisons
Quote:
>> char astr[7]="abcde"; >> char bstr[6]="abcde"; >> char *ptr; >> char chr; >> ptr=astr+6; /* Legal. */ >> chr=*ptr; /* Dubious. Illegal only if a char can trap after all, but >> I'll assume it can't; which means chr now contains >> garbage, but legal garbage. */ >Doh. I initialised it. It contains '\0', guaranteed. So it's guaranteed >to be legal, too. >The comment in the quoted bit only goes if it's uninitialised memory >into which I've written "abcde", and no more, like this: > char astr[7]; /* Assuming block scope. */ > strcpy(astr, "abcde");
Or perhaps char astr[7] = { 'a', 'b', 'c', 'd', 'e', 0 }; -- rihad
|
Sat, 26 Jun 2004 23:28:17 GMT |
|
 |
riha #6 / 18
|
 pointer comparisons
Quote:
>> char *c = malloc(10 * sizeof *c); >> int *i = malloc(10 * sizeof *i); >> struct s *s = malloc(10 * sizeof *s); >> iterate(c); >> iterate(i); >> iterate(s); >> void iterate(anytype *p) >What is anytype?
It's pseudocode. Think of it as if I had explicitly written iterate_{c, i, s} with the specific anytype. I thought it was obvious from context, sorry. Quote: >> { >> for (anytype *pp = p; pp < p + 10; pp++) >> use(pp); >> } >> I get the feeling that pointer comparison for at least one of the >> three given anytype *'s is undefined, >Depends on what anytype is. If it's any kind of char, it's guaranteed to >be defined, as far as the pointer comparison goes. It's dubious practice >in any case, though, unless you figure out a way to tell iterate how >large your buffer is.
I could have passed the '10' as an arg, that's not the point. Still, why does it make a difference what p (and pp) point at? Is char special? Aren't char, int, struct s all valid C objects? Can't pointer arithmentic adn comparison work all of them with equal semantics? -- rihad
|
Sat, 26 Jun 2004 23:33:35 GMT |
|
 |
riha #7 / 18
|
 pointer comparisons
Quote: >> char astr[7]; /* Assuming block scope. */ >> strcpy(astr, "abcde"); >Or perhaps >char astr[7] = { 'a', 'b', 'c', 'd', 'e', 0 };
Duh, sorry, it won't work, a mind glitch. -- rihad
|
Sat, 26 Jun 2004 23:35:28 GMT |
|
 |
Scott Fluhre #8 / 18
|
 pointer comparisons
Quote: > Hi there, > 2nd question (extra credit) > having the following semi-pseudo snippet: > char *c = malloc(10 * sizeof *c); > int *i = malloc(10 * sizeof *i); > struct s *s = malloc(10 * sizeof *s); > iterate(c); > iterate(i); > iterate(s); > void iterate(anytype *p) > { > for (anytype *pp = p; pp < p + 10; pp++) > use(pp); > }
The problem is that there is no generic pointer type that you can increment. C has a problem with this because a generic pointer type wouldn't have any type information with it, and so it wouldn't know how far to increment the pointer on a pp++, whether to the next char, int or struct s. Here are two ways to do it: void iterate( void *p, size_t increment ) { int i; for (i=0; i<10; i++, p = (char*)p + increment) { use(p); } Quote: }
iterate( c, sizeof *c ); iterate( i, sizeof *i ); iterate( s, sizeof *s ); -- or -- #define iterate( p, type ) \ do { \ int i; \ type pp = p; \ for (i=0; i<10; i++, pp++) \ use(pp); \ } iterate( c, char * ); iterate( i, int * ); iterate( s, struct s* ); (you can get rid of the type argument if you don't mind changing the value of the first parameter). -- poncho
|
Sat, 26 Jun 2004 23:58:30 GMT |
|
 |
riha #9 / 18
|
 pointer comparisons
On Tue, 8 Jan 2002 07:58:30 -0800, "Scott Fluhrer"
<snipped> Since you're yet another poster after Richard Bos who misunderstood the point of anytype * and iterate, I really ought to rethink my conversational skills :) Sorry :) The point was that whether having three functions void iterate_c(char *p) { /* body stays same */ } void iterate_i(int *p) { /* body stays same */ } void iterate_s(struct s *p) { /* body stays same */ } the pointer comparison (pp < p + 10) is legal in *all* of them. I have reservations because of the aforeposted excerpt from kazlib. -- rihad
|
Sun, 27 Jun 2004 00:16:43 GMT |
|
 |
riha #10 / 18
|
 pointer comparisons
Quote:
>Hi there, >1st question (easy) >can a char * reference the byte past the '\0' in a string?
After some thinking, I'm almost sure that it can, because a string can really look like "hello\0world\0!\0", with a total of four '\0''s. It all depends on how objects are laid out and undefined behaviour comes into play when you access memory not belonging to the C virtual machine. (thus, strlen((char *) 0xdeadbeef) is most likely undefined even if it's well defined for an OS (like its version string being there :)) Unless some part of a C object (of current program?) happens to live at 0xdeadbeef. -- rihad
|
Sun, 27 Jun 2004 00:37:07 GMT |
|
 |
karl malbra #11 / 18
|
 pointer comparisons
Quote:
> Hi there, > 1st question (easy) > can a char * reference the byte past the '\0' in a string?
No. Bytes past the '\0' are not defined for a string. karl m
|
Sun, 27 Jun 2004 03:19:13 GMT |
|
 |
Ben Pfaf #12 / 18
|
 pointer comparisons
Quote:
> > can a char * reference the byte past the '\0' in a string? > No. Bytes past the '\0' are not defined for a string. karl m
You are wrong as usual, Karl. A pointer to one-past-the-end is allowed for any object, and a string is no exception. Dereferencing such a one-past-the-end pointer is not allowed.
|
Sun, 27 Jun 2004 03:22:52 GMT |
|
 |
Tobias Oe #13 / 18
|
 pointer comparisons
Quote:
> On Tue, 8 Jan 2002 07:58:30 -0800, "Scott Fluhrer"
> <snipped> > Since you're yet another poster after Richard Bos who misunderstood > the point of anytype * and iterate, I really ought to rethink my > conversational skills :) Sorry :) > The point was that whether having three functions > void iterate_c(char *p) { /* body stays same */ } > void iterate_i(int *p) { /* body stays same */ } > void iterate_s(struct s *p) { /* body stays same */ }
The body was: { for (anytype *pp = p; pp < p + 10; pp++) use(pp); Quote: }
This is legal. The problem kaz lib tries to address is to figure out if pointer sometype *p points into sometype array[X]; One may be tempted to do if(p>=array && p<array+X){ /* p points into array */ Quote: }else{
/* p doesn't point into array */ Quote: }
But this is illegal because in order to compare pointers with <, <= etc they have to point to memory allocated for one and the same array in the first place. That's why kazlib iterates over the elements of the array and compares the pointer to each of these elements: int i,into; for(i=0,into=0;i<X && !into;tmp++) if(p==array+i) into=1; if(into){ /* p points into array */ Quote: }else{
/* p doesn't point into array */ Quote: }
Tobias.
|
Sun, 27 Jun 2004 03:49:18 GMT |
|
 |
Kaz Kylhe #14 / 18
|
 pointer comparisons
Quote:
>Hi there, >1st question (easy) >can a char * reference the byte past the '\0' in a string?
Yes. In C, a pointer which points to an array-like object can be incremented to point to one element index beyond the end of that object. That pointer is considered to point to the object for the purposes of being compared to other pointers which are based on the same array. That is to say, it's not wrong to use the relational operator to compare this pointer to other pointers into the same array. Only, it cannot be dereferenced to access anything. Quote: >2nd question (extra credit) >having the following semi-pseudo snippet: >char *c = malloc(10 * sizeof *c); >int *i = malloc(10 * sizeof *i); >struct s *s = malloc(10 * sizeof *s); >iterate(c); >iterate(i); >iterate(s); >void iterate(anytype *p) >{ > for (anytype *pp = p; pp < p + 10; pp++) > use(pp); >}
This is in fact a common C idiom, and it is probably the primary reason why pointer arithmetic is allowed to produce a pointer one past the end of an array. Without that provision, loop guards like pp < p + 10 would risk nonportability. If p + 10 were not required to be a valid pointer which compares greater than p or p + 9, the loop might not terminate. That could happen if, say, the dynamic object were allocated at the highest possible address in some memory segment, so that incrementing one byte past its end would cause the pointer to wrap around. The C standard prhohibits such a behavior; the implementation has to leave at least one byte of slack in such a situation. Quote: >I get the feeling that pointer comparison for at least one of the >three given anytype *'s is undefined, because here's what it says in >kazlib 1.20 (list.c:316):
That's a pretty roundabout way to learn obscure ANSI C facts, but I'm glad someone finds it educational. ;) Code has many uses; reading it, and even its comments, can be more interesting than actually running it.
|
Sun, 27 Jun 2004 04:37:12 GMT |
|
 |
CBFalcone #15 / 18
|
 pointer comparisons
Quote:
> 1st question (easy) > can a char * reference the byte past the '\0' in a string?
Of course. a string is just an array of char with a '\0' marker. Quote: > 2nd question (extra credit) > having the following semi-pseudo snippet: > char *c = malloc(10 * sizeof *c); > int *i = malloc(10 * sizeof *i); > struct s *s = malloc(10 * sizeof *s); > iterate(c); > iterate(i); > iterate(s); > void iterate(anytype *p) > { > for (anytype *pp = p; pp < p + 10; pp++) > use(pp); > }
Assuming suitable coding based on the above pseudo template, why not? You are never creating pointers outside the allocated range (+1), and never dereferencing any outside the range. It might be clearer with the exit condition written as "pp-p < 10". --
Available for consulting/temporary embedded and systems. (Remove "XXXX" from reply address. yahoo works unmodified)
|
Sun, 27 Jun 2004 08:08:44 GMT |
|
|
Page 1 of 2
|
[ 18 post ] |
|
Go to page:
[1]
[2] |
|