I am following a pdf to study recursion and string manipulation and I stumbled upon this.. I usually have an understanding of how a recursive function will behave (still not that good) but can't figure this out. This reverses the string. Well, prints it reversed.
void reverse(const char *const sptr);
int main()
{
char sentence[80];
printf("Enter a line of text:\n");
gets(sentence);
printf("\nThe reversed version:\n");
reverse(sentence);
puts("");
return 0;
}
void reverse(const char *const sptr)
{
if(sptr[0] == '\0')
{
return;
}
else{
reverse(&sptr[1]);
putchar(sptr[0]);
}
}
I don't really understand how putchar works in this occasion. Can anyone explain it to me? I imagine this isn't just for putchar, how does the function behave when another command line is written "after" the recalling of the function?
It has nothing to do with putchar, it has everything to do with recursion.
Say you give it the string "1234" - or lets call it ['1','2','3','4','\0']
The first time reverse is called, it is called with the argument sptr pointing to ['1','2','3','4','\0'];
Execution reaches the recursive call to reverse and this time uses the offset 1, hence the argument becomes ['2','3','4','\0']
The process is repeated until a '\0' is found and now the function returns to the previous caller which prints the last character, returns to previous caller, which prints the 2:nd last character and so on until top reverse call is reached which prints the first character, and then exists.
Perhaps printing some additional debug info will make it easier to understand.
#include <stdio.h>
void reverse(const char *const sptr);
int recursion_level;
int main()
{
recursion_level=0;
char sentence[80]="1234";
// printf("Enter a line of text:\n");
// gets(sentence);
printf("\nThe reversed version:\n");
reverse(sentence);
puts("");
return 0;
}
void reverse(const char *const sptr)
{
recursion_level++;
printf("reverse entered, recursion level:%d , sptr:%s \n",recursion_level, sptr);
if(sptr[0] == '\0')
{ recursion_level--;
return;
}
else{
reverse(&sptr[1]);
putchar(sptr[0]);
}
printf("\n reverse exits, recursion level:%d , \n",recursion_level);
recursion_level--;
}
Which generates the following output
The reversed version:
reverse entered, recursion level:1 , sptr:1234
reverse entered, recursion level:2 , sptr:234
reverse entered, recursion level:3 , sptr:34
reverse entered, recursion level:4 , sptr:4
reverse entered, recursion level:5 , sptr:
4
reverse exits, recursion level:4 ,
3
reverse exits, recursion level:3 ,
2
reverse exits, recursion level:2 ,
1
reverse exits, recursion level:1 ,
this works because of that :
reverse(&sptr[1]);
putchar(sptr[0]);
you first call on the next characters then you print the first, so
the first printed character will be the last
then you come back and write the previous being just before the last
...
then you come back and print the first character
&sptr[1] is equivalent of sptr + 1 so that point to the address of the next character
if you reverse the lines and do that :
putchar(sptr[0]);
reverse(&sptr[1]);
you print the characters in the initial order
When you don't understand just execute the program into a debugger step by step
It is very simple.
You recursively call the function with the string as a parameter. Every call the the string is one char shorter (as you pass the pointer to the second char in the string . When it is zero length the first return occurs. The string has a length 1 and it is only the last character of the string. You print it (as you print the first character), then you return to the instance where the string was 2 chars long - you print it the first char whicg is the second from the end. Then you return and the string is 3 chars long you print the first char again and this repeats until you print all chars form the string in the reverse order.
You do not need the else statement at all as if the condition is met the control will never reach that statements
void reverse(const char *const sptr)
{
if(!sptr[0]) return;
reverse(&sptr[1]);
putchar(sptr[0]);
}
int main()
{
reverse("Hello World");
return 0;
}
You can also add the check if the parameter is not NULL
void reverse(const char *const sptr)
{
if(!sptr && sptr[0] == '\0') return;
reverse(&sptr[1]);
putchar(sptr[0]);
}
As all others are saying, this is simple.
But the best thing to explain is to see you how that work in adding some log in your C code.
#include "pch.h"
#include <stdio.h>
#include <stdlib.h>
void reverse(const char *const sptr);
void openTraceFile();
void closeTraceFile();
void enterFunction();
void exitFunction();
void writeMessage(const char* s);
int main()
{
char sentence[80];
printf("Enter a line of text:\n");
//gets(sentence);
fgets(sentence, 80, stdin);
openTraceFile();
printf("\nThe reversed version:\n");
reverse(sentence);
puts("");
closeTraceFile();
return 0;
}
static FILE* logfile;
static int iNrSpaces = 0;
void reverse(const char *const sptr)
{
enterFunction();
if (sptr[0] == '\0')
{
writeMessage("end of string");
exitFunction();
return;
}
reverse(&sptr[1]);
putchar(sptr[0]);
char s[80];
sprintf(s,"putchar( %c )", sptr[0]);
writeMessage(s);
exitFunction();
}
void openTraceFile()
{
logfile = fopen("reverse.log", "w");
if (logfile == NULL)
{
printf("Error! Could not open file\n");
exit(-1);
}
void closeTraceFile()
{
fclose(logfile);
}
void enterFunction()
{
writeMessage(">> reverse()");
iNrSpaces += 4;
writeMessage("{");
}
void exitFunction()
{
writeMessage("}");
iNrSpaces -= 4;
}
void writeMessage(const char* s)
{
for (int i = 0; i < iNrSpaces; i++)
{
fputc(' ',logfile);
}
fprintf(logfile, s);
fputc('\n', logfile);
}
When you execute this program in entering "help", you will obtain following lines in reverse.log file.
>> reverse()
{
>> reverse()
{
>> reverse()
{
>> reverse()
{
>> reverse()
{
>> reverse()
{
end of string
}
putchar( \0 )
}
putchar( p )
}
putchar( l )
}
putchar( e )
}
putchar( h )
}
If now, you extract putchar() call without changing order of execution, you will obtain
putchar( p );
putchar( l );
putchar( e );
putchar( h );
that is the inversed string !
I hope that this explanation using LOG has helped you to understand this problem.
Little remark: \0 character is returner first in your example !
Related
Yesterday I had to solve an exam exercise, which, unfortunately, I failed..
The exercise was to create a function in C with the following rules:
Write a function that takes a string and displays the string in reverse
order followed by the newline.
Its prototype is constructed like this : char *ft_rev_print (char *str)
It must return its argument
Only allowed to use function 'write'(so no printf or others)
With that information I wrote :
int ft_strlen(char *str) /*to count the length of the original string*/
{
int i;
i = 0;
while (str[i])
i++;
return (i);
}
char *ft_rev_print (char *str)
{
int i;
i = ft_strlen(str);
while (i)
{
write (1, (str +1), 1);
i--;
}
return (str); /*returning its argument */
}
int main(void) /*IT HAD TO WORK WITH THIS MAIN, DID NOT WROTE THIS MYSELF!*/
{
ft_rev_print("rainbow dash");
write(1, "\n", 1);
return (0);
}
I tried for ages to get it to work, but failed.. So now I'm breaking my head over this. What did i do wrong ? What did i miss?
Thanks in advance !
Your while loop is wrong, you start with i=0 and iterate while it's not zero, so no iterations will be done.
What you should do is:
initialize i so that it is the index of the last character
loop as long as it's a valid index
print the i-th character, not always the second (at index one)
char *ft_rev_print (char *str)
{
int i;
i = ft_strlen(str) - 1; // <-- Initialize i to be the index of the last character
while (i >= 0) // <-- Loop as long as it's valid
{
write (1, (str+i), 1); // <-- Print the i-th character
i--;
}
return (str);
}
For starters your teachers are not enough qualified. The functiuon should be declared at least like
char * ft_rev_print( const char *str );
^^^^^
because the passed string is not changed within the function.
You forgot to call the function ft_strlen.
It seems you mean
i = ft_strlen( str );
As a result this loop
i = 0;
while (i)
{
//...
}
is never executed because initially i is equal to 0 and the condition of the loop at once evaluates to false.
Also in this call
write (1, (str +1), 1);
^^^^^^^^
you are always trying to output the second symbol of the string.
Also the output of the new line character '\n' should be within the function according to its description.
The function can look the following way as it is shown in the demonstrative program below (instead of the non-standard function write I will use the function putchar but you can substitute it for write yourself)
#include <stdio.h>
char * ft_rev_print( const char *str )
{
const char *p = str;
while ( *p ) ++p;
while ( p != str ) putchar( *--p ); // substitute the call of putchar for write( 1, *--p, 1 )
putchar( '\n' ); // substitute the call of putchar for write( 1, "\n", 1 )
return ( char * )str;
}
int main(void)
{
ft_rev_print( "rainbow dash" );
return 0;
}
The program output is
hsad wobniar
Hey I have tried your question and there is a small point I would like to add,In your question you have written the length of your string and also the part below in your code:
write (1, (str +1), 1);
was not correct so I corrected it and in that basically we are adding the back of previous characters like this and error was in a while loop condition:
write (1,(str+i),1);
You can full prototype here:
char *ft_rev_print (char *str)
{
int i;
i = ft_strlen(str);//returning the length of string
while (i>=0)
{
write (1,(str+i),1);
i--;
}
return (str); /*returning its argument */
}
So I have this and I want to:
For the word "are":
caramare
aresdn
lasrare
aresare
mare
We have n=3 as only 3 words end in our specific word and have it inside only once.
If I read a wrong word, like "ares", it will break the program. Why is that?
It is required to start the program from:
n=.....;
for(i=1;i<=11;i++)
{ cin>>s; | scanf(“%s”,s);
............
}
This is what I have tried:
#include <stdio.h>
#include <string.h>
int main()
{
char s[20][20];
int n=0;
int i;
for(i=1;i<=11;i++)
{
scanf("%s",s);
if(strcmp ( strstr("are",s[i]) ,"are") ==0 )
{
n++;
}
}
printf("%d",n);
}
One problem is that strstr returns NULL if the needle is not found. Then you pass a NULL pointer to strcmp which will go all wrong.
You need to split it like:
char* tmp = strstr("are",s[i]);
if (tmp)
{
if (strcmp ( tmp ,"are") ==0 )
{
n++;
}
}
And this
char s[20][20];
shall just be:
char s[20];
and please never, never ever do scanf("%s",s); Always - like in always, allways, allways - put a limit - like scanf("%19s",s); so that the user can't overflow your input buffer.
I am encountering a problem while printing out a string using a while loop in a standalone function.
I have the following code:
#include <stdio.h>
int pword(char *);
int main() {
char s[] = "Alice";
pword(s);
return 0;
}
int pword(char *s) {
while(*s!='\0') {
printf("%s", s);
s++;
}
printf("\n");
return 0;
}
This is printing: Aliceliceicecee.
you're printing the offseted word each time, instead of the character.
Try changing (for instance)
printf("%s", s);
by
printf("%c", *s);
or since you don't really need formatting, use
putchar(*s);
(all this means that you're basically rewriting puts with a loop. So if no further processing is required on the characters, maybe you should just stick with standard functions)
%s means expect a const char * argument
%c means expect a character argument. The character argument is printed. Null characters are ignored;
You are looking for later one.
More info on %s: The argument is taken to be a string (character pointer), and characters from the string
are printed until a null character or until the number of characters indicated by the
precision specification is reached; however, if the precision is 0 or missing, all characters up to a null are printed;
Seeing no answer explained what exactly was going on, here is what you are actually doing:
int pword(char *s) { /* s = "Alice" (s is a char* that holds the address of "Alice" string)*/
while(*s!='\0') { /* check if the first char pointed to by s != '\0' */
printf("%s", s); /* print the string that start at s*/
s++; /* move s (the char pointer) 1 step forward*/
} /* s points to "lice" -> "ice" -> "ce" -> "e" */
printf("\n");
return 0;
}
In order to print the string "Alice" you could have just used printf("%s", s); as it would take the address pointed to by s, where "Alice" is stored, and print it until reaching null-terminator ('\0').
If you want to use a loop and print char by char, you should have used printf("%c", *s);. Using %c is meant for printing char where %s is for printing strings. Another thing to note is the s vs *s, where the former is a char* (pointer to char) that can hold number of consecutive chars, and the later (*s)is *(char*) i.e. dereferenced char*, that holds a single char.
To sum up:
print char by char
int pword(char *s) {
while(*s!='\0') {
printf("%c", *s);
s++;
}
printf("\n");
return 0;
}
print the whole string at once
int pword(char *s) {
printf("%s\n", s);
return 0;
}
If you want to print character by character, you should use *s in the printf statement like below.
#include <stdio.h>
int pword(char *);
int main() {
char s[] = "Alice";
pword(s);
return 0;
}
int pword(char *s) {
while(*s!='\0') {
printf("%c", *s);
s++;
}
printf("\n");
return 0;
}
This is the code. It has to have the section before the void main() in it as it is the requirements i was told for the code.The stuff after void strcopy needs to be kept until void main().
#include <stdio.h>
void strcopy(char * string1, char * string2)
{
int i = 0;
while (string1[i] != '\0') {
string2[i] = string1[i];
i++;
}
return;
/* copies string1 to string 2 */
}
void main()
{
char string1[1000], string2[1000];
int i;
printf("Enter the string: \n");
scanf("%[^\n]s", string1);
printf(" %s ", string2);
return;
}
This is what is being printed and I'm stumped. Can someone help me out please?
Enter the string:
hello
t��\�
Thanks
First, you do not call strcopy, so you print just the uninitialized content of string2. Second, in strcopy, you forgot to terminate the target string (note that your loop terminates before the `\0' would be written). Write:
void strcopy(char * string1, char * string2)
{
int i = 0;
while (string1[i] != '\0') {
string2[i] = string1[i];
i++;
}
string2[i]='\0';
return;
/* copies string1 to string 2 */
}
If you do not terminate a string, then any bytes in the target memory are treated as "belonging to the string" until a 0x0 byte is reached. And these bytes might produce such weird output.
But you never called strcopy().
Add the function call after reading input:
strcopy(string1, string2);
Other issues are:
main() function should return int. So, change the definition to: int main(void) {... and return an int value such as return EXIT_SUCCESS;.
You haven't inserted the null byte into your destination. You need it because you are printing it as a string using %s. Add string2[i] = 0; after the while loop.
Remove the s from scanf()'s format specifier. %[^\n] is enough to read upto a newline. Instead you might considering using fgets(). Because scanf() as you use - is susceptible to buffer overflow and generally inferior.
I have to reverse a string in a recursive function, but I cannot use loops or strlen to find where the end of the string is. Then I have to pass the reversed string back to main and copy it to a new file. Here's what I have so far:
int reverse(char *str, char *strnew, int p)
{
char temp=str[p];
if(temp=='\0' || temp=='\n')
{
strnew=str;
return p;
}
else
{
reverse(str++, strnew, ++p);
p--;
strnew[p]=str[p];
printf("strnew: %c\n", strnew[p]);
return 0;
}
}
int main(int argc, char *argv[])
{
FILE *fp;
char buffer[100];
char newstr[100];
int pointer=0;
fp=fopen("lab8.txt", "r");
if(fp==NULL)
{
printf("Error opening file\n");
return 0;
}
(fgets(buffer, 100, fp));
reverse(buffer, newstr, pointer);
printf("newstr: %s\n", newstr);
FILE *fp2=fopen("lab8.2.txt", "w");
fputs(newstr, fp2);
fclose(fp);
fclose(fp2);
return 0;
}
I cannot wrap my head around how to reverse the string. I've found where the null character is using p, but how do I copy the string backwards onto a new string?
#include <stdio.h>
int reverse(char *str, int pos){
char ch = str[pos];
return (ch == '\0')? 0 : ((str[pos=reverse(str, ++pos)]=ch), ++pos);
}
int main(){
char buffer[100];
scanf("%99[^\n]", buffer);
reverse(buffer, 0);
fprintf(stdout, "%s\n", buffer);
return 0;
}
Since this is obviously homework, no complete solution, only ideas.
First, you don't need to limit yourself to one recursive function. You can have several, and a resursive implementation of strlen is trivial enough. my_strlen(char *p) evaluates to 0 if *p = 0, and to 1 + my_strlen(p+1) otherwise.
You can probably do it in a single recursion loop, too, but you don't have to.
One more thing: as you recurse, you can run your code both on the front end of recursion and on the back end. A recursion is like a loop; but after the nested call to self returns, you have a chance to perform another loop, this one backwards. See if you can leverage that.
It is quite simple. When you enter the string, you save the character at the position you are are. Call the method recursively more character to the right. When you get to the end of the string, you will have N stack frames, each holding one character of an N character string. As you return, write the characters back out, but increment the pointer as you return, so that the characters are written in the opposite order.
I'll try to be nice and give you a little sample code. With some explanation.
The beauty of recursion is that you don't need to know the length of the string, however the string must be null terminated. Otherwise you can add a parameter for the string length.
What you need to think is that the last input character is your first output character, therefore you can recurse all the way to the end until you hit the end of the string. As soon as you hit the end of the string you start appending the current character to the output string (initially set to nulls) and returning control to the caller which will subsequently append the previous character to the output string.
void reverse(char *input, char *output) {
int i;
if(*input) /* Checks if end of string */
reverse(input+1,output); /* keep recursing */
for(i=0;output[i];i++); /* set i to point to the location of null terminator */
output[i]=*input; /* Append the current character */
output[i+1]=0; /* Append null terminator */
} /* end of reverse function and return control to caller */
Finally, lets test the function.
int main(argc, argv) {
char a[]="hello world";
char b[12]="\0";
reverse(a,b);
printf("The string '%s' in reverse is '%s'\n", a, b);
}
Output
The string 'hello world' in reverse is 'dlrow olleh'