By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,148 Members | 1,339 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,148 IT Pros & Developers. It's quick & easy.

Another String reversal question

P: n/a
As if we needed another string reversal question.

I have a problem with the following code, that I believe should work.

int StringReverse(char* psz)
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}

Thing is, when it gets to the *p = *q line, I get an access violation.

Any ideas why, or what I can do to fix this?

Thanks,

Michael

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #1
Share this Question
Share on Google+
74 Replies


P: n/a
Michael wrote:
int StringReverse(char* psz)
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}

Thing is, when it gets to the *p = *q line, I get an access violation.


A strong indication that either the pointer value is wrong
or you use the function in an invalid way.
What did your debugger say?

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #2

P: n/a
Karl Heinz Buchegger wrote:
Michael wrote:

int StringReverse(char* psz)
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}

Thing is, when it gets to the *p = *q line, I get an access violation.

A strong indication that either the pointer value is wrong
or you use the function in an invalid way.
What did your debugger say?


The OP couldn't *possibly* done something like:

char * some_str = "reverse me";
int result = StringReverse(some_str);
...

Ya think? ;-)

--ag

--
Artie Gold -- Austin, Texas
Oh, for the good old days of regular old SPAM.

Jul 22 '05 #3

P: n/a
Artie Gold wrote:

Karl Heinz Buchegger wrote:
Michael wrote:

int StringReverse(char* psz)
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}

Thing is, when it gets to the *p = *q line, I get an access violation.

A strong indication that either the pointer value is wrong
or you use the function in an invalid way.
What did your debugger say?


The OP couldn't *possibly* done something like:

char * some_str = "reverse me";
int result = StringReverse(some_str);
...

Ya think? ;-)


Yep. Another possibility is that he feeds a bogous C-style string
to this function (one, which eg. has no terminating '\0')

The function has a bug (the subtraction of 1 is faulty), but
as long as he dosn't feed an empty char array to it, it should not crash.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #4

P: n/a
Karl Heinz Buchegger wrote:
Artie Gold wrote:
Karl Heinz Buchegger wrote:
Michael wrote:

int StringReverse(char* psz)
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}

Thing is, when it gets to the *p = *q line, I get an access violation.
A strong indication that either the pointer value is wrong
or you use the function in an invalid way.
What did your debugger say?

The OP couldn't *possibly* done something like:

char * some_str = "reverse me";
int result = StringReverse(some_str);
...

Ya think? ;-)

Yep. Another possibility is that he feeds a bogous C-style string
to this function (one, which eg. has no terminating '\0')


In which case it would likely die on the call to strlen().

The function has a bug (the subtraction of 1 is faulty), but
as long as he dosn't feed an empty char array to it, it should not crash.

Hmmm. The subtraction of 1 seems right to me.

