469,360 Members | 1,782 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,360 developers. It's quick & easy.

Highly efficient string reversal code

Hello, I'm a highly experienced expert C programmer and I've written
this code to reverse a string in place. I think you could all learn
something from it!

int reverse(char* reverseme){
int retval=-1;
if(retval!=NULL){
int len=strlen(retval){
if(len>0){
int half=len>>1;
for(;retval<half;retval++){
reverseme[retval]^=reverseme[len-(retval+1)];
reverseme[len-(retval+1)]=reverseme[retval];
reverseme[retval]^=reverseme[len-(retval+1)];
}
}
}
return retval;
}

-Phil/CERisE
Sep 22 '08
144 4130
My contribution to the cause

char *reverse(char *str)
{
char *start, *end, temp;

for (end=str;*end;++end);
--end; /* A */

for (start=str; start < end; ++start, --end) /* B */
{
temp = *start;
*start = *end;
*end = temp;
}
return str;
}

NB: For the degenerate case of a zero-length string, the computation of the
end character ( /* A */ ) produces a pointer that, *if dereferenced* would
encounter UB because it points out-of-bounds to the intended array.
*However*, the reversal loop ( /* B */ ) tests the value of this pointer
(without dereferencing it), and will discontinue the loop immediately
(again, without dereferencing the pointer).

--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
Sep 24 '08 #101

"oksid" <ok***@bluewin.chwrote in message
news:be***************************@news.hispeed.ch ...
Bartc wrote:
>>
"Ben Bacarisse" <be********@bsb.me.ukwrote in message
news:87************@bsb.me.uk...
>>"Malcolm McLean" <re*******@btinternet.comwrites:

"Ben Bacarisse" <be********@bsb.me.ukwrote in message
void reverse(char *str)
{
char temp;
int start = 0;
int end = strlen(str) - 1;
while(start < end)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
}

Of course strlen() returns a size_t. So we'll replace those ints with
size_t's. What horrible thing have I now done to this function?

I don't get your point. You know the above is wrong and that
switching to size_ t does not make it right, so what are you driving
at?

What's wrong about it? It works fine, provided str points to a valid
string.

If "str" points to an empty string "strlen()" will return 0...
"end" will be equal to -1 or 0xFFFFFFFF
So? In that case start<end will be false, and the loop isn't executed.

Unless you're saying int can be unsigned? That would be news to me.

How can anyone write any sort of portable, reliable code when you don't even
know whether 'int' is signed or unsigned.

--
Bartc

Sep 24 '08 #102
"Bartc" <bc@freeuk.comwrites:
"Ben Bacarisse" <be********@bsb.me.ukwrote in message
news:87************@bsb.me.uk...
>"Malcolm McLean" <re*******@btinternet.comwrites:
<snip>
>>void reverse(char *str)
{
char temp;
int start = 0;
int end = strlen(str) - 1;
while(start < end)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
start++;
end--;
}
}

Of course strlen() returns a size_t. So we'll replace those ints with
size_t's. What horrible thing have I now done to this function?

I don't get your point. You know the above is wrong and that
switching to size_ t does not make it right, so what are you driving
at?

What's wrong about it? It works fine, provided str points to a valid string.
There are two cases. If all of the values of size_t (the result of
strlen) can be represented in an int (not likely, but possible) then
the code works. If not, then strlen("") - 1 is a large positive
number that is out of range for an int, and the conversion to int is
implementation defined (which may include raising a signal).

--
Ben.
Sep 24 '08 #103
Lew Pitcher <lp******@teksavvy.comwrites:
My contribution to the cause

char *reverse(char *str)
{
char *start, *end, temp;

for (end=str;*end;++end);
--end; /* A */

for (start=str; start < end; ++start, --end) /* B */
{
temp = *start;
*start = *end;
*end = temp;
}
return str;
}

NB: For the degenerate case of a zero-length string, the computation of the
end character ( /* A */ ) produces a pointer that, *if dereferenced* would
encounter UB because it points out-of-bounds to the intended array.
You need to say why you dispute the claim that 6.5.6 paragraph 8 says
the result is undefined behaviour:

"... If both the pointer operand and the result point to elements
of the same array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined."
*However*, the reversal loop ( /* B */ ) tests the value of this pointer
(without dereferencing it), and will discontinue the loop immediately
(again, without dereferencing the pointer).
And then you'd have to say why the < operation is defined when most
people read 6.5.8 paragraph 5 as saying that it is not.

--
Ben.
Sep 24 '08 #104
Lew Pitcher said:
My contribution to the cause

