In-place reverse of C-style string
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
5
down vote
favorite
This is a question from the book "Cracking the Coding Interview".
Write code to reverse a C-Style String (C-String means that âÂÂabcdâ is
represented as five characters, including the null character )
Please review this code.
#include <iostream>
void inPlaceReverseString(char str, int size)
int j = size - 2;
int i;
for (i = 0; i < (size-1)/2; ++i)
std::swap(str[i], str[j]);
j--;
str[size - 1] = '';
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, 255);
std::cout << "String: " << str << 'n';
int size = 0;
while (str[size] != '')
size++;
size++;
inPlaceReverseString(str, size);
std::cout << "Reversed String: " << str << 'n';
c++ strings programming-challenge interview-questions
add a comment |Â
up vote
5
down vote
favorite
This is a question from the book "Cracking the Coding Interview".
Write code to reverse a C-Style String (C-String means that âÂÂabcdâ is
represented as five characters, including the null character )
Please review this code.
#include <iostream>
void inPlaceReverseString(char str, int size)
int j = size - 2;
int i;
for (i = 0; i < (size-1)/2; ++i)
std::swap(str[i], str[j]);
j--;
str[size - 1] = '';
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, 255);
std::cout << "String: " << str << 'n';
int size = 0;
while (str[size] != '')
size++;
size++;
inPlaceReverseString(str, size);
std::cout << "Reversed String: " << str << 'n';
c++ strings programming-challenge interview-questions
3
std::reverse(str, std::strchr(str, ''));
â johnchen902
Jul 31 at 1:59
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
This is a question from the book "Cracking the Coding Interview".
Write code to reverse a C-Style String (C-String means that âÂÂabcdâ is
represented as five characters, including the null character )
Please review this code.
#include <iostream>
void inPlaceReverseString(char str, int size)
int j = size - 2;
int i;
for (i = 0; i < (size-1)/2; ++i)
std::swap(str[i], str[j]);
j--;
str[size - 1] = '';
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, 255);
std::cout << "String: " << str << 'n';
int size = 0;
while (str[size] != '')
size++;
size++;
inPlaceReverseString(str, size);
std::cout << "Reversed String: " << str << 'n';
c++ strings programming-challenge interview-questions
This is a question from the book "Cracking the Coding Interview".
Write code to reverse a C-Style String (C-String means that âÂÂabcdâ is
represented as five characters, including the null character )
Please review this code.
#include <iostream>
void inPlaceReverseString(char str, int size)
int j = size - 2;
int i;
for (i = 0; i < (size-1)/2; ++i)
std::swap(str[i], str[j]);
j--;
str[size - 1] = '';
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, 255);
std::cout << "String: " << str << 'n';
int size = 0;
while (str[size] != '')
size++;
size++;
inPlaceReverseString(str, size);
std::cout << "Reversed String: " << str << 'n';
c++ strings programming-challenge interview-questions
edited Aug 1 at 4:19
200_success
123k14143398
123k14143398
asked Jul 30 at 16:34
coder
911425
911425
3
std::reverse(str, std::strchr(str, ''));
â johnchen902
Jul 31 at 1:59
add a comment |Â
3
std::reverse(str, std::strchr(str, ''));
â johnchen902
Jul 31 at 1:59
3
3
std::reverse(str, std::strchr(str, ''));
â johnchen902
Jul 31 at 1:59
std::reverse(str, std::strchr(str, ''));
â johnchen902
Jul 31 at 1:59
add a comment |Â
4 Answers
4
active
oldest
votes
up vote
8
down vote
accepted
Because this is an attempt to answer an interview question, let's assume a hypothetical interviewer then asked you,
what would happen if I called your function using the following code:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
It would print,
"i sihT" has 6 characters
That doesn't seem to make sense. Not only that, your function potentially clobbered the rest of my string, by writing over the
s
in the word is
.
Don't break expectations/convention with strings
@koblas mentioned to use the standard library function strlen()
.
strlen()
returns the number of characters, not including the terminating character, in the string passed to it. C and C++ string handling functions that take a count parameter generally expect that count refers to the number of characters to work on.
But the size
parameter to inPlaceReverseString()
breaks that expectation. I think you're overthinking the C-style string's terminating character.
For interview questions (as well as coding in general), start with the simplest thing that can work and meets the specifications
Note that the interview question you quoted said, "write code to reverse a C-Style String", not "write code to reverse a specified number of characters in a C-Style String". For an interview-type question like this, rather than pass the length of the string as a parameter, just discover the length of the string within your function:
void inPlaceReverseString(char str)
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Note also that I slightly changed the loop-terminating logic, by checking i < j
. This makes the logic a bit easier to read, making it obvious that when the indexes i
and j
pass each other, there's no more replacement to be done.
Now, if you still want to have a length parameter (or are asked to extend the simple answer I wrote above), a couple suggestions:
Use a parameter name such as
num
,len
, or evenn
, as opposed tosize
. This is really pedantic on my part, butsize
tends to suggest memory sizes, as opposed to length of strings or number of characters.Use
size_t
as the type of the length parameter. This is an unsigned type, and conforms with the rest of C-style string functions that have a length/number parameter.Don't write a terminating
after the in place reversal.
Even if a length is specified, you should still check for a terminating
character within the string.
So, a possible implementation of the answer would look something like:
void inPlaceReverseString(char str, size_t num)
int len = strlen(str);
if (len < num)
// length of 'str' is less than 'num'. How to handle? ...
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Now, the original hypothetical question asked by the hypothetical interviewer at the start of this answer would work:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
would print:
"si sihT my long string with lots of character." has 47 characters
Would it be worth adding a comparison prior to the swap? For palindromic strings or those with lots of one particular character (aaaaaaabaac
) it could skip a fair amount of writes, and the cost for long random strings would be eliminated by branch prediction.
â Phil H
Jul 31 at 8:16
1
@PhilH I don't think it would be worth it. It would have to have a hard-coded letter frequency analysis, which is language-dependent. But even that assumes that the average use of the function is calling it on strings with the same expected distribution. I can't imagine the optimization ever paying off.
â scottbb
Jul 31 at 13:15
@PhilH Now, perhaps I could see a run-time hash table of reversed substrings working out. Maybe. But let's don't lose sight of the big picture: this is an interview question. I've never been in an interview where such complexity was desired, unless it was explicitly sought for.
â scottbb
Jul 31 at 13:18
add a comment |Â
up vote
5
down vote
You should look at using the strlen()
function. Use sizeof(str) so you don't have constants in two places.
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, sizeof(str));
std::cout << "String: " << str << 'n';
inPlaceReverseString(str, strlen(str) + 1);
std::cout << "Reversed String: " << str << 'n';
For your loop: Put everything in the loop iteration portion.
You initialize some variables inside and outside the loop, better if it's all in one place.
for (int i = 0, j = size - 2; i < (size-1)/2; ++i, --j)
std::swap(str[i], str[j]);
add a comment |Â
up vote
3
down vote
Here's a few things to consider:
You can remove the j variable from your loop
You only use it once. Instead you can write str[size - 1 - i]
. This saves you two lines of code, and the less code you have, the easier it usually is to focus on what a function does and to reason about it.
var--
is slower than --var
If you wanted to keep your j
, you could change that second line of the loop to --j
. This isn't a major speed improvement, but if you're preparing for an interview, it's probably a good way to show that you know what you're doing. This article does a fairly good job at explaining why this is, but don't bother too much trying to understand the messy details. Just know that it's a thing.
You don't need to manually append
Reversing a string does not change its length, so the null-character will be at the same byte it was before, thus you can just leave it be.
Conclusion
Considering the three points above, and the fact that size
can be used as if it was a local variable to your function, you could write the function like this:
void inPlaceReverseString(char str, int length)
int i;
--length;
for (i = 0; i < (length)/2; ++i)
std::swap(str[i], str[length - i]);
As you can see, you can decrement the size
variable in place as you only ever need size-1
. That's one operation we've taken out of the loop. If you want to take this one step further, you can save size/2
into its own variable to avoid having to divide it by 2 in every loop, but that'd make the code more complex and you'd only want to do that if speed is really crytical. In an interview, you could possibly mention this as an option if future benchmarks show that the function acts as a bottleneck.
Also note that I have changed size
to length
. The reason for that is that size usually refers to the size of the character buffer (255 in your example), not the length of the string it contains. Also the length of a string usually doesn't count the null-character at the end, so I took the liberty to change that as well. That's important because the size you calculate in main
does include the null-character.
var-- is slower than --var
For integral types, that's not true. Most decent compilers will know much better than the programmer which decrement idiom works best. However, your point is valid for classes that have the increment/decrement operators overloaded. In general, in C++, the pre-inc/dec operator is never less efficient than the post- forms, and may be faster, due to a copy of the object needing to be made for the post-inc/dec operator.
â scottbb
Aug 1 at 14:51
1
@scottbb Thay may be true with many modern compilers, but getting used to writing--i
instead ofi--
certainly doesn't hurt, and it doesn't make the code the slightest bit more complex. If this wasn't the case, I'd always recommend going with readability and only optimizing when speed is discovered to be an actual issue in benchmarks.
â DarkWiiPlayer
17 hours ago
Couldn't agree more, that is a very solid point.
â scottbb
16 hours ago
add a comment |Â
up vote
3
down vote
Outside of <iostream>
, your code looks like C rather than C++. That isn't necessarily bad, since you're dealing with C style strings, but you could also consider alternatives.
C style reversing
The function seems to take an array as its first argument, but it's actually completely equivalent to:
void inPlaceReverseString(char* str, int size);
So you don't need to use array indexing and may as well manipulate pointers directly, which is more traditional, concise and readable:
void inPlaceReverseString(char* str, int size)
char* end = str + size;
while (str < --end) std::swap(*str++, *end);
Since you use std::swap
, you could as well use other small C++ language or library features (conventions included):
void inPlaceReverseString(char* first, int size)
auto last = std::next(first, size);
while (first < --last) std::swap(*first++, *last);
C++ style reversing
Since std::swap(*first++, *last)
can be replaced by std::iter_swap(first++, last)
, you could have chosen the latter, which is arguably more readable. That substitution is possible because pointers are iterators in C++. Which also leads us to what an in place reversing function would look like in C++:
template <typename Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
This is rather interesting, because it can reverse a vector
or a list
as well, or anything that has a bidirectional iterator interface actually. It will soon be possible to constrain the argument type with a concept
(voted for C++20):
// given a Bidirectional_iterator concept
template <Bidirectional_iterator Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
If we are given a c_style string and its size, we can then call reverse this way:
reverse(str, str+size);
Of course, it could be better to use a RAII container over a C string, but since it's part of the question...
add a comment |Â
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
8
down vote
accepted
Because this is an attempt to answer an interview question, let's assume a hypothetical interviewer then asked you,
what would happen if I called your function using the following code:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
It would print,
"i sihT" has 6 characters
That doesn't seem to make sense. Not only that, your function potentially clobbered the rest of my string, by writing over the
s
in the word is
.
Don't break expectations/convention with strings
@koblas mentioned to use the standard library function strlen()
.
strlen()
returns the number of characters, not including the terminating character, in the string passed to it. C and C++ string handling functions that take a count parameter generally expect that count refers to the number of characters to work on.
But the size
parameter to inPlaceReverseString()
breaks that expectation. I think you're overthinking the C-style string's terminating character.
For interview questions (as well as coding in general), start with the simplest thing that can work and meets the specifications
Note that the interview question you quoted said, "write code to reverse a C-Style String", not "write code to reverse a specified number of characters in a C-Style String". For an interview-type question like this, rather than pass the length of the string as a parameter, just discover the length of the string within your function:
void inPlaceReverseString(char str)
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Note also that I slightly changed the loop-terminating logic, by checking i < j
. This makes the logic a bit easier to read, making it obvious that when the indexes i
and j
pass each other, there's no more replacement to be done.
Now, if you still want to have a length parameter (or are asked to extend the simple answer I wrote above), a couple suggestions:
Use a parameter name such as
num
,len
, or evenn
, as opposed tosize
. This is really pedantic on my part, butsize
tends to suggest memory sizes, as opposed to length of strings or number of characters.Use
size_t
as the type of the length parameter. This is an unsigned type, and conforms with the rest of C-style string functions that have a length/number parameter.Don't write a terminating
after the in place reversal.
Even if a length is specified, you should still check for a terminating
character within the string.
So, a possible implementation of the answer would look something like:
void inPlaceReverseString(char str, size_t num)
int len = strlen(str);
if (len < num)
// length of 'str' is less than 'num'. How to handle? ...
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Now, the original hypothetical question asked by the hypothetical interviewer at the start of this answer would work:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
would print:
"si sihT my long string with lots of character." has 47 characters
Would it be worth adding a comparison prior to the swap? For palindromic strings or those with lots of one particular character (aaaaaaabaac
) it could skip a fair amount of writes, and the cost for long random strings would be eliminated by branch prediction.
â Phil H
Jul 31 at 8:16
1
@PhilH I don't think it would be worth it. It would have to have a hard-coded letter frequency analysis, which is language-dependent. But even that assumes that the average use of the function is calling it on strings with the same expected distribution. I can't imagine the optimization ever paying off.
â scottbb
Jul 31 at 13:15
@PhilH Now, perhaps I could see a run-time hash table of reversed substrings working out. Maybe. But let's don't lose sight of the big picture: this is an interview question. I've never been in an interview where such complexity was desired, unless it was explicitly sought for.
â scottbb
Jul 31 at 13:18
add a comment |Â
up vote
8
down vote
accepted
Because this is an attempt to answer an interview question, let's assume a hypothetical interviewer then asked you,
what would happen if I called your function using the following code:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
It would print,
"i sihT" has 6 characters
That doesn't seem to make sense. Not only that, your function potentially clobbered the rest of my string, by writing over the
s
in the word is
.
Don't break expectations/convention with strings
@koblas mentioned to use the standard library function strlen()
.
strlen()
returns the number of characters, not including the terminating character, in the string passed to it. C and C++ string handling functions that take a count parameter generally expect that count refers to the number of characters to work on.
But the size
parameter to inPlaceReverseString()
breaks that expectation. I think you're overthinking the C-style string's terminating character.
For interview questions (as well as coding in general), start with the simplest thing that can work and meets the specifications
Note that the interview question you quoted said, "write code to reverse a C-Style String", not "write code to reverse a specified number of characters in a C-Style String". For an interview-type question like this, rather than pass the length of the string as a parameter, just discover the length of the string within your function:
void inPlaceReverseString(char str)
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Note also that I slightly changed the loop-terminating logic, by checking i < j
. This makes the logic a bit easier to read, making it obvious that when the indexes i
and j
pass each other, there's no more replacement to be done.
Now, if you still want to have a length parameter (or are asked to extend the simple answer I wrote above), a couple suggestions:
Use a parameter name such as
num
,len
, or evenn
, as opposed tosize
. This is really pedantic on my part, butsize
tends to suggest memory sizes, as opposed to length of strings or number of characters.Use
size_t
as the type of the length parameter. This is an unsigned type, and conforms with the rest of C-style string functions that have a length/number parameter.Don't write a terminating
after the in place reversal.
Even if a length is specified, you should still check for a terminating
character within the string.
So, a possible implementation of the answer would look something like:
void inPlaceReverseString(char str, size_t num)
int len = strlen(str);
if (len < num)
// length of 'str' is less than 'num'. How to handle? ...
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Now, the original hypothetical question asked by the hypothetical interviewer at the start of this answer would work:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
would print:
"si sihT my long string with lots of character." has 47 characters
Would it be worth adding a comparison prior to the swap? For palindromic strings or those with lots of one particular character (aaaaaaabaac
) it could skip a fair amount of writes, and the cost for long random strings would be eliminated by branch prediction.
â Phil H
Jul 31 at 8:16
1
@PhilH I don't think it would be worth it. It would have to have a hard-coded letter frequency analysis, which is language-dependent. But even that assumes that the average use of the function is calling it on strings with the same expected distribution. I can't imagine the optimization ever paying off.
â scottbb
Jul 31 at 13:15
@PhilH Now, perhaps I could see a run-time hash table of reversed substrings working out. Maybe. But let's don't lose sight of the big picture: this is an interview question. I've never been in an interview where such complexity was desired, unless it was explicitly sought for.
â scottbb
Jul 31 at 13:18
add a comment |Â
up vote
8
down vote
accepted
up vote
8
down vote
accepted
Because this is an attempt to answer an interview question, let's assume a hypothetical interviewer then asked you,
what would happen if I called your function using the following code:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
It would print,
"i sihT" has 6 characters
That doesn't seem to make sense. Not only that, your function potentially clobbered the rest of my string, by writing over the
s
in the word is
.
Don't break expectations/convention with strings
@koblas mentioned to use the standard library function strlen()
.
strlen()
returns the number of characters, not including the terminating character, in the string passed to it. C and C++ string handling functions that take a count parameter generally expect that count refers to the number of characters to work on.
But the size
parameter to inPlaceReverseString()
breaks that expectation. I think you're overthinking the C-style string's terminating character.
For interview questions (as well as coding in general), start with the simplest thing that can work and meets the specifications
Note that the interview question you quoted said, "write code to reverse a C-Style String", not "write code to reverse a specified number of characters in a C-Style String". For an interview-type question like this, rather than pass the length of the string as a parameter, just discover the length of the string within your function:
void inPlaceReverseString(char str)
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Note also that I slightly changed the loop-terminating logic, by checking i < j
. This makes the logic a bit easier to read, making it obvious that when the indexes i
and j
pass each other, there's no more replacement to be done.
Now, if you still want to have a length parameter (or are asked to extend the simple answer I wrote above), a couple suggestions:
Use a parameter name such as
num
,len
, or evenn
, as opposed tosize
. This is really pedantic on my part, butsize
tends to suggest memory sizes, as opposed to length of strings or number of characters.Use
size_t
as the type of the length parameter. This is an unsigned type, and conforms with the rest of C-style string functions that have a length/number parameter.Don't write a terminating
after the in place reversal.
Even if a length is specified, you should still check for a terminating
character within the string.
So, a possible implementation of the answer would look something like:
void inPlaceReverseString(char str, size_t num)
int len = strlen(str);
if (len < num)
// length of 'str' is less than 'num'. How to handle? ...
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Now, the original hypothetical question asked by the hypothetical interviewer at the start of this answer would work:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
would print:
"si sihT my long string with lots of character." has 47 characters
Because this is an attempt to answer an interview question, let's assume a hypothetical interviewer then asked you,
what would happen if I called your function using the following code:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
It would print,
"i sihT" has 6 characters
That doesn't seem to make sense. Not only that, your function potentially clobbered the rest of my string, by writing over the
s
in the word is
.
Don't break expectations/convention with strings
@koblas mentioned to use the standard library function strlen()
.
strlen()
returns the number of characters, not including the terminating character, in the string passed to it. C and C++ string handling functions that take a count parameter generally expect that count refers to the number of characters to work on.
But the size
parameter to inPlaceReverseString()
breaks that expectation. I think you're overthinking the C-style string's terminating character.
For interview questions (as well as coding in general), start with the simplest thing that can work and meets the specifications
Note that the interview question you quoted said, "write code to reverse a C-Style String", not "write code to reverse a specified number of characters in a C-Style String". For an interview-type question like this, rather than pass the length of the string as a parameter, just discover the length of the string within your function:
void inPlaceReverseString(char str)
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Note also that I slightly changed the loop-terminating logic, by checking i < j
. This makes the logic a bit easier to read, making it obvious that when the indexes i
and j
pass each other, there's no more replacement to be done.
Now, if you still want to have a length parameter (or are asked to extend the simple answer I wrote above), a couple suggestions:
Use a parameter name such as
num
,len
, or evenn
, as opposed tosize
. This is really pedantic on my part, butsize
tends to suggest memory sizes, as opposed to length of strings or number of characters.Use
size_t
as the type of the length parameter. This is an unsigned type, and conforms with the rest of C-style string functions that have a length/number parameter.Don't write a terminating
after the in place reversal.
Even if a length is specified, you should still check for a terminating
character within the string.
So, a possible implementation of the answer would look something like:
void inPlaceReverseString(char str, size_t num)
int len = strlen(str);
if (len < num)
// length of 'str' is less than 'num'. How to handle? ...
for (int i = 0, int j = strlen(str) - 1; i < j; ++i, --j)
std::swap(str[i], str[j]);
Now, the original hypothetical question asked by the hypothetical interviewer at the start of this answer would work:
...
char mylongstr = "This is my long string with lots of character.";
inPlaceReverseString(mylongstr, 7); // should reverse "This is"
cout << '"' << mylongstr << '"';
cout << " has " << strlen(mylongstr) << " charactersn";
...
would print:
"si sihT my long string with lots of character." has 47 characters
answered Jul 31 at 1:05
scottbb
830611
830611
Would it be worth adding a comparison prior to the swap? For palindromic strings or those with lots of one particular character (aaaaaaabaac
) it could skip a fair amount of writes, and the cost for long random strings would be eliminated by branch prediction.
â Phil H
Jul 31 at 8:16
1
@PhilH I don't think it would be worth it. It would have to have a hard-coded letter frequency analysis, which is language-dependent. But even that assumes that the average use of the function is calling it on strings with the same expected distribution. I can't imagine the optimization ever paying off.
â scottbb
Jul 31 at 13:15
@PhilH Now, perhaps I could see a run-time hash table of reversed substrings working out. Maybe. But let's don't lose sight of the big picture: this is an interview question. I've never been in an interview where such complexity was desired, unless it was explicitly sought for.
â scottbb
Jul 31 at 13:18
add a comment |Â
Would it be worth adding a comparison prior to the swap? For palindromic strings or those with lots of one particular character (aaaaaaabaac
) it could skip a fair amount of writes, and the cost for long random strings would be eliminated by branch prediction.
â Phil H
Jul 31 at 8:16
1
@PhilH I don't think it would be worth it. It would have to have a hard-coded letter frequency analysis, which is language-dependent. But even that assumes that the average use of the function is calling it on strings with the same expected distribution. I can't imagine the optimization ever paying off.
â scottbb
Jul 31 at 13:15
@PhilH Now, perhaps I could see a run-time hash table of reversed substrings working out. Maybe. But let's don't lose sight of the big picture: this is an interview question. I've never been in an interview where such complexity was desired, unless it was explicitly sought for.
â scottbb
Jul 31 at 13:18
Would it be worth adding a comparison prior to the swap? For palindromic strings or those with lots of one particular character (
aaaaaaabaac
) it could skip a fair amount of writes, and the cost for long random strings would be eliminated by branch prediction.â Phil H
Jul 31 at 8:16
Would it be worth adding a comparison prior to the swap? For palindromic strings or those with lots of one particular character (
aaaaaaabaac
) it could skip a fair amount of writes, and the cost for long random strings would be eliminated by branch prediction.â Phil H
Jul 31 at 8:16
1
1
@PhilH I don't think it would be worth it. It would have to have a hard-coded letter frequency analysis, which is language-dependent. But even that assumes that the average use of the function is calling it on strings with the same expected distribution. I can't imagine the optimization ever paying off.
â scottbb
Jul 31 at 13:15
@PhilH I don't think it would be worth it. It would have to have a hard-coded letter frequency analysis, which is language-dependent. But even that assumes that the average use of the function is calling it on strings with the same expected distribution. I can't imagine the optimization ever paying off.
â scottbb
Jul 31 at 13:15
@PhilH Now, perhaps I could see a run-time hash table of reversed substrings working out. Maybe. But let's don't lose sight of the big picture: this is an interview question. I've never been in an interview where such complexity was desired, unless it was explicitly sought for.
â scottbb
Jul 31 at 13:18
@PhilH Now, perhaps I could see a run-time hash table of reversed substrings working out. Maybe. But let's don't lose sight of the big picture: this is an interview question. I've never been in an interview where such complexity was desired, unless it was explicitly sought for.
â scottbb
Jul 31 at 13:18
add a comment |Â
up vote
5
down vote
You should look at using the strlen()
function. Use sizeof(str) so you don't have constants in two places.
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, sizeof(str));
std::cout << "String: " << str << 'n';
inPlaceReverseString(str, strlen(str) + 1);
std::cout << "Reversed String: " << str << 'n';
For your loop: Put everything in the loop iteration portion.
You initialize some variables inside and outside the loop, better if it's all in one place.
for (int i = 0, j = size - 2; i < (size-1)/2; ++i, --j)
std::swap(str[i], str[j]);
add a comment |Â
up vote
5
down vote
You should look at using the strlen()
function. Use sizeof(str) so you don't have constants in two places.
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, sizeof(str));
std::cout << "String: " << str << 'n';
inPlaceReverseString(str, strlen(str) + 1);
std::cout << "Reversed String: " << str << 'n';
For your loop: Put everything in the loop iteration portion.
You initialize some variables inside and outside the loop, better if it's all in one place.
for (int i = 0, j = size - 2; i < (size-1)/2; ++i, --j)
std::swap(str[i], str[j]);
add a comment |Â
up vote
5
down vote
up vote
5
down vote
You should look at using the strlen()
function. Use sizeof(str) so you don't have constants in two places.
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, sizeof(str));
std::cout << "String: " << str << 'n';
inPlaceReverseString(str, strlen(str) + 1);
std::cout << "Reversed String: " << str << 'n';
For your loop: Put everything in the loop iteration portion.
You initialize some variables inside and outside the loop, better if it's all in one place.
for (int i = 0, j = size - 2; i < (size-1)/2; ++i, --j)
std::swap(str[i], str[j]);
You should look at using the strlen()
function. Use sizeof(str) so you don't have constants in two places.
int main()
char str[255];
std::cout << "Enter Stringn";
std::cin.getline(str, sizeof(str));
std::cout << "String: " << str << 'n';
inPlaceReverseString(str, strlen(str) + 1);
std::cout << "Reversed String: " << str << 'n';
For your loop: Put everything in the loop iteration portion.
You initialize some variables inside and outside the loop, better if it's all in one place.
for (int i = 0, j = size - 2; i < (size-1)/2; ++i, --j)
std::swap(str[i], str[j]);
answered Jul 30 at 19:01
koblas
1737
1737
add a comment |Â
add a comment |Â
up vote
3
down vote
Here's a few things to consider:
You can remove the j variable from your loop
You only use it once. Instead you can write str[size - 1 - i]
. This saves you two lines of code, and the less code you have, the easier it usually is to focus on what a function does and to reason about it.
var--
is slower than --var
If you wanted to keep your j
, you could change that second line of the loop to --j
. This isn't a major speed improvement, but if you're preparing for an interview, it's probably a good way to show that you know what you're doing. This article does a fairly good job at explaining why this is, but don't bother too much trying to understand the messy details. Just know that it's a thing.
You don't need to manually append
Reversing a string does not change its length, so the null-character will be at the same byte it was before, thus you can just leave it be.
Conclusion
Considering the three points above, and the fact that size
can be used as if it was a local variable to your function, you could write the function like this:
void inPlaceReverseString(char str, int length)
int i;
--length;
for (i = 0; i < (length)/2; ++i)
std::swap(str[i], str[length - i]);
As you can see, you can decrement the size
variable in place as you only ever need size-1
. That's one operation we've taken out of the loop. If you want to take this one step further, you can save size/2
into its own variable to avoid having to divide it by 2 in every loop, but that'd make the code more complex and you'd only want to do that if speed is really crytical. In an interview, you could possibly mention this as an option if future benchmarks show that the function acts as a bottleneck.
Also note that I have changed size
to length
. The reason for that is that size usually refers to the size of the character buffer (255 in your example), not the length of the string it contains. Also the length of a string usually doesn't count the null-character at the end, so I took the liberty to change that as well. That's important because the size you calculate in main
does include the null-character.
var-- is slower than --var
For integral types, that's not true. Most decent compilers will know much better than the programmer which decrement idiom works best. However, your point is valid for classes that have the increment/decrement operators overloaded. In general, in C++, the pre-inc/dec operator is never less efficient than the post- forms, and may be faster, due to a copy of the object needing to be made for the post-inc/dec operator.
â scottbb
Aug 1 at 14:51
1
@scottbb Thay may be true with many modern compilers, but getting used to writing--i
instead ofi--
certainly doesn't hurt, and it doesn't make the code the slightest bit more complex. If this wasn't the case, I'd always recommend going with readability and only optimizing when speed is discovered to be an actual issue in benchmarks.
â DarkWiiPlayer
17 hours ago
Couldn't agree more, that is a very solid point.
â scottbb
16 hours ago
add a comment |Â
up vote
3
down vote
Here's a few things to consider:
You can remove the j variable from your loop
You only use it once. Instead you can write str[size - 1 - i]
. This saves you two lines of code, and the less code you have, the easier it usually is to focus on what a function does and to reason about it.
var--
is slower than --var
If you wanted to keep your j
, you could change that second line of the loop to --j
. This isn't a major speed improvement, but if you're preparing for an interview, it's probably a good way to show that you know what you're doing. This article does a fairly good job at explaining why this is, but don't bother too much trying to understand the messy details. Just know that it's a thing.
You don't need to manually append
Reversing a string does not change its length, so the null-character will be at the same byte it was before, thus you can just leave it be.
Conclusion
Considering the three points above, and the fact that size
can be used as if it was a local variable to your function, you could write the function like this:
void inPlaceReverseString(char str, int length)
int i;
--length;
for (i = 0; i < (length)/2; ++i)
std::swap(str[i], str[length - i]);
As you can see, you can decrement the size
variable in place as you only ever need size-1
. That's one operation we've taken out of the loop. If you want to take this one step further, you can save size/2
into its own variable to avoid having to divide it by 2 in every loop, but that'd make the code more complex and you'd only want to do that if speed is really crytical. In an interview, you could possibly mention this as an option if future benchmarks show that the function acts as a bottleneck.
Also note that I have changed size
to length
. The reason for that is that size usually refers to the size of the character buffer (255 in your example), not the length of the string it contains. Also the length of a string usually doesn't count the null-character at the end, so I took the liberty to change that as well. That's important because the size you calculate in main
does include the null-character.
var-- is slower than --var
For integral types, that's not true. Most decent compilers will know much better than the programmer which decrement idiom works best. However, your point is valid for classes that have the increment/decrement operators overloaded. In general, in C++, the pre-inc/dec operator is never less efficient than the post- forms, and may be faster, due to a copy of the object needing to be made for the post-inc/dec operator.
â scottbb
Aug 1 at 14:51
1
@scottbb Thay may be true with many modern compilers, but getting used to writing--i
instead ofi--
certainly doesn't hurt, and it doesn't make the code the slightest bit more complex. If this wasn't the case, I'd always recommend going with readability and only optimizing when speed is discovered to be an actual issue in benchmarks.
â DarkWiiPlayer
17 hours ago
Couldn't agree more, that is a very solid point.
â scottbb
16 hours ago
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Here's a few things to consider:
You can remove the j variable from your loop
You only use it once. Instead you can write str[size - 1 - i]
. This saves you two lines of code, and the less code you have, the easier it usually is to focus on what a function does and to reason about it.
var--
is slower than --var
If you wanted to keep your j
, you could change that second line of the loop to --j
. This isn't a major speed improvement, but if you're preparing for an interview, it's probably a good way to show that you know what you're doing. This article does a fairly good job at explaining why this is, but don't bother too much trying to understand the messy details. Just know that it's a thing.
You don't need to manually append
Reversing a string does not change its length, so the null-character will be at the same byte it was before, thus you can just leave it be.
Conclusion
Considering the three points above, and the fact that size
can be used as if it was a local variable to your function, you could write the function like this:
void inPlaceReverseString(char str, int length)
int i;
--length;
for (i = 0; i < (length)/2; ++i)
std::swap(str[i], str[length - i]);
As you can see, you can decrement the size
variable in place as you only ever need size-1
. That's one operation we've taken out of the loop. If you want to take this one step further, you can save size/2
into its own variable to avoid having to divide it by 2 in every loop, but that'd make the code more complex and you'd only want to do that if speed is really crytical. In an interview, you could possibly mention this as an option if future benchmarks show that the function acts as a bottleneck.
Also note that I have changed size
to length
. The reason for that is that size usually refers to the size of the character buffer (255 in your example), not the length of the string it contains. Also the length of a string usually doesn't count the null-character at the end, so I took the liberty to change that as well. That's important because the size you calculate in main
does include the null-character.
Here's a few things to consider:
You can remove the j variable from your loop
You only use it once. Instead you can write str[size - 1 - i]
. This saves you two lines of code, and the less code you have, the easier it usually is to focus on what a function does and to reason about it.
var--
is slower than --var
If you wanted to keep your j
, you could change that second line of the loop to --j
. This isn't a major speed improvement, but if you're preparing for an interview, it's probably a good way to show that you know what you're doing. This article does a fairly good job at explaining why this is, but don't bother too much trying to understand the messy details. Just know that it's a thing.
You don't need to manually append
Reversing a string does not change its length, so the null-character will be at the same byte it was before, thus you can just leave it be.
Conclusion
Considering the three points above, and the fact that size
can be used as if it was a local variable to your function, you could write the function like this:
void inPlaceReverseString(char str, int length)
int i;
--length;
for (i = 0; i < (length)/2; ++i)
std::swap(str[i], str[length - i]);
As you can see, you can decrement the size
variable in place as you only ever need size-1
. That's one operation we've taken out of the loop. If you want to take this one step further, you can save size/2
into its own variable to avoid having to divide it by 2 in every loop, but that'd make the code more complex and you'd only want to do that if speed is really crytical. In an interview, you could possibly mention this as an option if future benchmarks show that the function acts as a bottleneck.
Also note that I have changed size
to length
. The reason for that is that size usually refers to the size of the character buffer (255 in your example), not the length of the string it contains. Also the length of a string usually doesn't count the null-character at the end, so I took the liberty to change that as well. That's important because the size you calculate in main
does include the null-character.
answered Aug 1 at 7:16
DarkWiiPlayer
1367
1367
var-- is slower than --var
For integral types, that's not true. Most decent compilers will know much better than the programmer which decrement idiom works best. However, your point is valid for classes that have the increment/decrement operators overloaded. In general, in C++, the pre-inc/dec operator is never less efficient than the post- forms, and may be faster, due to a copy of the object needing to be made for the post-inc/dec operator.
â scottbb
Aug 1 at 14:51
1
@scottbb Thay may be true with many modern compilers, but getting used to writing--i
instead ofi--
certainly doesn't hurt, and it doesn't make the code the slightest bit more complex. If this wasn't the case, I'd always recommend going with readability and only optimizing when speed is discovered to be an actual issue in benchmarks.
â DarkWiiPlayer
17 hours ago
Couldn't agree more, that is a very solid point.
â scottbb
16 hours ago
add a comment |Â
var-- is slower than --var
For integral types, that's not true. Most decent compilers will know much better than the programmer which decrement idiom works best. However, your point is valid for classes that have the increment/decrement operators overloaded. In general, in C++, the pre-inc/dec operator is never less efficient than the post- forms, and may be faster, due to a copy of the object needing to be made for the post-inc/dec operator.
â scottbb
Aug 1 at 14:51
1
@scottbb Thay may be true with many modern compilers, but getting used to writing--i
instead ofi--
certainly doesn't hurt, and it doesn't make the code the slightest bit more complex. If this wasn't the case, I'd always recommend going with readability and only optimizing when speed is discovered to be an actual issue in benchmarks.
â DarkWiiPlayer
17 hours ago
Couldn't agree more, that is a very solid point.
â scottbb
16 hours ago
var-- is slower than --var
For integral types, that's not true. Most decent compilers will know much better than the programmer which decrement idiom works best. However, your point is valid for classes that have the increment/decrement operators overloaded. In general, in C++, the pre-inc/dec operator is never less efficient than the post- forms, and may be faster, due to a copy of the object needing to be made for the post-inc/dec operator.â scottbb
Aug 1 at 14:51
var-- is slower than --var
For integral types, that's not true. Most decent compilers will know much better than the programmer which decrement idiom works best. However, your point is valid for classes that have the increment/decrement operators overloaded. In general, in C++, the pre-inc/dec operator is never less efficient than the post- forms, and may be faster, due to a copy of the object needing to be made for the post-inc/dec operator.â scottbb
Aug 1 at 14:51
1
1
@scottbb Thay may be true with many modern compilers, but getting used to writing
--i
instead of i--
certainly doesn't hurt, and it doesn't make the code the slightest bit more complex. If this wasn't the case, I'd always recommend going with readability and only optimizing when speed is discovered to be an actual issue in benchmarks.â DarkWiiPlayer
17 hours ago
@scottbb Thay may be true with many modern compilers, but getting used to writing
--i
instead of i--
certainly doesn't hurt, and it doesn't make the code the slightest bit more complex. If this wasn't the case, I'd always recommend going with readability and only optimizing when speed is discovered to be an actual issue in benchmarks.â DarkWiiPlayer
17 hours ago
Couldn't agree more, that is a very solid point.
â scottbb
16 hours ago
Couldn't agree more, that is a very solid point.
â scottbb
16 hours ago
add a comment |Â
up vote
3
down vote
Outside of <iostream>
, your code looks like C rather than C++. That isn't necessarily bad, since you're dealing with C style strings, but you could also consider alternatives.
C style reversing
The function seems to take an array as its first argument, but it's actually completely equivalent to:
void inPlaceReverseString(char* str, int size);
So you don't need to use array indexing and may as well manipulate pointers directly, which is more traditional, concise and readable:
void inPlaceReverseString(char* str, int size)
char* end = str + size;
while (str < --end) std::swap(*str++, *end);
Since you use std::swap
, you could as well use other small C++ language or library features (conventions included):
void inPlaceReverseString(char* first, int size)
auto last = std::next(first, size);
while (first < --last) std::swap(*first++, *last);
C++ style reversing
Since std::swap(*first++, *last)
can be replaced by std::iter_swap(first++, last)
, you could have chosen the latter, which is arguably more readable. That substitution is possible because pointers are iterators in C++. Which also leads us to what an in place reversing function would look like in C++:
template <typename Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
This is rather interesting, because it can reverse a vector
or a list
as well, or anything that has a bidirectional iterator interface actually. It will soon be possible to constrain the argument type with a concept
(voted for C++20):
// given a Bidirectional_iterator concept
template <Bidirectional_iterator Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
If we are given a c_style string and its size, we can then call reverse this way:
reverse(str, str+size);
Of course, it could be better to use a RAII container over a C string, but since it's part of the question...
add a comment |Â
up vote
3
down vote
Outside of <iostream>
, your code looks like C rather than C++. That isn't necessarily bad, since you're dealing with C style strings, but you could also consider alternatives.
C style reversing
The function seems to take an array as its first argument, but it's actually completely equivalent to:
void inPlaceReverseString(char* str, int size);
So you don't need to use array indexing and may as well manipulate pointers directly, which is more traditional, concise and readable:
void inPlaceReverseString(char* str, int size)
char* end = str + size;
while (str < --end) std::swap(*str++, *end);
Since you use std::swap
, you could as well use other small C++ language or library features (conventions included):
void inPlaceReverseString(char* first, int size)
auto last = std::next(first, size);
while (first < --last) std::swap(*first++, *last);
C++ style reversing
Since std::swap(*first++, *last)
can be replaced by std::iter_swap(first++, last)
, you could have chosen the latter, which is arguably more readable. That substitution is possible because pointers are iterators in C++. Which also leads us to what an in place reversing function would look like in C++:
template <typename Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
This is rather interesting, because it can reverse a vector
or a list
as well, or anything that has a bidirectional iterator interface actually. It will soon be possible to constrain the argument type with a concept
(voted for C++20):
// given a Bidirectional_iterator concept
template <Bidirectional_iterator Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
If we are given a c_style string and its size, we can then call reverse this way:
reverse(str, str+size);
Of course, it could be better to use a RAII container over a C string, but since it's part of the question...
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Outside of <iostream>
, your code looks like C rather than C++. That isn't necessarily bad, since you're dealing with C style strings, but you could also consider alternatives.
C style reversing
The function seems to take an array as its first argument, but it's actually completely equivalent to:
void inPlaceReverseString(char* str, int size);
So you don't need to use array indexing and may as well manipulate pointers directly, which is more traditional, concise and readable:
void inPlaceReverseString(char* str, int size)
char* end = str + size;
while (str < --end) std::swap(*str++, *end);
Since you use std::swap
, you could as well use other small C++ language or library features (conventions included):
void inPlaceReverseString(char* first, int size)
auto last = std::next(first, size);
while (first < --last) std::swap(*first++, *last);
C++ style reversing
Since std::swap(*first++, *last)
can be replaced by std::iter_swap(first++, last)
, you could have chosen the latter, which is arguably more readable. That substitution is possible because pointers are iterators in C++. Which also leads us to what an in place reversing function would look like in C++:
template <typename Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
This is rather interesting, because it can reverse a vector
or a list
as well, or anything that has a bidirectional iterator interface actually. It will soon be possible to constrain the argument type with a concept
(voted for C++20):
// given a Bidirectional_iterator concept
template <Bidirectional_iterator Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
If we are given a c_style string and its size, we can then call reverse this way:
reverse(str, str+size);
Of course, it could be better to use a RAII container over a C string, but since it's part of the question...
Outside of <iostream>
, your code looks like C rather than C++. That isn't necessarily bad, since you're dealing with C style strings, but you could also consider alternatives.
C style reversing
The function seems to take an array as its first argument, but it's actually completely equivalent to:
void inPlaceReverseString(char* str, int size);
So you don't need to use array indexing and may as well manipulate pointers directly, which is more traditional, concise and readable:
void inPlaceReverseString(char* str, int size)
char* end = str + size;
while (str < --end) std::swap(*str++, *end);
Since you use std::swap
, you could as well use other small C++ language or library features (conventions included):
void inPlaceReverseString(char* first, int size)
auto last = std::next(first, size);
while (first < --last) std::swap(*first++, *last);
C++ style reversing
Since std::swap(*first++, *last)
can be replaced by std::iter_swap(first++, last)
, you could have chosen the latter, which is arguably more readable. That substitution is possible because pointers are iterators in C++. Which also leads us to what an in place reversing function would look like in C++:
template <typename Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
This is rather interesting, because it can reverse a vector
or a list
as well, or anything that has a bidirectional iterator interface actually. It will soon be possible to constrain the argument type with a concept
(voted for C++20):
// given a Bidirectional_iterator concept
template <Bidirectional_iterator Iterator>
void reverse(Iterator first, Iterator last)
while (first < --last) std::iter_swap(first++, last);
If we are given a c_style string and its size, we can then call reverse this way:
reverse(str, str+size);
Of course, it could be better to use a RAII container over a C string, but since it's part of the question...
answered Aug 1 at 12:57
papagaga
2,424115
2,424115
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200600%2fin-place-reverse-of-c-style-string%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
3
std::reverse(str, std::strchr(str, ''));
â johnchen902
Jul 31 at 1:59