But, indeed, an empty C-style string (i.e. *psz = '\0') would make the
pointers in the `while' condition incomparable.

Cheers,
--ag
--
Artie Gold -- Austin, Texas
Oh, for the good old days of regular old SPAM.

Jul 22 '05 #5

P: n/a
Michael wrote:
As if we needed another string reversal question.

I have a problem with the following code, that I believe should work.

int StringReverse(char* psz)
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}

Thing is, when it gets to the *p = *q line, I get an access violation.

Any ideas why, or what I can do to fix this?


The code seems reasonable to me, except that it has undefined
behaviour if you give it a zero-length string. I suspect that
you have mistakenly passed a string literal to it. String
literals are arrays of const char, even though they can be
converted to char *. An attempt to modify a string literal
has undefined behaviour.

As for zero-length strings, the problem is that if strlen(psz)
== 0 then the evaluation of q's initialiser has undefined
behaviour. You can avoid this by making q point to the byte
after the one to be swapped:

void StringReverse(char * psz)
{
char * p = psz;
char * q = psz + strlen(psz);
while (q - p >= 2)
{
--q;
char tmp = *p;
*p = *q;
*q = tmp;
++p;
}
}

Anyway, you don't need to write all that yourself; just use
std::reverse:

void StringReverse(char * psz)
{
std::reverse(psz, psz + strlen(psz));
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #6

P: n/a
Michael wrote:

As if we needed another string reversal question.

I have a problem with the following code, that I believe should work.

int StringReverse(char* psz)
{
Thing is, when it gets to the *p = *q line, I get an access violation.

Any ideas why, or what I can do to fix this?

Show us a complete program. I'll bet you are passing in a string
literal, which should not be modified.


Brian Rodenborn
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #7

P: n/a
Michael wrote:
As if we needed another string reversal question.
I have a problem with the following code, that I believe should work.
Thing is, when it gets to the *p = *q line, I get an access violation.
Any ideas why, or what I can do to fix this?


As a guess, you are calling it with a literal string.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #8

P: n/a
In article <1U******************@twister.austin.rr.com>, Michael
<mi*****@roleplaying.net> writes
As if we needed another string reversal question.

I have a problem with the following code, that I believe should work.

int StringReverse(char* psz)
what is the return value for? It communicates nothing.
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}

Thing is, when it gets to the *p = *q line, I get an access violation.

Any ideas why, or what I can do to fix this?


I will leave others to find the problem with your code, instead I will
deal with the problem of using the available tools:

inline void StringReverse(char* psz){
return std::reverse(psz, psz+strlen(psz));
}

should do what you want without making demands debugging re-invented
wheels. Much less typing, provides a method that can be used on all
sequence containers, and has less risk of logic errors.

And here is a complete program:

#include <algorithm>
#include <iostream>
#include <ostream>

inline void StringReverse(char* psz){
return std::reverse(psz, psz+strlen(psz));
}

int main(){
char s[]="This is a test";
StringReverse(s);
std::cout << s;
}

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #9

P: n/a
On 17 Dec 2003 14:20:40 -0500, there came a drop of sanity from
"Michael" <mi*****@roleplaying.net> containing:
As if we needed another string reversal question.
All though this is probably school work I'll try to fix it...

I have a problem with the following code, that I believe should work.

int StringReverse(char* psz)
Why do you return int here?
{
char *p = psz;
Why don't you use std::string?
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
Why don't you instead use std::swap here?
*p = *q;
*q = tmp;
p++;
q--;
Why don't you use pre incremental operators here?
}
return 1;
Once again, why do you return the integer here?
Return values are either to state some kind of "state" (C-style) or to
return some kind of result (C++-style).
The signature of your function should rather have been:
std::string StringReverse( const std::string & input )
Or at least "void StringReverse( char * psz )"

}

Thing is, when it gets to the *p = *q line, I get an access violation.
No idea why you get this, but I have some theories...
Se further down...

Any ideas why, or what I can do to fix this?
This is how I would have done it:

std::string StringReverse( const std::string & input )
{
std::string retVal;
for( std::string::const_iterator idx = input.end();
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
return retVal;
}

....or maybe even better...:
template<class T>
std::basic_string<T> StringReverse2( const std::basic_string<T>
& input )
{
typedef std::basic_string<T> myString;
myString retVal;
for( myString::const_iterator idx = input.end()-1;
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
retVal.push_back( *input.begin() );
return retVal;
}

....or the _completely_ generic way...:
template<class T>
T StringReverse2( typename T::const_iterator begin,
typename T::const_iterator end )
{
--end;
T retVal;
while( end != begin )
{
retVal.push_back( *end );
--end;
}
retVal.push_back( *end );
return retVal;
}

The last one works for both std::string, std::vector and std::list...!
But you need to explicitly define in the calling of it which class you
wish to use, e.g.:
"std::string x = StringReverse<std::string>( or.begin(), or.end() );"

If you are persistant on using c-strings (maybe you're a game
programmer) you can allways do it like this, but I would have choosen
ANY of the above solutions before I did it like this:

void StringReverse( char * input )
{
char * begin = input;
char * end = input+(strlen(input)-1);
while( begin < end )
{
char tmp = *end;
*end = *begin;
*begin = tmp;
++begin, --end;
}
}

Why your solution doesn't work I wouldn't know, but I tried it in
Visual Studio and I added up a "char * tmp = "Thomas Hansen";" line
and when I tried to reverse that line I got an "access violation".
This is probably since Visual Studio define that memory as "read only"
since it's statically linked into the process image...
Don't know if this is a bug or not....?
Why can't we do:

char * tmp = "Thomas Hansen";
StringReverse( tmp );

Anybody?!?
Suggestions?!?
Is it illegal?!?

Thanks,

Michael

--
http://smartwin.sourceforge.net THE template based Windows API GUI Library
My email:
"jo**********@theJohnsons.com"
* Replace "john" with "thomas", replace "johnson" with "hansen", replace "theJohnsons" with "adramatch"

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #10

P: n/a
Artie Gold wrote:
Yep. Another possibility is that he feeds a bogous C-style string
to this function (one, which eg. has no terminating '\0')
In which case it would likely die on the call to strlen().


Ah. right. That would not explain the access violation.

The function has a bug (the subtraction of 1 is faulty), but
as long as he dosn't feed an empty char array to it, it should not crash.
Hmmm. The subtraction of 1 seems right to me.


strlen returns the length without the terminating '\0'.
If he subtracts 1, then he will swap the first character
with the one-before-last character. If the goal
is to revert the string then I call this behaviour a bug.

But, indeed, an empty C-style string (i.e. *psz = '\0') would make the
pointers in the `while' condition incomparable.


The most plausible explanation is: He feed a string literal to this
function. That's why I asked for an example of how he is using it.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #11

P: n/a
Artie Gold <ar*******@austin.rr.com> wrote in message
news:<3F**************@austin.rr.com>...
Karl Heinz Buchegger wrote:
Artie Gold wrote:
Karl Heinz Buchegger wrote:
Michael wrote:int StringReverse(char* psz)
>{
> char *p = psz;
> char *q = psz + strlen(psz) - 1;
> while (p < q)
> {
> char tmp = *p;
> *p = *q;
> *q = tmp;
> p++;
> q--;
> }
> return 1;
>}Thing is, when it gets to the *p = *q line, I get an access violation. [...]The OP couldn't *possibly* done something like: char * some_str = "reverse me";
int result = StringReverse(some_str);
... Ya think? ;-)

That would be my guess as well.
Yep. Another possibility is that he feeds a bogous C-style string to
this function (one, which eg. has no terminating '\0')
In which case it would likely die on the call to strlen(). The function has a bug (the subtraction of 1 is faulty), but as long
as he dosn't feed an empty char array to it, it should not crash.