char *reverse(char *str)
{
char *start, *end, temp;

for (end=str;*end;++end);
--end; /* A */
<snip>
NB: For the degenerate case of a zero-length string, the computation of
the end character ( /* A */ ) produces a pointer that, *if dereferenced*
would encounter UB because it points out-of-bounds to the intended array.
If you fall off the beginning of an array, dereferencing is not required -
just doing it is UB.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 24 '08 #105
Lew Pitcher <lp******@teksavvy.comwrites:
My contribution to the cause

char *reverse(char *str)
{
char *start, *end, temp;

for (end=str;*end;++end);
--end; /* A */
Did you not read the thread section where this is UDB in the case of
zero length strings? A surprise to me too I must admit. And thats even
before you use the illegal value in the comparison below.
>
for (start=str; start < end; ++start, --end) /* B */
{
temp = *start;
*start = *end;
*end = temp;
}
return str;
}

NB: For the degenerate case of a zero-length string, the computation of the
end character ( /* A */ ) produces a pointer that, *if dereferenced* would
encounter UB because it points out-of-bounds to the intended array.
*However*, the reversal loop ( /* B */ ) tests the value of this pointer
(without dereferencing it), and will discontinue the loop immediately
(again, without dereferencing the pointer).
--
Sep 24 '08 #106


do**************@ymail.com ha scritto:
Hello, I'm a highly experienced expert C programmer and I've written
this code to reverse a string in place. I think you could all learn
something from it!

int reverse(char* reverseme){
int retval=-1;
if(retval!=NULL){
int len=strlen(retval){
if(len>0){
int half=len>>1;
for(;retval<half;retval++){
reverseme[retval]^=reverseme[len-(retval+1)];
reverseme[len-(retval+1)]=reverseme[retval];
reverseme[retval]^=reverseme[len-(retval+1)];
}
}
}
return retval;
}

-Phil/CERisE
Just another little variation :

void reverse(char* pStart)
{
char* pEnd;
int len;

if((NULL==pStart) || (1 >= (len=(strlen(pStart)))))
return;

pEnd= pStart+len;
do{
char t;

pEnd--;
t = *pStart;
*pStart++ = *pEnd;
*pEnd = t;
}while(pStart < pEnd);
}

B.
Sep 24 '08 #107
Of course, that works, not like Your mental-disturbed code ;-)
B.

Sep 24 '08 #108
On September 24, 2008 09:49, in comp.lang.c, Ben Bacarisse
(be********@bsb.me.uk) wrote:
Lew Pitcher <lp******@teksavvy.comwrites:
>My contribution to the cause

char *reverse(char *str)
{
char *start, *end, temp;

for (end=str;*end;++end);
--end; /* A */

for (start=str; start < end; ++start, --end) /* B */
{
temp = *start;
*start = *end;
*end = temp;
}
return str;
}

NB: For the degenerate case of a zero-length string, the computation of
the end character ( /* A */ ) produces a pointer that, *if dereferenced*
would encounter UB because it points out-of-bounds to the intended array.

You need to say why you dispute the claim that 6.5.6 paragraph 8 says
the result is undefined behaviour:

"... If both the pointer operand and the result point to elements
of the same array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined."
>*However*, the reversal loop ( /* B */ ) tests the value of this pointer
(without dereferencing it), and will discontinue the loop immediately
(again, without dereferencing the pointer).

And then you'd have to say why the < operation is defined when most
people read 6.5.8 paragraph 5 as saying that it is not.
Oops. My bad. You are right, of course.

So, I'll try again - how about this variation?

char *reverse(char str[])
{
long int start, end;
char temp;

for (end=0;str[end];++end);
--end;

for (start=0; start < end; ++start, --end)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
}
return &str[0];
}
--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
Sep 24 '08 #109
Lew Pitcher wrote, On 24/09/08 18:28:
On September 24, 2008 09:49, in comp.lang.c, Ben Bacarisse
(be********@bsb.me.uk) wrote:
>Lew Pitcher <lp******@teksavvy.comwrites:
>>My contribution to the cause

char *reverse(char *str)
{
char *start, *end, temp;

for (end=str;*end;++end);
--end; /* A */

for (start=str; start < end; ++start, --end) /* B */
{
temp = *start;
*start = *end;
*end = temp;
}
return str;
}

NB: For the degenerate case of a zero-length string, the computation of
the end character ( /* A */ ) produces a pointer that, *if dereferenced*
would encounter UB because it points out-of-bounds to the intended array.
You need to say why you dispute the claim that 6.5.6 paragraph 8 says
the result is undefined behaviour:

"... If both the pointer operand and the result point to elements
of the same array object, or one past the last element of the array
object, the evaluation shall not produce an overflow; otherwise, the
behavior is undefined."
>>*However*, the reversal loop ( /* B */ ) tests the value of this pointer
(without dereferencing it), and will discontinue the loop immediately
(again, without dereferencing the pointer).
And then you'd have to say why the < operation is defined when most
people read 6.5.8 paragraph 5 as saying that it is not.

Oops. My bad. You are right, of course.

So, I'll try again - how about this variation?

char *reverse(char str[])
{
long int start, end;
char temp;

for (end=0;str[end];++end);
A problem is the string is longer than can be represented by a long int ;-)
--end;

for (start=0; start < end; ++start, --end)
{
temp = str[start];
str[start] = str[end];
str[end] = temp;
}
return &str[0];
Why not "return str"?
}
char *reverse(char *str)
{
if (str && *str) {
char *end;
char *start;
/* subtract safe as already caught 0 length */
for (start = str, end = strchr(str,0) - 1;
end start;
start++, end--) {
char temp = *start;
*start = *end;
*end = temp;
}
}
return str;
}

