I was wondering whether someone could explain how this small code snippet works.
void reverse(char *s)
{
if(*s)
reverse(s+1);
else
return;
cout << *s;
}
When you call this function in main, it supposedly prints out the reverse of any string put in (ie. hello would cout as olleh) but I don't understand how. As I understand it, the if statement increases the value of s until it reaches the end of the string, printing out each value in the string as it goes. Why doesn't that just re-print the string. Clearly I am missing something. (Sorry btw, I am new to C++ and recursive functions)
Consider how the "hello" string is stored in memory: let's say the address of its 'h' character happens to be 0xC000. Then the rest of the string would be stored as follows:
0xC000 'h'
0xC001 'e'
0xC002 'l'
0xC003 'l'
0xC004 'o'
0xC005 '\0'
Now consider a series of invocations of reverse: the initial invocation passes 0xC000; the call of reverse from inside the reverse passes s+1, so the next level gets 0xC001; the next one gets 0xC002, and so on.
Note that each level calls the next level, until the level that sees '\0'. Before we get to zero, the stack is "loaded" like this:
reverse(0xC004) // the last invocation before we hit '\0'
reverse(0xC003)
reverse(0xC002)
reverse(0xC001)
reverse(0xC000) // the earliest invocation
Now when the top invocation calls reverse(0xC005), the check for *s fails, and the function returns right away without printing anything. At this point the stack starts "unwinding", printing whatever is pointed to by its s argument:
0xC004 -> prints 'o', then returns to the previous level
0xC003 -> prints 'l', then returns to the previous level
0xC002 -> prints 'l', then returns to the previous level
0xC001 -> prints 'e', then returns to the previous level
0xC000 -> prints 'h', then returns for good.
That's how the reverse of the original "hello" string gets printed.
Try visualizing how the call stack builds up. Each recursive call creates another stack frame with a copy of s incremented by one. When the exit condition occurs, the stack starts unwinding and cout statement gets called for each frame. Because of LIFO principle, the string is printed in reverse.
Let's consider a string of length 3. reverse(i) is short for the function called on the i-th index of the string (well technically it's the char pointer + i, but that explanation requires a little more advanced understanding).
It's also useful to note (as Robert pointed out) that *s returns false if s points to \0, which indicates the end of the string, so, in this case, it will simply return.
Here's what happens:
reverse(0)
calls reverse(1)
calls reverse(2)
calls reverse(3)
end of string - return
prints 2
prints 1
prints 0
Lets look at a simple example, assume s = "the"
We would have:
rev(t) ->increment pointer
rev(h)->increment pointer
rev(e) ->increment pointer
rev('\0') (this would just return)
Then we would be back in the body of rev(e) which would print e
Then back to rev(h) which would print h
Then finally back to rev(t) which would print t
In that order then we would have: eht ("the" in reverse)
Perhaps it would be clearer to write the function as:
void reverse(const char *s)
{
if(*s)
{
reverse(s+1);
std::cout << *s;
}
}
i.e each not null characther will be printed after calling the next one (by the calling to reverse)
PD: Use "const char*" instead of "char*" if you will not modify the given string.
Related
For my homework assignment I am required to use pointers to navigate arrays in c++. The set function I have written to set a private object member variable char m_make[] equal to the passed char[] is not functioning correctly. When I try and run my program it appears to terminate after I call the setMake() function. What am I doing wrong?
Function declaration: (contained in an object called RentalCar)
void setMake(char make[5]);
Here is the code for setMake():
void RentalCar::setMake(char make[5]){
for(int i = 0; (make+i) != '\0';i++){
*(m_make+i) = *(make+i);
}
}
When I call setMake() no matter what I pass the function the output is Process returned followed by a very large number.
In your for loop, you are checking (make+i) != '\0' which basically adds i to make each time you iterate. make is the memory address of the first character of the array.
With that being said, (make+i) will never be == '\0' because (make+i) is a memory address, and addresses that your program has access to are never NULL which means it is an infinite loop.
You need to use the pointer notation to actually de-reference your (make+i) so that it checks the value that is inside the memory (make+i) but not the address itself. Means, you have to do:
*(make + i) != '\0'
to get the value and compare it, just like you are doing to set the value:
*(m_make+i) = *(make+i);
I have a homework with which I cannot cope.
"Write a recursive function that retrieves characters from the user until it encounters an star and returns a string of user-entered characters (without an star - *) in reverse order than they were entered."
I tried to write a code that gets characters until the star appears, but I do not know how to display the characters in reverse.
Solution
string recursiveReverse()
{
cout << "Enter a new character" << endl;
char text;
cin >> text;
if(text == '*')
return std::string();
else
recursiveReverse();
cout << text;
}
There are two stumbling blocks in what you’ve shown us:
Your function takes an argument; why? Nothing in the problem description suggests doing so.
Your function returns char rather than std::string (as requested).
If you adapt these two points you end up with the following function signature1:
std::string magic();
Now, how to implement this function? Well, the problem description hints at it:
read a single character
if the character is '*', return (an empty string) immediately
otherwise, recursively call the function and concatenate the current character to its return value.
1 This is the intuitive, naïve solution. There’s a better solution, which requires a changed signature. But this probably isn’t asked here and the reason why that signature is better isn’t trivial to explain.
Why don't you make the function return type void, when you encounter * you just return.
and you call the function recursively without putting a return before your recursive call
and then you print the character that you got and then you return.
Please need to know how this reverse function work, don't really get it, I know pointer do point to string[0], but how this function is able to print the right character to reverse the string correctly, How this is archive?
#include <iostream>
using namespace std;
void reverse(char *s); //prototype
//-------------------------------------------------------------------
int main ()
{
char str[] = "begin_this is a test_last"; //cstring to be reverse
reverse(str); //recursive function
cout << "\n";
return 0;
}
//---------------------------------------------------------------------
void reverse(char *s)
{
if(*s){
reverse(s + 1);
}else
return;
cout << *s; //question how this print the string in reverse??????
}
Your reverse() function is not actually reversing the string in memory, it is just outputting the string's characters in reverse order (to actually reverse the string in memory, use the STL's std::reverse() algorithm).
Now, lets look at the logic.
main() calls reverse(). A stack frame is pushed on the call stack, where s is pointing at the 1st character (str decays into a pointer to the first character).
s is not pointing at the null terminator, so reverse() calls itself, pushing a new stack frame on the call stack, where s contains a pointer to the 2nd character.
s is not pointing at the null terminator, so reverse() calls itself again, pushing a new stack frame on the call stack, where s contains a pointer to the 3rd character.
And so on, until reverse() is running with a stack frame where s is pointing at the null terminator. At this point, nothing has been output to std::cout yet, and a pointer to every character, including the null terminator, has been pushed onto the call stack in first-to-last order.
Now, reverse() stops calling itself and just exits, popping the current stack frame from the call stack (where s points at the null terminator).
Execution returns to the previous call site of reverse(), whose stack frame has s pointing at the last character. That character is output to std::cout and then reverse() exits, popping that stack frame from the call stack.
Execution returns to the previous call site of reverse(), whose stack frame has s pointing at the 2nd-to-last character. That character is output to std::cout and then reverse() exits, popping that stack frame from the call stack.
Execution returns to the previous call site of reverse(), whose stack frame has s pointing at the 3rd-to-last character. That character is output to std::cout and then reverse() exits, popping that stack frame from the call stack.
And so on, until execution returns to main(), and the entire string has been output to std::cout in reverse order.
reverse(char *s) is a recursive function. Recursive function would terminate only if certain conditions are met. In your example, the condition is *s == NULL
If the condition does not met, it would uses a stack to save the content of current function and execute the remaining code until its next generation complete all the tasks.
In your example, all cout << *s would be push into the stack until the last generation. Therefore, the first time you execute cout << *s is actually printing the last character of your string.
For example, let char arr[] = "READ" be the array.
1st R // waiting
2nd E // waiting
3rd A // waiting
4nd D // printing!!
After the last generation is complete:
1st R // waiting
2nd E // waiting
3rd A // printing!!
4nd D // finish!!
And then the next generation
1st R // waiting
2nd E // printing!!
3rd A // finish!!
4nd D // finish!!
And then the final generation
1st R // printing!!
2nd E // finish!!
3rd A // finish!!
4nd D // finish!!
This is exactly how to print a string backwards recursively.
Translated into English: in order to print a string in reverse, you first reverse-print everything except its first character, then you print its first character. If the string is empty, you do nothing.
Recursion, like the idea of functions in general, is older than computers. You can understand it without knowing a single thing about how a programming language might be implemented.
(It helps if you're familiar with mathematical induction, but it's definitely not a requirement.)
In fact, if you understand that in order to "first do this, then do that", that has to wait until this is done, you've pretty much understood everything.
The only thing missing, and what makes it recursive, is that in order to accomplish this, you may possibly need to do a smaller bit of "this, then that" first.
More concretely, suppose we want to print "abc" in reverse.
One way to look at it as that we need to first print 'c', then 'b', then 'a'.
Another way is to say that we can first print "cb", then 'a'.
But "cb" is also the reverse of the "tail" of "abc", so we should be able to use the same procedure for reversing both "abc" and "bc" - as long as we know how to reverse a shorter string, we can do that and then tack the string's first character on afterwards.
When does it end?
When we reach the shortest possible string, the empty string, we don't need to do anything, so that's where it ends.
Slightly more formally, we can use this procedure:
If the string is empty, do nothing.
If the string is not empty:
First print, using this procedure, all the characters except the first one,
Then print the first character.
and reversing "abc" will go like this:
Reverse "abc"
-> Reverse "bc", then print 'a'
-> Reverse "c", then print 'b', then print 'a'
-> Reverse "", then print 'c', then print 'b', then print 'a'
Reversing "" is to not do anything.
After we've done nothing, we can continue executing the rest of the sentence.
-> print 'c', then print 'b', then print 'a'
[Output: c]
-> print 'b', then print 'a'
[Output: cb]
-> print 'a'
[Output: cba]
I'm pretty inexperienced in c++, and I wrote the following code to see how characters and strings work.
#include "stdio.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
char asdf[] = "hello";
char test[5] = {'h','e','l','l','o'};
cout << test;
}
I was expected it to output "hello", but instead I got "hellohello", which is really puzzling to me. I did some experimenting:
If I change the asdf to another string of a different length, it outputs "hello" normally.
If I change the amount of characters in test it outputs "hello" normally.
I thought this only happened when the two were the same length, but when I change them both to "hell" it seems to output "hell" normally.
To make things more confusing, when I asked a friend to run this code on their computer, it outputted "hello" and then a random character.
I'm running a fresh install of code blocks on Ubuntu. Anyone have any idea what is going on here?
This is undefined behaviour.
Raw char* or char[] strings in C and C++ must be NULL-terminated. That is, the string needs to end with a '\0' character. Your test[5] does not do that, so the function printing the output continues after the last o, because it is still looking for the NULL-termination.
Due to how the strings are stored on the stack (the stack usually grows towards lower addresses), the next bytes it encounters are those of asdf[], to which you assigned "hello". This is how the memory layout actually looks like, the arrow indicates the direction in which memory addresses (think pointers) increase:
---->
+-------------------
|hellohello\0 ...
+-------------------
\_ asdf
\_ test
Now in C++ and C, string literals like "hello" are NULL-terminated implicitly, so the compiler writes a hidden '\0' behind the end of the string. The output function continues to print the contents of asdf char-by-char until it reaches that hidden '\0' and then it stops.
If you were to remove the asdf, you would likely see a bit of garbage after the first hello and then a segmentation fault. But this is undefined behaviour, because you are reading out of the bounds of the test array. This also explains why it behaves differently on different systems: for example, some compilers may decide to lay out the variables in a different order on the stack, so that on your friends system, test is actually lower on the stack (remember, lower on the stack means at a higher address):
---->
+-------------------
|hello\0hello ...
+-------------------
\_ test
\_ asdf
Now when you print the contents of test, it will print hello char-by-char, then continue reading the memory until a \0 is found. The contents of ... are highly specific to architecture and runtime used, possibly even phase of the moon and time of day (not entirely serious), so that on your friends machine it prints a "random" character and stops then.
You can fix this by adding a '\0' or 0 to your test array (you will need to change the size to 6). However, using const char test[] = "hello"; is the sanest way to solve this.
You have to terminate your test array with an ascii 0 char. What happens now is that in memory it is adjacent to your asdf string, so since test isn't terminated, the << will just continue until it meets the ascii 0 at the end of asdf.
In case you wonder: When filling asdf, this ascii 0 is added automatically.
The reason for this is that C style strings need the null character to mark the end of the string.
As you have not put this into the array test it will just keep printing characters until it finds one. In you case the array asdf happens to follow test in memory - but this cannot be guaranteed.
Instead change the code to this:
char test[] = {'h','e','l','l','o', 0};
cout is printing all characters starting from the beginning of the given address (test here, or &test[0] in equivalent notation) up to the point where it finds a null terminator. As you haven't put a null terminator into the test array it will continue to print until it accidently finds one in memory. Up from this point it's pretty much undefined behavior what happens.
Last character should be '\0' to indicate end of string.
char test[6] = {'h','e','l','l','o','\0'};
Unless there is an overload of operator<< for a reference to an array of 5 chars, the array will "decay" to a pointer to char and treated as a C style string by the operator. C style strings are by convention terminated with a 0 char, which your array is lacking. Therefore the operator continues outputting the bytes in memory, interpreting them as printable chars. It just so happens that on the stack, the two arrays were adjacent so that the operator ran into asdf's memory area, outputting those chars and finally encountering the implicit 0 char which is at the end of "hello". If you omit the other declaration it's likely that your program will crash, namely if the next 0 byte comes later than the memory boundary of your program.
It is undefined behavior to access memory outside an object (here: test) through a pointer to that object.
Character sequences need a null terminator (\0).
char asdf[] = "hello"; // OK: String literals have '\0' appended at the end
char test[5] = {'h','e','l','l','o'}; // Oops, not null terminated. UB
Corrected:
char test[6] = {'h','e','l','l','o','\0'}; // OK
// ^ ^^^^
I have the following simple code:
#include<iostream>
const char str[]={'C','+','+'};
int main()
{
const char *cp=str;
std::cout<<*str<<std::endl;
while (*cp++>0)
std::cout<<*cp;
}
can't understand why it prints
C
++
Shouldn't the postfix increment operator evaluate the expression but return the value unchanged? (I double checked precedence of increment, dereference and relational operators and it should work)
This line prints: C and the carriage return.
std::cout<<*str<<std::endl;
Then you are looping on following characters but there is no ending character (c.f. buffer overflow)
Here's the code fixed up.
#include <iostream>
const char str[]={'C','+','+', '\0'};
int main()
{
const char* cp = str;
std::cout<< *str << std::endl;
while (*cp++ > 0)
std::cout << *cp;
return 0;
}
This code is even simpler if you want to display "C++"
#include <iostream>
const char str[]={'C','+','+', '\0'};
int main()
{
const char* cp = str;
while (*cp > 0)
std::cout << *cp++;
std::cout << std::endl;
return 0;
}
Your problem is here:
while (*cp++>0)
std::cout<<*cp;
The postfix operator increments the value after the expression it was used in is evaluated. There are two different expressions referring to cp in this while statement though: the first one tests and increments, but the second one prints. Since the second one is a separate statement, the increment has already happened by then.
i.e. you currently test against 'C', then increment regardless of the result, then print '+' through the now-incremented pointer. If it were iterating a string literal, this code would also increment once after reaching the 0, although you don't see a result of that because it skips the print (because it iterates over a hand-created array with no null terminator, what it actually does here is fall off the end and exhibit undefined behaviour; this is a big error in itself, you can't rely on there being a zero at the end if one wasn't put there).
shouldn't the postfix increment operator evaluate the expression but return the value unchanged?
No, postfix operator returns the value of operand first then, only it is increased by 1.
here,
while (*cp++>0)
std::cout<<*cp;
by the time it reaches std::cout<<*cp; the value of cp is incremented, and hence the result ++.
In the line
while(*cp++>0)
The post increment operator is executed, after the evaluation happens.
i.e. cp points to C during the first evaluation of the while condition.
So,
*cp => 'C' which is greater than 0.
Before moving to the next line (Inside the loop), the post increment operator gets executed, making cp point to the first +
After + is printed, the while condition is executed again, this time *cp returns '+'. since '+' > 0, the control enters the loop for the second time.
Before entering the loop, the post increment operator executes again, making cp point to the second '+', which is printed.
Now, while condition is executed for the third time. Here, *cp returns +. Thus, control enters the loop again.
Before entering the loop, post increment executes again. This time, it makes cp point to the next character, which is \0.
The \0 is printed, which makes no difference in this code. Then, when the while condition executes again, *cp returns \0, which is not > 0. So, the condition fails.
Edit: Saw in the comments that you wanted to print the entire String in the same line. Change the loop to:
while(*cp > 0)
std:cout<<*cp++;