446,148 Members | 1,339 Online
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
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 wrongor 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 writesAs 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 #include #include 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" 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 std::basic_string StringReverse2( const std::basic_string & input ) { typedef std::basic_string 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 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( 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 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 , Thomas Hansen writeschar * 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), butas 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 wrote: ...or maybe even better...: template std::basic_string StringReverse2( const std::basic_string & input ) { typedef std::basic_string 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 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" 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

 P: n/a On 18 Dec 2003 06:41:26 -0500, Thomas Hansen 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 std::basic_string StringReverse2( const std::basic_string & input ) { typedef std::basic_string 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(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" wrote in message "Michael" 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 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 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" 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 wrote: Is this variant better? (works with any traits/allocators or other implementation of string that do not use them) template 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" 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

 P: n/a Artie Gold 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 aslong as he dosn't feed an empty char array to it, it should notcrash. 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 , Siemel Naran writesOthers have good answers. Just one other unrelated thing. For functionsreturning 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 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 wrote in message news:... In article , Thomas Hansen writeschar * 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 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 hesubtracts 1, then he will swap the first character with theone-before-last character. If the goal is to revert the string thenI 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), butas 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 containing: On 18 Dec 2003 06:41:26 -0500, Thomas Hansen 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 averageprogrammer. The first thing you do is dereference end(). Trythis 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" wrote in message news:KnUDPDBXCr4 Naran writes Others have good answers. Just one other unrelated thing. For functionsreturning 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" 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 wrote: On 19 Dec 2003 02:40:03 -0500, there came a drop of sanity from John Potter containing: On 18 Dec 2003 06:41:26 -0500, Thomas Hansen 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 averageprogrammer. The first thing you do is dereference end(). Trythis 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 writes"John Potter" 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 validFine. p + 2; // undefined behavior for just trying to compute it p - 1; // same thingFine, but what could possibly go wrong. My compilers don't complain orcrash (ie. they do the right thing). But I guess other platforms could messup? 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 writesYes, for functions returning bool the convention is true means success (andtrue maps to a non-zero integer). And third, functions could throw tosignify 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. -- 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" 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 wrote: In message <7v***********************@bgtnsc04-news.ops.worldnet.att.net>, Siemel Naran writes"John Potter" 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 orcrash (ie. they do the right thing). But I guess other platforms could messup? 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 , Dhruv writesSame thing? AFAIK, delete is not allowed to mofdify the pointer passed toit, so just accessing the value stored in the pointer should not be aproblem? 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 wrote: "John Potter" 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" 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" 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 tosignify 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 , Dhruv writesSame thing? AFAIK, delete is not allowed to mofdify the pointer passed toit, so just accessing the value stored in the pointer should not be aproblem? 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 , Dhruv writesI do not know what address registers are. The only hardware that I'mpartially familiar with is the current x386 and pentium architecture, sowhatever I think is in terms of that hardware. It would be nice if youcould explain what happens on architectures with 'address registers', andwhat 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 , Siemel Naran writesFor the record, that convention is something I came up, and a few peopleuse. But I don't think anyone read throughout the land has said anythinglike 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 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 wrote: > > "John Potter" 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 #include 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 , Dhruv writesSo, 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 , Dhruv writesSo, 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.