I think the only limits on this would be the limits on the C
implementation and, of course, needing the pointer passed to be a valid
pointer to the first[1] character modifiable string.

[1] Well, the first character of the sub-string you want reversed, you
could leave the start of a string unreversed by passing a pointer to a
later character in the string.
--
Flash Gordon
If spamming me sent it to sm**@spam.causeway.com
If emailing me use my reply-to address
See the comp.lang.c Wiki hosted by me at http://clc-wiki.net/
Sep 24 '08 #110
brix99luftballons wrote:
>
Of course, that works, not like Your mental-disturbed code ;-)
What works? You failed to quote anything. Bad.

See the following links:

<http://www.catb.org/~esr/faqs/smart-questions.html>
<http://www.caliburn.nl/topposting.html>
<http://www.netmeister.org/news/learn2quote.html>
<http://cfaj.freeshell.org/google/ (taming google)
<http://members.fortunecity.com/nnqweb/ (newusers)

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Sep 24 '08 #111

"Ben Bacarisse" <be********@bsb.me.ukwrote in message
"Bartc" <bc@freeuk.comwrites:
>What's wrong about it? It works fine, provided str points to a valid
string.

There are two cases. If all of the values of size_t (the result of
strlen) can be represented in an int (not likely, but possible) then
the code works. If not, then strlen("") - 1 is a large positive
number that is out of range for an int, and the conversion to int is
implementation defined (which may include raising a signal).
See the evil?

--
Free games and programming goodies.
http://www.personal.leeds.ac.uk/~bgy1mm

Sep 24 '08 #112
"Malcolm McLean" <re*******@btinternet.comwrites:
"Ben Bacarisse" <be********@bsb.me.ukwrote in message
>"Bartc" <bc@freeuk.comwrites:
>>What's wrong about it? It works fine, provided str points to a
valid string.

There are two cases. If all of the values of size_t (the result of
strlen) can be represented in an int (not likely, but possible) then
the code works. If not, then strlen("") - 1 is a large positive
number that is out of range for an int, and the conversion to int is
implementation defined (which may include raising a signal).
See the evil?
No, I see a problem if you subtract one from an unsigned number
that might be zero.

--
Ben.
Sep 24 '08 #113
Flash Gordon wrote:
char *reverse(char *str)
{
if (str && *str) {
char *end;
char *start;
/* subtract safe as already caught 0 length */
for (start = str, end = strchr(str,0) - 1;
end start;
start++, end--) {
char temp = *start;
*start = *end;
*end = temp;
}
}
return str;
}

I think the only limits on this would be the limits on the C
implementation and, of course, needing the pointer passed to be a valid
pointer to the first[1] character modifiable string.

[1] Well, the first character of the sub-string you want reversed, you
could leave the start of a string unreversed by passing a pointer to a
later character in the string.
[1]Footnote not needed:
Every byte in a string,
is the first byte of some string.

My turn!

#include <string.h>

char *str_rev(char *s)
{
char *const p = s;
char *t;
char swap;

if (*s != '\0') {
t = s + strlen(s + 1);
while (t s) {
swap = *t;
*t-- = *s;
*s++ = swap;
}
}
return p;
}

--
pete
Sep 24 '08 #114
pete wrote, On 25/09/08 00:16:
Flash Gordon wrote:
<snip>
>[1] Well, the first character of the sub-string you want reversed, you
could leave the start of a string unreversed by passing a pointer to a
later character in the string.

[1]Footnote not needed:
Every byte in a string,
is the first byte of some string.
I new that, but without it someone would have complained that it was
valid to pass a pointer to part way through a string :-)
My turn!

#include <string.h>

char *str_rev(char *s)
{
char *const p = s;
char *t;
char swap;

if (*s != '\0') {
You've decided to leave s==NULL as undefined behaviour. This *is* a
perfectly valid design decision.
t = s + strlen(s + 1);
Clever, saved yourself a subtraction :-)
It will still fail with a really stupidly long string so long that
strlen fails ;-) Now I've just got to find a way to generate such a
string :-) Not a problem in practice, but one I deliberately sidestepped
by using strchr.

<snip>
--
Flash Gordon
If spamming me sent it to sm**@spam.causeway.com
If emailing me use my reply-to address
See the comp.lang.c Wiki hosted by me at http://clc-wiki.net/
Sep 25 '08 #115
Flash Gordon wrote:
pete wrote:
.... snip ...
>
>Every byte in a string, is the first byte of some string.

I new that, but without it someone would have complained that it
was valid to pass a pointer to part way through a string :-)
I doubt it. I suspect you will get more 'fix your k key' help.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Sep 25 '08 #116
CBFalconer wrote, On 25/09/08 16:10:
Flash Gordon wrote:
>pete wrote:
... snip ...
>>Every byte in a string, is the first byte of some string.
I new that, but without it someone would have complained that it
was valid to pass a pointer to part way through a string :-)