Hmmm. The subtraction of 1 seems right to me. But, indeed, an empty C-style string (i.e. *psz = '\0') would make the
pointers in the `while' condition incomparable.


If psz points to an empty string, then the second line will result in
undefined behavior, before even getting to the comparison in the while
(which is also undefined, of course).

I'm also surprised that no one mentioned the obvious solution in C++:

void
StringReverse( std::string& s )
{
std::reverse( s.begin(), s.end() ) ;
}

A bit simpler than his solution.

--
James Kanze GABI Software mailto:ka***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
Jul 22 '05 #12

P: n/a
In article <jo********************************@4ax.com>, Thomas Hansen
<sy****@yahoo.com> writes
char * tmp = "Thomas Hansen";
StringReverse( tmp );

Anybody?!?
Suggestions?!?
Is it illegal?!?


Yes, attempts to write to a string literal have been undefined behaviour
for a couple of decades. And as from 1996 the type of a string literal
in C++ has been 'array of const char'.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #13

P: n/a
Karl Heinz Buchegger wrote:
Artie Gold wrote:
[snip]

The function has a bug (the subtraction of 1 is faulty), but
as long as he dosn't feed an empty char array to it, it should not crash.


Hmmm. The subtraction of 1 seems right to me.

strlen returns the length without the terminating '\0'.
If he subtracts 1, then he will swap the first character
with the one-before-last character. If the goal
is to revert the string then I call this behaviour a bug.


Perhaps I'm dense today, but...

If strlen(some_string) is x, the last character is some_string[x - 1] or
some_string + x - 1, no?

[snip]

--ag

--
Artie Gold -- Austin, Texas
Oh, for the good old days of regular old SPAM.

Jul 22 '05 #14

P: n/a
On Thu, 18 Dec 2003 06:41:26 -0500, Thomas Hansen wrote:

[...]
void StringReverse( char * input )
{
char * begin = input;
char * end = input+(strlen(input)-1);
while( begin < end )
{
char tmp = *end;
*end = *begin;
*begin = tmp;
++begin, --end;
}
}

You would be better off using std::reverse. Also, if you are so concerned
about efficiency, then I guess this would perform badly compared to a
straight run reverse, because for decently long strings, the cache is
getting messed up, not once, but twice!
Why your solution doesn't work I wouldn't know, but I tried it in
Visual Studio and I added up a "char * tmp = "Thomas Hansen";" line
and when I tried to reverse that line I got an "access violation".
This is probably since Visual Studio define that memory as "read only"
since it's statically linked into the process image...
Don't know if this is a bug or not....?
Why can't we do:

char * tmp = "Thomas Hansen";
StringReverse( tmp );

Anybody?!?
Suggestions?!?
Is it illegal?!?


Your compiler might put the string literal "..." in some sort of read-only
memory, or rather in the code segment of the program, so trying to assign
to memory there is seg-faultable... So much for self modifying code!
Regards,
-Dhruv.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #15

P: n/a
On 18 Dec 2003 06:41:26 -0500, Thomas Hansen <sy****@yahoo.com> wrote:

...or maybe even better...:
template<class T>
std::basic_string<T> StringReverse2( const std::basic_string<T>
& input )
{
typedef std::basic_string<T> myString;
myString retVal;
for( myString::const_iterator idx = input.end()-1;
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
retVal.push_back( *input.begin() );
return retVal;
}


Is this variant better?
(works with any traits/allocators or other
implementation of string that do not use them)

template<class String>
String StringReverse2( const String & input )
{
String retVal;
for( String::const_iterator idx = input.end()-1;
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
retVal.push_back( *input.begin() );
return retVal;
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #16

P: n/a
Thomas Hansen wrote:
std::string retVal;
for( std::string::const_iterator idx = input.end();
idx != input.begin();
--idx )
{
retVal.push_back( *idx );


*KABOOM!*
The first iteration dereferences input.end(), which isn't dereferencable.

Wasn't there something like std::reverse()? Even if not, one could use
reverse_iterators.... it's all so easy! ;)

Uli
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #17

P: n/a
"Ben Hutchings" <do**************@bwsint.com> wrote in message
news:sl****************************@tin.bwsint.com ...
Michael wrote:
> As if we needed another string reversal question.
>
> I have a problem with the following code, that I believe should work.
>
> int StringReverse(char* psz)
> {
> char *p = psz;
> char *q = psz + strlen(psz) - 1;
> while (p < q)
> {
> char tmp = *p;
> *p = *q;
> *q = tmp;
> p++;
> q--;
> }
> return 1;
>
> }
>
> Thing is, when it gets to the *p = *q line, I get an access violation.
>
> Any ideas why, or what I can do to fix this?
[snip] As for zero-length strings, the problem is that if strlen(psz)
== 0 then the evaluation of q's initialiser has undefined
behaviour.


Does it? If strlen(psz)==0 then q==psz+0-1 and so q==psz-1. q is not a
pointer to a valid object, but it's never going to get dereferenced since
!p<q. That makes it a singular pointer, no? I think that's the term.

I suppose the question I'm asking is, does pointer arithmetic which gives
rise to a singular pointer constitute undefined behaviour? I know you're
allowed to produce a pointer which is one beyond the end of an array, even
though you're not allowed to dereference it. But is it wrong to produce any
other kind of pointer that isn't to a valid object?

George

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #18

P: n/a
On 18 Dec 2003 06:41:26 -0500, Thomas Hansen <sy****@yahoo.com> wrote:
This is how I would have done it: std::string StringReverse( const std::string & input )
{
std::string retVal;
for( std::string::const_iterator idx = input.end();
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
return retVal;
}
Which shows that the problem is just too difficult for the average
programmer. The first thing you do is dereference end(). Try
this test to either get a fault or unexpected results.

cout << StringReverse("Hello") << " "
<< StringReverse("World").c_str() << "\n";
...or maybe even better...:
template<class T>
std::basic_string<T> StringReverse2( const std::basic_string<T>
& input )
{
typedef std::basic_string<T> myString;
myString retVal;
for( myString::const_iterator idx = input.end()-1;
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
retVal.push_back( *input.begin() );
return retVal;
}
This is much better, it fails to compile and can do no damage. Should
you decide to fix that, test it with

cout << StringReverse2(string()) << "\n";
...or the _completely_ generic way...:
[snip]

Also dereferences end.
void StringReverse( char * input )
{
char * begin = input;
char * end = input+(strlen(input)-1);
Undefined behavior for an empty string just like the original.
while( begin < end )
{
char tmp = *end;
*end = *begin;
*begin = tmp;
++begin, --end;
}
}
Running pointers and iterators backwards is not for the novice.
Use subscripts.
Why your solution doesn't work I wouldn't know, but I tried it in
Visual Studio and I added up a "char * tmp = "Thomas Hansen";" line
and when I tried to reverse that line I got an "access violation".
This is probably since Visual Studio define that memory as "read only"
since it's statically linked into the process image...
Don't know if this is a bug or not....?
In your code, yes. In the compiler, no.
Why can't we do: char * tmp = "Thomas Hansen";
Because that litteral string is constant. For histerical reasons, you
can get a non-const pointer to it, but you can not modify it. You need
an array.

char tmp[] = "Thomas Hansen";
StringReverse( tmp );


Now just forget about that hard to write function and use the one in the
library.

std::reverse(tmp, tmp + sizeof(tmp) - 1);

We do not want the null terminator on the front.

Since you seem to want to produce a reversed copy, we also have

char const* tmp = "Thomas Hansen";
*std::reverse_copy(tmp, tmp + strlen(tmp),
ostream_iterator<char>(cout)) = '\n';

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #19

P: n/a
"Thomas Hansen" <sy****@yahoo.com> wrote in message
"Michael" <mi*****@roleplaying.net> containing: std::string StringReverse( const std::string & input )
{
std::string retVal;
for( std::string::const_iterator idx = input.end();
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
return retVal;
}
The original problem appears to be to reverse a char[] array in place. Your
solution employs additional memory.

Also, it's still in error. The expression *string.end() is an access
violation. Use reverse iterators.

for( std::string::const_reverse_iterator idx = input.rbegin();
idx != input.rend();
++idx )
{
retVal.push_back( *idx );
}

Or even better

std::copy(input.rbegin(), input.rend(), std::back_inserter(retVal));

Or just try std::reserve.

Also, since we know the final length of retVal, we can optimize by calling
reserve.

std::string retVal;
retVal.reserve(input.size());

But the above does not generalize to generic containers (as you try to do
later) as only vector and string have the function reserve.

template<class T>
T StringReverse2( typename T::const_iterator begin,
typename T::const_iterator end )
For these sorts of generic functions consider the example of std::transform
and the like

template<class InputIter, class OutputIter>
OutputIter Reverse(InputIter begin, InputIter end, OutputIter output);

Why your solution doesn't work I wouldn't know, but I tried it in
Visual Studio and I added up a "char * tmp = "Thomas Hansen";" line
and when I tried to reverse that line I got an "access violation".
This is probably since Visual Studio define that memory as "read only"
since it's statically linked into the process image...
Don't know if this is a bug or not....?


It's a feature.

--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #20

P: n/a
"Michael" <mi*****@roleplaying.net> wrote in message news:1UZDb.135726
int StringReverse(char* psz)
{
char *p = psz;
char *q = psz + strlen(psz) - 1;
while (p < q)
{
char tmp = *p;
*p = *q;
*q = tmp;
p++;
q--;
}
return 1;

}


Others have good answers. Just one other unrelated thing. For functions
returning an integer, return of zero means no error, and return of any other
number (positive or negative) means error. Are you sure you want to return
1?

--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #21

P: n/a
On 18 Dec 2003 18:52:22 -0500, Marco Oman <ni**************@libero.it>
wrote:
Is this variant better?
(works with any traits/allocators or other
implementation of string that do not use them) template<class String>
String StringReverse2( const String & input )
{
String retVal;
for( String::const_iterator idx = input.end()-1;
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
retVal.push_back( *input.begin() );
return retVal;
}


It crashes on an empty string. Correctness is required before we
can talk about other things.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #22

P: n/a
On 18 Dec 2003 21:47:37 -0500, "George van den Driessche"
<no****@nowhere.com> wrote:
Does it? If strlen(psz)==0 then q==psz+0-1 and so q==psz-1. q is not a
pointer to a valid object, but it's never going to get dereferenced since
!p<q. That makes it a singular pointer, no? I think that's the term.
No. A singular pointer is not initialized. It is also invalid to look
at the singular value. A past-the-end or null pointer is not
dereferenceable but it is valid to look at the value.

int* p;
if (p) // undefined behavior.

int x;
int* p(&x);
p + 1; // one past the end of the int x is valid
p + 2; // undefined behavior for just trying to compute it
p - 1; // same thing
p = new int;
delete p;
if (p) // undefined behavior
I suppose the question I'm asking is, does pointer arithmetic which gives
rise to a singular pointer constitute undefined behaviour?


Yes.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #23

P: n/a
Artie Gold <ar*******@austin.rr.com> wrote in message
news:<3F**************@austin.rr.com>...
Karl Heinz Buchegger wrote:
Artie Gold wrote:
[snip]
The function has a bug (the subtraction of 1 is faulty), but as
long as he dosn't feed an empty char array to it, it should not
crash. Hmmm. The subtraction of 1 seems right to me.
strlen returns the length without the terminating '\0'. If he
subtracts 1, then he will swap the first character with the
one-before-last character. If the goal is to revert the string then
I call this behaviour a bug.

Perhaps I'm dense today, but... If strlen(some_string) is x, the last character is some_string[x - 1]
or some_string + x - 1, no?


And if strlen( someString ) is 0, there is no last character, and the
expression someString + strlen( someString ) - 1 is someString - 1,
which is undefined behavior.

--
James Kanze GABI Software mailto:ka***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
Jul 22 '05 #24

P: n/a
In message
<tl**********************@bgtnsc05-news.ops.worldnet.att.net>, Siemel
Naran <Si*********@REMOVE.att.net> writes
Others have good answers. Just one other unrelated thing. For functions
returning an integer, return of zero means no error, and return of any other
number (positive or negative) means error. Are you sure you want to return
1?


I am unconvinced of this. Where a function's return will simply denote
whether it succeeded or not a C++ programmer would use bool and a pre
C99 C programmer would use 1 for true and 0 for false (which neatly maps
to the conversions of true and false values of bool).

However the catch is that when a return value does not denote simple
success/failure but is returning an error code, 0 is used for no errors
and other values are used to distinguish the different modes of failure.

A user needs to know which convention is in operation if they are using
such functions. This is a case where understanding of the issues and the
chosen solutions is essential.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #25

P: n/a
Francis Glassborow <fr*****@robinton.demon.co.uk> wrote in message
news:<Z0**************@robinton.demon.co.uk>...
In article <jo********************************@4ax.com>, Thomas Hansen
<sy****@yahoo.com> writes
char * tmp = "Thomas Hansen";
StringReverse( tmp ); Anybody?!?
Suggestions?!?
Is it illegal?!?
Yes, attempts to write to a string literal have been undefined
behaviour for a couple of decades. And as from 1996 the type of a
string literal in C++ has been 'array of const char'.


Just a nit, but a couple of decades would be 2 or more -- more than 20
years. In fact, writing to a string literal was legal and had well
defined semantics in K&R 1, and only became illegal with the C standard,
in 1989. Almost a decade and a half, but not quite a couple of decades.

But as a I said, it's a nit -- even 15 years is long enough for people
not to have leared what was always a bad programming technique.

--
James Kanze GABI Software mailto:ka***@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #26

P: n/a
ka***@gabi-soft.fr wrote:
Artie Gold <ar*******@austin.rr.com> wrote in message
news:<3F**************@austin.rr.com>...
Karl Heinz Buchegger wrote:
Artie Gold wrote:

[snip]


>The function has a bug (the subtraction of 1 is faulty), but as
>long as he dosn't feed an empty char array to it, it should not
>crash.
Hmmm. The subtraction of 1 seems right to me.
strlen returns the length without the terminating '\0'. If he
subtracts 1, then he will swap the first character with the
one-before-last character. If the goal is to revert the string then
I call this behaviour a bug.

Perhaps I'm dense today, but...


If strlen(some_string) is x, the last character is some_string[x - 1]
or some_string + x - 1, no?

And if strlen( someString ) is 0, there is no last character, and the
expression someString + strlen( someString ) - 1 is someString - 1,
which is undefined behavior.

Of course. But that issue has been hammered out elsethread. ;-)

Cheers,
--ag

--
Artie Gold -- Austin, Texas
Oh, for the good old days of regular old SPAM.

Jul 22 '05 #27

P: n/a
Artie Gold wrote:

Karl Heinz Buchegger wrote:
Artie Gold wrote:

[snip]
The function has a bug (the subtraction of 1 is faulty), but
as long as he dosn't feed an empty char array to it, it should not crash.
Hmmm. The subtraction of 1 seems right to me.

strlen returns the length without the terminating '\0'.
If he subtracts 1, then he will swap the first character
with the one-before-last character. If the goal
is to revert the string then I call this behaviour a bug.


Perhaps I'm dense today, but...


No. It's me.
Damned counting.
I knew that climbing down from the trees was a failure :-)

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #28

P: n/a
On 19 Dec 2003 02:40:03 -0500, there came a drop of sanity from John
Potter <jp*****@falcon.lhup.edu> containing:
On 18 Dec 2003 06:41:26 -0500, Thomas Hansen <sy****@yahoo.com> wrote:
This is how I would have done it:

std::string StringReverse( const std::string & input )
{
std::string retVal;
for( std::string::const_iterator idx = input.end();
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
return retVal;
}


Which shows that the problem is just too difficult for the average
programmer. The first thing you do is dereference end(). Try
this test to either get a fault or unexpected results.

If you look at one of the function examples just above you would have
seen that I did it like this in at least one of the functions...

for( myString::const_iterator idx = input.end()-1;

....but I should have tested more thourough before posting...
[snip]

--
http://smartwin.sourceforge.net THE template based Windows API GUI Library
My email:
"jo**********@theJohnsons.com"
* Replace "john" with "thomas", replace "johnson" with "hansen", replace "theJohnsons" with "adramatch"

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #29

P: n/a
"Francis Glassborow" <fr*****@robinton.demon.co.uk> wrote in message
news:KnUDPDBXCr4
Naran <Si*********@REMOVE.att.net> writes
Others have good answers. Just one other unrelated thing. For functions
returning an integer, return of zero means no error, and return of any othernumber (positive or negative) means error. Are you sure you want to return1?


I should have said zero usually means no error.
I am unconvinced of this. Where a function's return will simply denote
whether it succeeded or not a C++ programmer would use bool and a pre
C99 C programmer would use 1 for true and 0 for false (which neatly maps
to the conversions of true and false values of bool).
Yes, for functions returning bool the convention is true means success (and
true maps to a non-zero integer). And third, functions could throw to
signify an error. For functions returning int the convention is zero means
success.
However the catch is that when a return value does not denote simple
success/failure but is returning an error code, 0 is used for no errors
and other values are used to distinguish the different modes of failure.

A user needs to know which convention is in operation if they are using
such functions. This is a case where understanding of the issues and the
chosen solutions is essential.


--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #30

P: n/a
"John Potter" <jp*****@falcon.lhup.edu> wrote in message
On 18 Dec 2003 21:47:37 -0500, "George van den Driessche" int x;
int* p(&x);
p + 1; // one past the end of the int x is valid
Fine.
p + 2; // undefined behavior for just trying to compute it
p - 1; // same thing


Fine, but what could possibly go wrong. My compilers don't complain or
crash (ie. they do the right thing). But I guess other platforms could mess
up?

--
+++++++++++
Siemel Naran

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #31

P: n/a
On 19 Dec 2003 13:46:21 -0500, Thomas Hansen <sy****@yahoo.com> wrote:
On 19 Dec 2003 02:40:03 -0500, there came a drop of sanity from John
Potter <jp*****@falcon.lhup.edu> containing:
On 18 Dec 2003 06:41:26 -0500, Thomas Hansen <sy****@yahoo.com> wrote:
This is how I would have done it: std::string StringReverse( const std::string & input )
{
std::string retVal;
for( std::string::const_iterator idx = input.end();
idx != input.begin();
--idx )
{
retVal.push_back( *idx );
}
return retVal;
}
Which shows that the problem is just too difficult for the average
programmer. The first thing you do is dereference end(). Try
this test to either get a fault or unexpected results.

If you look at one of the function examples just above
There is no code above that which was written by you. If you look at
the rest of my post, you will find that everything you wrote is
defective.
you would have
seen that I did it like this in at least one of the functions... for( myString::const_iterator idx = input.end()-1;


Which decrements begin when the string is empty. Which undefined
behavior do you prefer?

Running loops backwards with subscripts is fairly easy, with
pointers/iterators is fairly hard. The library has reverse_iterators
because getting it right is non-trivial. It also has algorithms because
over 80% of non-counting loops written are defective. That includes
those published in textbooks. I always assume that my first attempt is
likely wrong. It is a rare pleasure when that assumption is wrong.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #32

P: n/a
In message
<7v***********************@bgtnsc04-news.ops.worldnet.att.net>, Siemel
Naran <Si*********@REMOVE.att.net> writes
"John Potter" <jp*****@falcon.lhup.edu> wrote in message
On 18 Dec 2003 21:47:37 -0500, "George van den Driessche"

int x;
int* p(&x);
p + 1; // one past the end of the int x is valid


Fine.
p + 2; // undefined behavior for just trying to compute it
p - 1; // same thing


Fine, but what could possibly go wrong. My compilers don't complain or
crash (ie. they do the right thing). But I guess other platforms could mess
up?

UB is generally an issue for the executable not for the compiler. That
is the point, the compiler is required to accept the code unless it can
demonstrate that it will always fail and that the code will always be
executed (rather hard unless it is working as an interpreter)

When we come to execution time either p-1 or p+2 maybe pointer into
memory that does not belong to the process, and the consequences can be
anything (on protected memory systems it usually results in the process
being aborted). If you look as if you are about to touch memory you do
not own then the OS is entitled to do whatever it wants -- but that
action is outside the domain of the C++ Standard and so is undefined (by
C++)
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #33

P: n/a
In message
<6v***********************@bgtnsc04-news.ops.worldnet.att.net>, Siemel
Naran <Si*********@REMOVE.att.net> writes
Yes, for functions returning bool the convention is true means success (and
true maps to a non-zero integer). And third, functions could throw to
signify an error. For functions returning int the convention is zero means
success.


I think that I probably have an unusually extensive reading of relevant
literature but cannot recall any such statement being made by good, bad
or indifferent authors. Perhaps you could jog my memory with a few
references.

While I would give 'use bool to report success/failure' as a very strong
guideline, it is not an option when writing code that needs to be
compatible to all versions of C and to C++ so I continue to have strong
doubts that any convention such as the one you claim exists in the wider
C & C++ programming community.

Note that zero denotes success for return from main, and it also does so
for comparison functions passed to qsort and bsearch but it does not do
so for comparison functions passed to the various C++ sort and search
functions.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #34

P: n/a
Siemel Naran wrote:
"John Potter" <jp*****@falcon.lhup.edu> wrote in message
> On 18 Dec 2003 21:47:37 -0500, "George van den Driessche"
> int x;
> int* p(&x);
> p + 1; // one past the end of the int x is valid
John,

What do you mean "one past the end of the int x?" Are you sure that's
valid? I know the address marking the end of an array is always valid...
> p + 2; // undefined behavior for just trying to compute it
> p - 1; // same thing


Fine, but what could possibly go wrong. My compilers don't complain or
crash (ie. they do the right thing).


Siemel,

That's not necessarily the right thing, even if it is what you expect.
But I guess other platforms could mess up?


No, the platform isn't messing up, you are. There may not be any
address with value p + 2. The very act of computing it could cause a
bus error.

The address you're computing probably is valid most of the time.
However, this is not a good habit to develop. The fact that it has not
been a problem for you yet does not mean it won't be.

-Jeff
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #35

P: n/a
On Fri, 19 Dec 2003 02:53:41 -0500, John Potter wrote:
int x;
int* p(&x);
p + 1; // one past the end of the int x is valid
p + 2; // undefined behavior for just trying to compute it
In particular, what's wrong with computing p+2? What's the rationale
behind not allowing it?
p - 1; // same thing
p = new int;
delete p;
if (p) // undefined behavior


Same thing? AFAIK, delete is not allowed to mofdify the pointer passed to
it, so just accessing the value stored in the pointer should not be a
problem? Or is my thinking orthogonal to the standard?
Regards,
-Dhruv.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #36

P: n/a
On 20 Dec 2003 10:08:40 -0500, Francis Glassborow
<fr*****@robinton.demon.co.uk> wrote:
In message
<7v***********************@bgtnsc04-news.ops.worldnet.att.net>, Siemel
Naran <Si*********@REMOVE.att.net> writes
"John Potter" <jp*****@falcon.lhup.edu> wrote in message
On 18 Dec 2003 21:47:37 -0500, "George van den Driessche" int x;
int* p(&x);
p + 1; // one past the end of the int x is valid
Fine. p + 2; // undefined behavior for just trying to compute it
p - 1; // same thing
Fine, but what could possibly go wrong. My compilers don't complain or
crash (ie. they do the right thing). But I guess other platforms could mess
up?

UB is generally an issue for the executable not for the compiler. That
is the point, the compiler is required to accept the code unless it can
demonstrate that it will always fail and that the code will always be
executed (rather hard unless it is working as an interpreter) When we come to execution time either p-1 or p+2 maybe pointer into
memory that does not belong to the process, and the consequences can be
anything (on protected memory systems it usually results in the process
being aborted). If you look as if you are about to touch memory you do
not own then the OS is entitled to do whatever it wants -- but that
action is outside the domain of the C++ Standard and so is undefined (by
C++)


Which also allows the compiler to insert code which runs nethack if
executed. Fat pointers can hold base and bound values to allow
checking of all pointer arithmetic.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #37

P: n/a
In message <pa****************************@gmx.net>, Dhruv
<dh*******@gmx.net> writes
Same thing? AFAIK, delete is not allowed to mofdify the pointer passed to
it, so just accessing the value stored in the pointer should not be a
problem? Or is my thinking orthogonal to the standard?
I do not think you are thinking clearly about what happens on hardware
that has address registers, and particularly with oSs that do proper
memory management.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #38

P: n/a
On 20 Dec 2003 12:40:47 -0500, Jeff Schwab <je******@comcast.net> wrote:
"John Potter" <jp*****@falcon.lhup.edu> wrote in message
> int x;
> int* p(&x);
> p + 1; // one past the end of the int x is valid
What do you mean "one past the end of the int x?" Are you sure that's
valid?


Yes.

| 5.7/4 For the purposes of these operators, a pointer to a
| non-array object behaves the same as a pointer to the first element of
| an array of length one with the type of the object as its element type.

It is always valid to add one to a dereferencable pointer value.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #39

P: n/a
On 20 Dec 2003 12:45:05 -0500, "Dhruv" <dh*******@gmx.net> wrote:
On Fri, 19 Dec 2003 02:53:41 -0500, John Potter wrote:
int x;
int* p(&x);
p + 1; // one past the end of the int x is valid
p + 2; // undefined behavior for just trying to compute it In particular, what's wrong with computing p+2? What's the rationale
behind not allowing it?
I don't think C++ is rational. There is no rationale. :)
p - 1; // same thing
p = new int;
delete p;
if (p) // undefined behavior

Same thing? AFAIK, delete is not allowed to mofdify the pointer passed to
it, so just accessing the value stored in the pointer should not be a
problem? Or is my thinking orthogonal to the standard?


I think you are confusing operator delete with the delete expression.
The delete expression does anything the compiler generates including
assigning an invalid value to the pointer or adding the value of the
pointer expression to a list of addresses which cause email to your
boss in a program that produces that rvalue.

See 5.3.5/4. The delete expresion invalidates the pointer. The only
thing that may be done with a pointer holding an invalid value is to
assign a new value. You are not allowed to look at the old value.

John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #40

P: n/a
"Francis Glassborow" <fr*****@robinton.demon.co.uk> wrote in message
news:7vGPtvBZ4D5
<6v***********************@bgtnsc04-news.ops.worldnet.att.net>, Siemel

Yes, for functions returning bool the convention is true means success (andtrue maps to a non-zero integer). And third, functions could throw to
signify an error. For functions returning int the convention is zero meanssuccess.


I think that I probably have an unusually extensive reading of relevant
literature but cannot recall any such statement being made by good, bad
or indifferent authors. Perhaps you could jog my memory with a few
references.

While I would give 'use bool to report success/failure' as a very strong
guideline, it is not an option when writing code that needs to be
compatible to all versions of C and to C++ so I continue to have strong
doubts that any convention such as the one you claim exists in the wider
C & C++ programming community.

Note that zero denotes success for return from main, and it also does so
for comparison functions passed to qsort and bsearch but it does not do
so for comparison functions passed to the various C++ sort and search
functions.


For the record, that convention is something I came up, and a few people
use. But I don't think anyone read throughout the land has said anything
like it.

--
+++++++++++
Siemel Naran
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #41

P: n/a
On Sat, 20 Dec 2003 15:58:39 -0500, Francis Glassborow wrote:
In message <pa****************************@gmx.net>, Dhruv
<dh*******@gmx.net> writes
Same thing? AFAIK, delete is not allowed to mofdify the pointer passed to
it, so just accessing the value stored in the pointer should not be a
problem? Or is my thinking orthogonal to the standard?


I do not think you are thinking clearly about what happens on hardware
that has address registers, and particularly with oSs that do proper
memory management.


I do not know what address registers are. The only hardware that I'm
partially familiar with is the current x386 and pentium architecture, so
whatever I think is in terms of that hardware. It would be nice if you
could explain what happens on architectures with 'address registers', and
what they actually are?

Regards,
-Dhruv.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #42

P: n/a
In message <pa***************************@gmx.net>, Dhruv
<dh*******@gmx.net> writes
I do not know what address registers are. The only hardware that I'm
partially familiar with is the current x386 and pentium architecture, so
whatever I think is in terms of that hardware. It would be nice if you
could explain what happens on architectures with 'address registers', and
what they actually are?


This is not the place for a lesson on hardware architecture. However
even the most elementary experience of X86 architectures requires some
knowledge that the standard register set include various special purpose
registers (SI, DI, SP and BP are examples that I recall from the days
when I had to dabble at that low a level). However the important issue
is that protected memory systems check values that purport to be
addresses and take action if the value is not available to the process.
Doing anything that uses an invalid pointer value (i.e. rvalue or
address in this context) is outside the domain of the C++ Standard and
so is undefined by the Standard.

The point at issue is that address registers in a protected memory
system are sometimes designed to trap when an out of range value is
loaded into them and there is nothing that a C++ programmer can do in
such circumstances.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #43

P: n/a
In message
<TF***********************@bgtnsc04-news.ops.worldnet.att.net>, Siemel
Naran <Si*********@REMOVE.att.net> writes
For the record, that convention is something I came up, and a few people
use. But I don't think anyone read throughout the land has said anything
like it.


Oh you mean "Siemel Naran's" convention. That is very different from
'the convention' which would claim some for of general acceptance. In
addition treating personal coding conventions as if they were universal
is very dangerous particularly when that information is handed out to
the inexperienced.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #44

P: n/a
dh*******@gmx.net (Dhruv) wrote (abridged):
int x;
int* p(&x);
p + 1; // one past the end of the int x is valid
p + 2; // undefined behavior for just trying to compute it
In particular, what's wrong with computing p+2? What's the rationale
behind not allowing it?


p+1 is allowed because x is treated as an array of length 1, and p+1
is the one-past-the-end value, which is fine. p+2 is not fine. It may
point to memory which is not owned by the program, and C++ is allowed
to trap as soon as such an address is evaluated.

AFAIK, delete is not allowed to mofdify the pointer passed to it,
so just accessing the value stored in the pointer should not be a
problem?


Even if p has the same bit pattern, the memory which that bit pattern
refers to no longer belongs to the program. So again C++ is allowed
to trap on load.

-- Dave Harris, Nottingham, UK

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #45

P: n/a
[mod note: setting your newsreader to post with a width of less than 80 columns
will avoid this type of formatting problem.]

"Dhruv" <dh*******@gmx.net> wrote in message
news:pa***************************@gmx.net...
It would be nice if you
could explain what happens on architectures with 'address registers', and
what they actually are?


This whole "one-past-the-end" issue came from a very real environment that
was in popular
use at the time the C standard was originally being hammered out. It was
the 80x86 segmented
(pre-386) architectures. While there were others as well, like your
beloved Pentium, it was
very popular in it's day. The issue was that these architectures could
only index 16-bits worth
of address space at a time, a separate register held the rest of the
address. Without specifically
mandating the one-past-the-end guarantees, it was quite possible that an
object/array could be
placed at the end of a 64K segment. The one past the end address could
roll over to be have
a value LESS than an address inside the array (if the behavior was left
undefined as other outside
the bounds of arrays are even today).

Maybe you can assume a flat address space today, but who knows what the
future will bring.
Perhaps some day we'll end up with huge cross-network addresses (such an
architecture
did exist in the past: the Apollo Domain). It may be once again
advantageous to work with
local pointers that are subsets of the global address space, and the
one-past-the-end guarantee
will need come into play again.

Another issue is while by and large most architectures only trap invalid
acesses when you actually
read or write through pointers to invalid memory, nothing precludes a
machine from trapping when
you manipulate an invalid pointer value. Again you will need the
one-past-the-end guarantee.
This might happen someday when security and reliability become more
important that the current
cavalier Microsoft-induced attitude.

Believe me, it can happen and be best to make your application clean against
reliance on undefined
behavior. Lots of heartburn when apps were ported to the first 64 bit
architectures in common use
in micros (Alpha) because people assumed a things like the size of pointers
and the various other
types. We also had fun because while most machines trap only computations
involving invalid
floating point numbers, the Alpha (which was fine by the language) trapped
even loading invalid
floats into the fp registers. Our bad for assuming we could put (possibly)
garbage values into
float variables. We had to clean that up.

-Ron

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #46

P: n/a
On Sun, 21 Dec 2003 06:40:17 -0500, John Potter wrote:

[...]
> In particular, what's wrong with computing p+2? What's the rationale
> behind not allowing it?
I don't think C++ is rational. There is no rationale. :)


There goes the standard ;-)

[...]
I think you are confusing operator delete with the delete expression.
The delete expression does anything the compiler generates including
assigning an invalid value to the pointer or adding the value of the
pointer expression to a list of addresses which cause email to your
boss in a program that produces that rvalue.

See 5.3.5/4. The delete expresion invalidates the pointer. The only
thing that may be done with a pointer holding an invalid value is to
assign a new value. You are not allowed to look at the old value.


So, how would you account for something like this:

delete ((int*)0); ?

Regards,
-Dhruv.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #47

P: n/a
John Potter wrote:
On 20 Dec 2003 12:40:47 -0500, Jeff Schwab <je******@comcast.net> wrote:
> > "John Potter" <jp*****@falcon.lhup.edu> wrote in message > > > int x;
> > > int* p(&x);
> > > p + 1; // one past the end of the int x is valid

> What do you mean "one past the end of the int x?" Are you sure that's
> valid?


Yes.

| 5.7/4 For the purposes of these operators, a pointer to a
| non-array object behaves the same as a pointer to the first element of
| an array of length one with the type of the object as its element type.

It is always valid to add one to a dereferencable pointer value.

John

Sweet!!! I guess this implies that algorithms meant to work on
collections actually can work on individual elements just as easily.
Good to know.

#include <iostream>
#include <cctype>

int main( )
{
char const* s = "a";
char const c = 'a';

std::cout << std::equal( s, s + 1, &c ) << '\n';
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #48

P: n/a
In message <pa***************************@gmx.net>, Dhruv
<dh*******@gmx.net> writes
So, how would you account for something like this:

delete ((int*)0); ?


Your point being? Because that is actually pointless code ((int*)0) is a
null pointer (guaranteed to be a valid pointer value) and C++ guarantees
that supplying that in a delete expression results in nothing happening.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
or http://www.robinton.demon.co.uk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #49

P: n/a
On Sun, 21 Dec 2003 20:16:48 -0500, Francis Glassborow wrote:
In message <pa***************************@gmx.net>, Dhruv
<dh*******@gmx.net> writes
So, how would you account for something like this:

delete ((int*)0); ?


Your point being? Because that is actually pointless code ((int*)0) is a
null pointer (guaranteed to be a valid pointer value) and C++ guarantees
that supplying that in a delete expression results in nothing happening.


ok, no because as John Potter mentioned that the delete expression is
allowed to modify the pointer passed to it, so I was just wondering how it
would modify a constant passed to it. But now that you've mentioned that
C++ guarantees a Null operation, there's nothing wrong with it.

Regards,
-Dhruv.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jul 22 '05 #50

74 Replies

This discussion thread is closed

Replies have been disabled for this discussion.