I doubt it.
I don't.
I suspect you will get more 'fix your k key' help.
Nothing wrong with it. There is also a perfectly good reason why my
spelling is sometimes less than perfect, and a spell checker enabled in
my Usenet client and all my email clients to minimise the errors.
--
Flash Gordon
If spamming me sent it to sm**@spam.causeway.com
If emailing me use my reply-to address
See the comp.lang.c Wiki hosted by me at http://clc-wiki.net/
Sep 25 '08 #117

"lovecreatesbea...@gmail.com" <lo***************@gmail.comha scritto nel
messaggio
news:12**********************************@s20g2000 prd.googlegroups.com...
On Sep 23, 9:28 am, "lovecreatesbea...@gmail.com"
<lovecreatesbea...@gmail.comwrote:
On Sep 23, 7:22 am, pete <pfil...@mindspring.comwrote:


Richard wrote:
#include <string.h>
char * my_strrev(char *s){
char t;
char *e = s+strlen(s)-1;
while(e>s){
t = *s;
*s++ = *e;
*e-- = t;
}
}
unsigned my_strrev(char *s)
{unsigned h;
char *e, t;
if(s==0) return 0;
h=strlen(s);
if((int)h<=0) return 0;
e=s+h-1;
for( ;e>s ;--e,++s)
{t=*s; *s=*e; *e=t;}
return h;
}

not tested
don't know if "if((int)h<=0) return 0;" is right

I'm sure it breaks some sort of ISO magic, but it seems more concise
and
readable to me. No I didnt test it, but I guess the idea should be
self
evident.
It's undefined when attempting to reverse a zero length string.

How to reverse a zero length string for it has only a single NULL
terminating character : ) The reverse function quits if this is the
case.
My version

char *reverse(char *p)
{
char *p1, *p2, ch;

for (p1 = p; *(p1 + 1); p1++) ;
for (p2 = p; p2 < p1; p2++, p1--)
ch = *p2, *p2 = *p1, *p1 = ch;
return p;
}

Sep 26 '08 #118
Rosario wrote:
"lovecreatesbea...@gmail.com" <lo***************@gmail.comha scritto nel
messaggio
news:12**********************************@s20g2000 prd.googlegroups.com...
On Sep 23, 9:28 am, "lovecreatesbea...@gmail.com"
<lovecreatesbea...@gmail.comwrote:
>How to reverse a zero length string for it has only a single NULL
terminating character : ) The reverse function quits if this is the
case.

My version

char *reverse(char *p)
{
char *p1, *p2, ch;

for (p1 = p; *(p1 + 1); p1++) ;
*(p1 + 1) is undefined for a zero length string.

--
pete
Sep 26 '08 #119
On Sep 26, 5:08*pm, pete <pfil...@mindspring.comwrote:
*(p1 + 1) is undefined for a zero length string.
It existed in my old reply. Been revised as follow:

char *reverse(char *p)
{
char *p1, *p2, ch;

p1 = p;
if (!*p) return p;
while (*p1) p1++;
p1--;
for (p2 = p; p2 < p1; p2++, p1--)
ch = *p2, *p2 = *p1, *p1 = ch;
return p;
}
Sep 26 '08 #120
On Sep 26, 4:56 pm, "Rosario" <x...@y.zwrote:
>
unsigned my_strrev(char *s)
{unsigned h;
char *e, t;
if(s==0) return 0;
h=strlen(s);
if((int)h<=0) return 0;
e=s+h-1;
for( ;e>s ;--e,++s)
{t=*s; *s=*e; *e=t;}
return h;

}

not tested
don't know if "if((int)h<=0) return 0;" is right
The length of a string won't be a negative. The cast also isn't
required. The rest of it seems fine :)
Sep 26 '08 #121
pete wrote:
Rosario wrote:
.... snip ...
>
>char *reverse(char *p) {
char *p1, *p2, ch;

for (p1 = p; *(p1 + 1); p1++) ;

*(p1 + 1) is undefined for a zero length string.
Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Sep 26 '08 #122
On Sep 26, 5:20 pm, CBFalconer <cbfalco...@yahoo.comwrote:
pete wrote:
Rosario wrote:

... snip ...
char *reverse(char *p) {
char *p1, *p2, ch;
for (p1 = p; *(p1 + 1); p1++) ;
*(p1 + 1) is undefined for a zero length string.

Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.
Nit picking time :-)
Yes it is,

char foo[2];
foo[0] = 0;
reverse(foo);
Sep 26 '08 #123
On Fri, 26 Sep 2008 08:04:29 -0700 (PDT), vi******@gmail.com wrote:
>On Sep 26, 5:20 pm, CBFalconer <cbfalco...@yahoo.comwrote:
>pete wrote:
Rosario wrote:

... snip ...
>char *reverse(char *p) {
char *p1, *p2, ch;
> for (p1 = p; *(p1 + 1); p1++) ;
*(p1 + 1) is undefined for a zero length string.

Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.

Nit picking time :-)
Yes it is,

char foo[2];
Which array do you think is smaller than two characters?
>foo[0] = 0;
Since the value in foo[1] is indeterminate, *(p1+1) still invokes
undefined behavior.
>reverse(foo);
--
Remove del for email
Sep 27 '08 #124
Barry Schwarz wrote:
vi******@gmail.com wrote:
>CBFalconer <cbfalco...@yahoo.comwrote:
>>pete wrote:
Rosario wrote:

... snip ...

char *reverse(char *p) {
char *p1, *p2, ch;
>
for (p1 = p; *(p1 + 1); p1++) ;

*(p1 + 1) is undefined for a zero length string.

Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.

Nit picking time :-) Yes it is,

char foo[2];

Which array do you think is smaller than two characters?
>foo[0] = 0;

Since the value in foo[1] is indeterminate, *(p1+1) still
invokes undefined behavior.
No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Sep 27 '08 #125
On Fri, 26 Sep 2008 21:20:11 -0400, CBFalconer <cb********@yahoo.com>
wrote:
>Barry Schwarz wrote:
>vi******@gmail.com wrote:
>>CBFalconer <cbfalco...@yahoo.comwrote:
pete wrote:
Rosario wrote:

... snip ...

>char *reverse(char *p) {
> char *p1, *p2, ch;
>>
> for (p1 = p; *(p1 + 1); p1++) ;
>
*(p1 + 1) is undefined for a zero length string.

Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.

Nit picking time :-) Yes it is,

char foo[2];

Which array do you think is smaller than two characters?
>>foo[0] = 0;

Since the value in foo[1] is indeterminate, *(p1+1) still
invokes undefined behavior.

No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.
The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is indeterminate
or not. Evaluating an indeterminate value invokes undefined behavior.

--
Remove del for email
Sep 27 '08 #126
In article
<ab**********************************@v16g2000prc. googlegroups.com>,
"lo***************@gmail.com" <lo***************@gmail.comwrote:
On Sep 26, 4:56 pm, "Rosario" <x...@y.zwrote:

unsigned my_strrev(char *s)
{unsigned h;
char *e, t;
if(s==0) return 0;
h=strlen(s);
if((int)h<=0) return 0;
e=s+h-1;
for( ;e>s ;--e,++s)
{t=*s; *s=*e; *e=t;}
return h;

}

not tested
don't know if "if((int)h<=0) return 0;" is right

The length of a string won't be a negative. The cast also isn't
required.
The cast in fact causes it to fail for strings of length INT_MAX,
since it casts a value greater than INT_MAX to an int, yielding
implementation-defined behavior (which on most machines, means you get a
negative value that causes the code to return 0).

Also, strlen returns size_t, which might be larger than unsigned, so it
could also fail on a 64-bit machine when given a string longer than
UINT_MAX.
Sep 27 '08 #127
My somewhat late entry (two actually), and to keep with the implicit
tradition, untested except mentally. I don't think they invoke any UB,
for any valid string length (that is, 0 to (size_t) -1).

/* Minimal version, no frills, s must not be NULL */
void strrev1(char *s)
{
char* e = s;
while ( *e )
++e;

while ( e s )
{
char t = *s;
*s++ = *--e;
*e = t;
}
}

/* returns length (0 if s is NULL) */
size_t strrev2(char *s)
{
size_t len = 0;
if ( s != NULL )
{
len = strlen( s );
char* e = s + len;
while ( e s+1 ) /* s+1 eliminates extra iter */
{
char t = *s;
*s++ = *--e;
*e = t;
}
}
return len;
}
Sep 27 '08 #128
On Sep 27, 3:32 am, Barry Schwarz <schwa...@dqel.comwrote:
On Fri, 26 Sep 2008 08:04:29 -0700 (PDT), vipps...@gmail.com wrote:
On Sep 26, 5:20 pm, CBFalconer <cbfalco...@yahoo.comwrote:
pete wrote:
Rosario wrote:
... snip ...
char *reverse(char *p) {
char *p1, *p2, ch;
for (p1 = p; *(p1 + 1); p1++) ;
*(p1 + 1) is undefined for a zero length string.
Nit picking time.
No it isn't. It is if that string is stored in a char array
smaller than array of two chars.
Nit picking time :-)
Yes it is,
char foo[2];

Which array do you think is smaller than two characters?
Hmm... ?
CBFalconer claimed this:
No it isn't [undefined behavior, unless] It is if that string is stored
in a char array smaller than array of two chars.
Which means he claims with arrays equal or greater than two chars it
won't invoke undefined behavior.
char [2] is such array, but my code does invoke undefined behavior.
foo[0] = 0;

Since the value in foo[1] is indeterminate, *(p1+1) still invokes
undefined behavior.
That's what I wanted to demonstrate.
reverse(foo);
Sep 27 '08 #129
On Fri, 26 Sep 2008 22:52:53 -0700, Barry Schwarz wrote:
On Fri, 26 Sep 2008 21:20:11 -0400, CBFalconer <cb********@yahoo.com>
wrote:
>>No it doesn't. foo is a char array. foo[1] is a char. By definition,
a char cannot have unused bits. Therefore *(p1 + 1) is a valid char
even though uninitialized.

The issue is not whether foo[1] could possibly be a trap representation
(or otherwise invalid) but whether it is indeterminate or not.
Evaluating an indeterminate value invokes undefined behavior.
Not in C99. In C99, if you read a trap representation, the behaviour is
undefined if the type is not a character type, and if you read an
indeterminate value, there is usually a possibility of reading a trap
representation. When that possibility does exist but the type is a
character type, the behaviour is not explicitly undefined, but may be
undefined by omission. When that possibility doesn't exist, the behaviour
is defined.

C90 didn't have the concept of trap representations, and reading
indeterminate values of any type was not allowed, and the next C standard
will apparently reintroduce undefined behaviour for reading uninitialised
values in certain situations, so relying on C99's requirements is probably
not a good idea here.
Sep 27 '08 #130
On Sep 27, 12:07 pm, Harald van Dk <true...@gmail.comwrote:
On Fri, 26 Sep 2008 22:52:53 -0700, Barry Schwarz wrote:
On Fri, 26 Sep 2008 21:20:11 -0400, CBFalconer <cbfalco...@yahoo.com>
wrote:
>No it doesn't. foo is a char array. foo[1] is a char. By definition,
a char cannot have unused bits. Therefore *(p1 + 1) is a valid char
even though uninitialized.
The issue is not whether foo[1] could possibly be a trap representation
(or otherwise invalid) but whether it is indeterminate or not.
Evaluating an indeterminate value invokes undefined behavior.

Not in C99. In C99, if you read a trap representation, the behaviour is
undefined if the type is not a character type, and if you read an
indeterminate value, there is usually a possibility of reading a trap
representation. When that possibility does exist but the type is a
character type, the behaviour is not explicitly undefined, but may be
undefined by omission. When that possibility doesn't exist, the behaviour
is defined.

C90 didn't have the concept of trap representations, and reading
indeterminate values of any type was not allowed, and the next C standard
will apparently reintroduce undefined behaviour for reading uninitialised
values in certain situations, so relying on C99's requirements is probably
not a good idea here.

It really doesn't matter whether it's C90 or C99, it both cases the
code invokes undefined behavior.
Here's what's snipped:

for (p1 = p; *(p1 + 1); p1++) ;

Here's what I claimed to invoke undefined behavior:

char foo[2];
foo[0] = 0;

/* p = foo */

Which is true, regardless of C90 or C99.

I think mr Schwarz agreed with what I said, in which case he's also
correct.
Sep 27 '08 #131
vi******@gmail.com wrote:
Harald van Dk <true...@gmail.comwrote:
>Barry Schwarz wrote:
>>CBFalconer <cbfalco...@yahoo.comwrote:

No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.

The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is
indeterminate or not. Evaluating an indeterminate value invokes
undefined behavior.

Not in C99. In C99, if you read a trap representation, the
behaviour is undefined if the type is not a character type, and
if you read an indeterminate value, there is usually a possibility
of reading a trap representation. When that possibility does exist
but the type is a character type, the behaviour is not explicitly
undefined, but may be undefined by omission. When that possibility
doesn't exist, the behaviour is defined.

C90 didn't have the concept of trap representations, and reading
indeterminate values of any type was not allowed, and the next C
standard will apparently reintroduce undefined behaviour for
reading uninitialised values in certain situations, so relying on
C99's requirements is probably not a good idea here.

It really doesn't matter whether it's C90 or C99, it both cases the
code invokes undefined behavior.

Here's what's snipped:

for (p1 = p; *(p1 + 1); p1++) ;

Here's what I claimed to invoke undefined behavior:

char foo[2];
foo[0] = 0;

/* p = foo */

Which is true, regardless of C90 or C99.

I think mr Schwarz agreed with what I said, in which case he's also
correct.
No, you are wrong. The behaviour is undefined because *(p + 1)
yields an undefined value, and program action depends on the
zeroness of that value. Repeat, VALUE. It is NOT undefined
because of accessing that value, because by definition all possible
values in that location represent real chars.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Sep 27 '08 #132
CBFalconer wrote:
pete wrote:
>Rosario wrote:
... snip ...
>>char *reverse(char *p) {
char *p1, *p2, ch;

for (p1 = p; *(p1 + 1); p1++) ;
*(p1 + 1) is undefined for a zero length string.

Nit picking time.

No it isn't. It is if that string is stored in a char array
smaller than array of two chars.
Thank you.

--
pete
Sep 27 '08 #133
On Sep 27, 11:27 pm, CBFalconer <cbfalco...@yahoo.comwrote:
vipps...@gmail.com wrote:
Harald van Djik <true...@gmail.comwrote:
Barry Schwarz wrote:
CBFalconer <cbfalco...@yahoo.comwrote:
>>No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.
>The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is
indeterminate or not. Evaluating an indeterminate value invokes
undefined behavior.
Not in C99. In C99, if you read a trap representation, the
behaviour is undefined if the type is not a character type, and
if you read an indeterminate value, there is usually a possibility
of reading a trap representation. When that possibility does exist
but the type is a character type, the behaviour is not explicitly
undefined, but may be undefined by omission. When that possibility
doesn't exist, the behaviour is defined.
C90 didn't have the concept of trap representations, and reading
indeterminate values of any type was not allowed, and the next C
standard will apparently reintroduce undefined behaviour for
reading uninitialised values in certain situations, so relying on
C99's requirements is probably not a good idea here.
It really doesn't matter whether it's C90 or C99, it both cases the
code invokes undefined behavior.
Here's what's snipped:
for (p1 = p; *(p1 + 1); p1++) ;
Here's what I claimed to invoke undefined behavior:
char foo[2];
foo[0] = 0;
/* p = foo */
Which is true, regardless of C90 or C99.
I think mr Schwarz agreed with what I said, in which case he's also
correct.

No, you are wrong. The behaviour is undefined because *(p + 1)
yields an undefined value, and program action depends on the
zeroness of that value. Repeat, VALUE. It is NOT undefined
because of accessing that value, because by definition all possible
values in that location represent real chars.
Where have I claimed that it's undefined because the program accesses
that value?
Sep 28 '08 #134
vi******@gmail.com wrote:
CBFalconer <cbfalco...@yahoo.comwrote:
.... snip ...
>
>No, you are wrong. The behaviour is undefined because *(p + 1)
yields an undefined value, and program action depends on the
zeroness of that value. Repeat, VALUE. It is NOT undefined
because of accessing that value, because by definition all
possible values in that location represent real chars.

Where have I claimed that it's undefined because the program
accesses that value?
Maybe I read something you didn't say. At any rate, I just wanted
to clear the matter up.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Sep 28 '08 #135
On Sat, 27 Sep 2008 17:15:00 -0700, vippstar wrote:
On Sep 27, 11:27 pm, CBFalconer <cbfalco...@yahoo.comwrote:
>vipps...@gmail.com wrote:
Harald van Djik <true...@gmail.comwrote:
Barry Schwarz wrote:
CBFalconer <cbfalco...@yahoo.comwrote:
No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.
>>The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is
indeterminate or not. Evaluating an indeterminate value invokes
undefined behavior.
[snip]
I think mr Schwarz agreed with what I said, in which case he's also
correct.
[snip]
Where have I claimed that it's undefined because the program accesses
that value?
Ignoring some of the confusion over wording, you didn't. I was replying to
a message of Barry Schwarz, who did, and you thought you and he were in
agreement. Are we all clear now?
Sep 28 '08 #136
On 22 Sep 2008 at 22:41, Richard wrote:
You know I really had to look hard at this to understand it. Horrible
variables names almost purposely made "no standard" as far as C around
the world goes for such a function. Unnecessary length check.
Unnecessary size_t. Multiple assignments on one line making perusal
with a debugger almost impossible.
Yep - CBF is a living master-class in anti-style.
Much nicer IMO:

#include <string.h>

char * my_strrev(char *s){
char t;
char *e = s+strlen(s)-1;
while(e>s){
t = *s;
*s++ = *e;
*e-- = t;
}
}
Much nicer! Of course the "UB" that got the regs in a state will never
be a problem in the real world.

As efficiency was a concern for the OP, it might be worth dealing
specially with the favorable case when both the string length and its
starting location match up with the machine's natural alignment, so that
one can use only aligned accesses.

For example, on a 32-bit machine this might be more efficient (though of
course only profiling will tell for sure):

#define SWAP32(x) ((((x) & 0xff000000) >24) | (((x) & 0x00ff0000) >8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))

char *my_strrev(char *s)
{
size_t len = strlen(s);
if(((unsigned long) s & len & 0x11)==0) {
/* s aligned on 4-byte boundary, and length a multiple of 4 */
unsigned *start = (unsigned *) s;
unsigned *end = start + (len>>2) - 1;
unsigned temp;
while(end start) {
temp = SWAP32(*start);
*start++ = SWAP32(*end);
*end-- = temp;
}
}
else {
/* use generic string reverser */
}
return s;
}

Sep 28 '08 #137
On Sep 28, 3:05 pm, Harald van Dk <true...@gmail.comwrote:
On Sat, 27 Sep 2008 17:15:00 -0700, vippstar wrote:
On Sep 27, 11:27 pm, CBFalconer <cbfalco...@yahoo.comwrote:
vipps...@gmail.com wrote:
Harald van Djik <true...@gmail.comwrote:
Barry Schwarz wrote:
CBFalconer <cbfalco...@yahoo.comwrote:
No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.
>The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is
indeterminate or not. Evaluating an indeterminate value invokes
undefined behavior.

[snip]
I think mr Schwarz agreed with what I said, in which case he's also
correct.

[snip]
Where have I claimed that it's undefined because the program accesses
that value?

Ignoring some of the confusion over wording, you didn't. I was replying to
a message of Barry Schwarz, who did, and you thought you and he were in
agreement. Are we all clear now?
Yes, sorry for any confusion.
Sep 28 '08 #138
Antoninus Twink <no****@nospam.invalidwrites:
On 22 Sep 2008 at 22:41, Richard wrote:
>You know I really had to look hard at this to understand it. Horrible
variables names almost purposely made "no standard" as far as C around
the world goes for such a function. Unnecessary length check.
Unnecessary size_t. Multiple assignments on one line making perusal
with a debugger almost impossible.
<snip>
As efficiency was a concern for the OP, it might be worth dealing
specially with the favorable case when both the string length and its
starting location match up with the machine's natural alignment, so that
one can use only aligned accesses.

For example, on a 32-bit machine this might be more efficient (though of
course only profiling will tell for sure):

#define SWAP32(x) ((((x) & 0xff000000) >24) | (((x) & 0x00ff0000) >8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))

char *my_strrev(char *s)
{
size_t len = strlen(s);
if(((unsigned long) s & len & 0x11)==0) {
/* s aligned on 4-byte boundary, and length a multiple of 4 */
unsigned *start = (unsigned *) s;
unsigned *end = start + (len>>2) - 1;
unsigned temp;
while(end start) {
temp = SWAP32(*start);
*start++ = SWAP32(*end);
*end-- = temp;
}
}
else {
/* use generic string reverser */
}
return s;
}
I presume you share Richard's preference for interactive debugging?

--
Ben.
Sep 28 '08 #139
On 28 Sep 2008 at 21:23, Ben Bacarisse wrote:
I presume you share Richard's preference for interactive debugging?
Hmm? Apart from the fact that a | has wrongly become a & in this line...
> if(((unsigned long) s & len & 0x11)==0) {
....(and as a result of the correction extra parentheses are needed), I
don't see any obvious bug.

Sep 28 '08 #140
Antoninus Twink <no****@nospam.invalidwrites:
On 28 Sep 2008 at 21:23, Ben Bacarisse wrote:
>I presume you share Richard's preference for interactive debugging?

Hmm? Apart from the fact that a | has wrongly become a & in this line...
>> if(((unsigned long) s & len & 0x11)==0) {

...(and as a result of the correction extra parentheses are needed), I
don't see any obvious bug.
Nothing happens when len == 4.

--
Ben.
Sep 28 '08 #141
On 28 Sep 2008 at 22:17, Ben Bacarisse wrote:
Nothing happens when len == 4.
Oops, yes, thanks.

I did the usual amount of debugging before posting to Usenet (i.e.
zero)...

Sep 29 '08 #142
Barry Schwarz <sc******@dqel.comwrites:
On Fri, 26 Sep 2008 21:20:11 -0400, CBFalconer <cb********@yahoo.com>
wrote:
[...]
No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.

The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is indeterminate
or not. Evaluating an indeterminate value invokes undefined behavior.
I believe you're wrong. Types such as unsigned char that don't
have trap representations only have unspecified values if
accessed, not undefined behavior. Please support your claim
with a section citation.

Oct 9 '08 #143
On 09 Oct 2008 00:12:21 -0700, Tim Rentsch <tx*@alumnus.caltech.edu>
wrote:
>Barry Schwarz <sc******@dqel.comwrites:
>On Fri, 26 Sep 2008 21:20:11 -0400, CBFalconer <cb********@yahoo.com>
wrote:
[...]
>No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.

The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is indeterminate
or not. Evaluating an indeterminate value invokes undefined behavior.

I believe you're wrong. Types such as unsigned char that don't
have trap representations only have unspecified values if
accessed, not undefined behavior. Please support your claim
with a section citation.
The fact that char (all three types) does not have traps is covered in
6.2.6.1-5 and again in the 11th clause of J.2. That is completely
separate from the issue of indeterminate values which is covered in
the 10th clause of J.2 with references to 6.2.4, 6.7.8, and 6.8.
Unfortunately, those sections only state that the value is
indeterminate. And I could not find anything n1336 that improves the
situation.

--
Remove del for email
Oct 9 '08 #144
Barry Schwarz <sc******@dqel.comwrites:
On 09 Oct 2008 00:12:21 -0700, Tim Rentsch <tx*@alumnus.caltech.edu>
wrote:
Barry Schwarz <sc******@dqel.comwrites:
On Fri, 26 Sep 2008 21:20:11 -0400, CBFalconer <cb********@yahoo.com>
wrote:
[...]

No it doesn't. foo is a char array. foo[1] is a char. By
definition, a char cannot have unused bits. Therefore *(p1 + 1)
is a valid char even though uninitialized.

The issue is not whether foo[1] could possibly be a trap
representation (or otherwise invalid) but whether it is indeterminate
or not. Evaluating an indeterminate value invokes undefined behavior.
I believe you're wrong. Types such as unsigned char that don't
have trap representations only have unspecified values if
accessed, not undefined behavior. Please support your claim
with a section citation.

The fact that char (all three types) does not have traps is covered in
6.2.6.1-5 and again in the 11th clause of J.2. That is completely
separate from the issue of indeterminate values which is covered in
the 10th clause of J.2 with references to 6.2.4, 6.7.8, and 6.8.
Unfortunately, those sections only state that the value is
indeterminate. And I could not find anything n1336 that improves the
situation.
6.8 p 3 says "(including storing an indeterminate value in
objects without an initializer)". Since (unsigned char) doesn't
have any trap representations, storing an indeterminate value
means storing an unspecified value. The comment in J.2 item 10
is a non-normative simplification.

On implementations where other types (e.g., unsigned int) don't
have trap representations, leaving such variables uninitialized
also produces only unspecified values, not undefined behavior.

Incidentally, I think it's generally agreed that (char) and
(signed char) can have trap representations, even though
(unsigned char) cannot.
Oct 10 '08 #145

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.