How does this string reverse recursion work? - c

I usually understand recursions pretty well, but because I'm new to C functions like strcpy and pointers I couldn't figure out how this recursion reverses a string:
char *reverse(char *string)
{
if (strlen(string) <= 1)
return string;
else
{
char temp = *string;
strcpy(string, reverse(string+1));
*(string+strlen(string)) = temp;
return string;
}
}
The strcpy part seems a little bit complicated to me, and also what's the purpose of this line:
*(string+strlen(string)) = temp;?
I realize that after flipping the string you need to add the character that was at the beginning to the end of the string, but I'm not sure I understand the logic behind this code.

This code is extremely inefficient but what it does is:
Save the original first character
Recursively reverse the rest of the string (string+1 is a pointer to the second character in the string).
Copy the rest of the (reversed) string one character to the left.
Put the original first character at the end (*(string+strlen(string)) = temp;).
The *(string+strlen(string)) = temp; is equivalent to string[strlen(string)] = temp; if that is easier to understand.
I will not recommend using this code at all, since it is extremely inefficient -- it copies the entire string (and measures its length twice) in every iteration, not to mention waste stack space.
A much better implementation would be:
void reverse(char *s) {
char *e = s+strlen(s)-1;
while (e > s) {
char tmp = *s;
*s=*e;
*e=tmp;
s++; e--:
}
}

*(string+strlen(string)) = temp is so-called pointer arithmetic - that code is equivalent to string[strlen(string)] = temp. Therefore, this puts the temp character to the end of the string. Note that the string still remains zero-terminated as reverse() returns string of the same length as its argument.
The reverse(string+1) is again pointer arithmetic, this time same as reverse(&string[1]) - i.e., reverse() will mirror the string from the second character onwards, but then strcpy() will place it at the beginning of the string, overwriting the first character that is stored in temp and put at the end of the string.
However, the overall code looks needlessly convoluted and inefficient, so I'd think twice before drawing any lessons on how to do things from it.

This is how the code works. The input string is divided in two parts,
the first character, and the rest. The first character is stored in temp,
and the rest is reversed through a recursive call. The result of the recursive call is placed at the beginning of the result, and the character in temp is placed at the end.
string is [1234567890]
temp is 1, string+1 is [234567890]
reverse(string+1) is [098765432], temp is 1
the strcopy line is the part that copies the result from reverse(string+1) at the beginning of string, and *(string+strlen(string)) = temp is the part that copies temp at the end of string.

Related

Finding the Beginning of a string in C

To solve a question, I am looking for a way to stop a loop after it has reached the beginning of the string, assuming the loop starts from the end and decrements, is there an alternative way to do this without finding the length of the string first and decrementing till the number is zero?
Please keep in mind the only functions I can use are malloc, free and write.
This is not possible, because there is nothing special about a string's contents at the beginning. C strings have a "sentinel value" at their end - '\0' - but the first character, and the byte in memory before the first character, can have any value.
is there an alternative way to do this without finding the length of the string first and decrementing till the number is zero?
Apparently you already know where the end of the string is. I suppose you must have a pointer to the terminator character, since you think you do not know the string length.
If finding the length of the string is a viable option at all, however, then you must already know where the beginning is, too. And if you know where the beginning is and you know where the end is, then you already know the length: it is end - beginning. But you do not need to keep a separate counter to iterate backward from the end of a string to the beginning, supposing that you do know where both the end and the beginning are. You can simply use pointer comparisons instead. For example:
int count_a_backwards(const char *beginning, const char *end) {
int count = 0;
for (const char *c = end; c > beginning; ) {
if (*--c == 'a') count += 1;
}
return count;
}
If in fact you do not know where the beginning of the string is, however, then you cannot identify it at all, at least not in the general case. Perhaps you can recognize the beginning if you have some kind of prior knowledge about the string's contents, or about its alignment, or some such, but in general, the beginning of a string cannot be recognized.
Please keep in mind the only functions I can use are malloc, free and
write.
If you are using the function malloc then the function returns pointer to the first byte of the allocated memory. So if the allocated array will contain a string then its beginning will be known.
The task is to find the end of the string.
You can use either the standard C function strlen or write your own loop that will find the end of the stored string.
So if you have two pointers, one that points to the beginning of a string and the second that points to the end of the same string then to traverse the string in the reverse order is not a hard work.
Pay attention to that if you have a character array that contains a string like this
char s[] = "Hello";
then the expressions s, s + 1, s + 2 and so on all points to a string correspondingly "Hello", "ello", "llo" and so on.
You could find the beginning of a string having a pointer to its end provided that the first element of the array contains a unique symbol that is a sentinel value. However in general this is a very rare case.
Here is a demonstrative program that shows how you can traverse a string in the reverse order without using standard C string functions except a function that places a string in a dynamically allocated array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
enum { N = 12 };
char *s = malloc( N );
strcpy( s, "Hello World" );
puts( s );
char *p = s;
while ( *p ) ++p;
while ( p != s ) putchar( *--p );
putchar( '\n');
free( s );
return 0;
}
The program output is
Hello World
dlroW olleH

Replace String pattern with new string

I could really use some help with this question...
char *replace(char *s, char *pat, char *rep)
Returns a copy of the string s, but with each instance of pat replaced with rep. Note that len(pat) can be less than, greater than, or equal to len(rep). The function allocates memory for the resulting string, and it is up to the caller to free it. For example, if we call replace("Fiore X", "X", "sucks"), what is returned is the new string Fiore sucks (but remember, pat could be longer than an individual character and could occur multiple times).
I've managed to determine whether the pattern occurs in the original string, but I run into a problem if the pattern occurs more than once. I also haven't got to the part of creating a new string with the replaced text. I'm not allowed to use any functions from <string.h>. (I'm still very new to C)
char *replace(char *s, char *pat, char *rep){
char *a = malloc(300);
char *pa = s;
int patLen = 0;
int i;
for(i = 0; pat[i] != '\0'; i++)
{
patLen++;
}
int ogLen = patLen;
while(*s != '\0')
{
if(*s == *pat)
{
s++;
pat++;
patLen--;
while(*s == *pat)
{
s++;
pat++;
patLen--;
}
if(patLen == 0)
{
printf("This is a pattern");
patLen = ogLen;
}
}
s++;
}
return s;
}
Since you can't use string.h functions, I'd write a few string utility functions to count string length, compare strings and copy strings. This will make your code easier to understand. I'd make 2 passes through string s: first time would count the occurrences of pat. Then I can calculate the size of the new string: length(s) + occurrences * (length(rep) - length(pat). Allocate the new string. Now pass through string s again, copying into new string but whenever occurrence of pat is found, copy rep instead. Hope this helps.
Ok, not using string.h, it can be done.
First thing, you're doing pat++, but never going back. after finding the first occurrence of the first letter of the pat string, you're never coming back to the start of the string to make other comparisons in the future.
Using s++ is fine, as you don't need to come back to the start of this string, but for pat I would advise you to use index, and assess pat[i]. Nevertheless, if you keep track on how many times you advanced with pat++, you should be able to pat-- the exact amount (by the way, recursion would be an elegant way to do so without creating an int to keep track of how many times you advanced)
On the second while, just for safety, I would include &&*s!='\0'. And for proccess reasons, add &&patLen!=0. If you don't include this last one, you'll do one extra s++, and lose one possible starting point.
And finally, just a printf won't solve your problems, you should be able to track where the pattern was found (easily done with an array of ints) so you can go back and replace it.
The replacing gets trick when pat and rep have different sizes. I would create some additional functions, to make room for chars (in case rep>pat), and to eliminate some chars (if rep

C - start traversing from the middle of a string

Just double checking because I keep mixing up C and C++ or C# but say that I have a string that I was parsing using strcspn(). It returns the length of the string up until the first delimiter it finds. Using strncpy (is that C++ only or was that available in C also?) I copy the first part of the string somewhere else and have a variable store my position. Let's say strcspn returned 10 (so the delimiter is the 10th character)
Now, my code does some other stuff and eventually I want to keep traversing the string. Do I have to copy the second half of the string and then call strncspn() from the beginning. Can I just make a pointer and point it at the 11th character of my string and pass that to strncspn() (I guess something like char* pos = str[11])? Something else simpler I'm just missing?
You can get a pointer to a location in the middle of the string and you don't need to copy the second half of the string to do it.
char * offset = str + 10;
and
char * offset = &str[10];
mean the same thing and both do what you want.
You mean str[9] for the 10th char, or str[10] for the 11th, but yes you can do that.
Just be careful that you are not accessing beyond the length of the string and beyond the size of memory allocated.
It sounds like you are performing tokenization, I would suggest that you can directly use strtok instead, it would be cleaner, and it already handles both of what you want to do (strcspn+strncpy and continue parsing after the delimiter).
you can call strcspn again with (str + 11) as first argument. But make sure that length of str is greater than 11.
n = strcspn(str, pattern);
while ((n+1) < strlen(str))
{
n2 = strcspn((str+n), pattern);
n += n2;
}
Note : using char *pos = str[11] is wrong. You should use like char *pos = str + 11;

C version of strpos and substr?

I'm really surprised I can't figure out a way to do this effectively. I've tried strstr, a combination of things with sscanf, and nothing seems to work the way I would expect it to based on my experience in other languages.
I have a char of "ABCDEFG HIJ K BEGINTheMiddleEND LMNO PQRS". I do not know where "BEGINTheMiddleEND" is in the string, and I would like to end with a char that equals "TheMiddle" by finding the occurrences of "BEGIN" and "END" and grabbing what is in between.
What is the most efficient way to accomplish this (find and sub-string)?
Thanks!
-- EDIT BASED ON ANSWERS --
I have tried this:
char *searchString = "ABCDEFG HIJ K BEGINTheMiddleEND LMNO PQRS"
char *t1, *t2;
t1 = strstr(searchString, "BEGIN");
t2 = strstr(t1, "END");
But something must be wrong from a pointer standpoint as it doesn't work for me. Strstr only takes two arguments, so I'm not sure what you mean by starting at the previous pointer. I'm also not sure how to then use those pointers to substring it, as they are not integer values like strpos returns, but character pointers.
Thanks again.
-- EDIT WITH FINAL CODE --
For anyone else who hits this, the final, working code:
char *searchString = "ABCDEFG HIJ K BEGINTheMiddleEND LMNO PQRS"
char *b = strstr(searchString , "BEGIN");
char *e = strstr(b, "END");
int offset = e - b;
b[offset] = 0;
Where "b" is now equal to "BEGINTheMiddle". (which as it turns out is what I needed in this case).
Thanks again everyone.
You need to realize what a string is. A 0 delimited sequence of chars.
strstr does what it says: it finds the beginning of the given substring.
So calling strstr with the needle "BEGIN" takes you to the position of this substring. The pointer pointing to "BEGIN", advanced by 5 characters is pointing to "TheMiddle" onward to the next 0 char. By searching for "END" you can find the end pointer, and then you need to copy the substring into a new string array (or cut it, by replacing the "E" with a 0; or implement your own string functions that do not use 0 terminated strings, so they can arbitrarily overlap).
That is probably the step that you are still missing: actually copy the string. E.g. using
t3 = strndup(t1, t2 - t1);
Take the string ABCDEF0, where 0 is an actual 0 character. A pointer to the beginning points to the full string, a pointer pointing to the E points to "EF" only. If you want to get a string "AB", you need to either copy that to "AB0", or replace C by 0.
strstr does not do the copying for you. It just finds the position. If you want an index, you can do int offset = newPosition - oldPosition;, but if you need to continue searching, it's easier to work with the newPosition pointer.
All this is less intuitive than e.g. String operations in Java. Except for truncating strings, it actually is more efficient as far as I know, and if you realize the 0-terminated memory layout, it makes a lot of sense. It's only when you think of strings as arrays that it may seem odd to have a pointer somewhere in the middle, and continue using it like a regular array. That makes "sub = string + offset" the C way of writing "sub = string.substring(offset)".
use strstr() twice, but the sencond time start from the position returned by the first call to strstr() + strlen(BEGIN).
This will be efficient because the first pointer returned from strstr() is going to be the beginning of BEGIN, therefore you won't be looking through the whole string again but start at the BEGIN-ing and look for the END from there; which means that at the most you run through the whole string once.
I hope this will help
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strpos(char *haystack, char *needle, int offset);
int main()
{
char *p = "Hello there all y'al, hope that you are all well";
int pos = strpos(p, "all", 0);
printf("First all at : %d\n", pos);
pos = strpos(p, "all", 10);
printf("Second all at : %d\n", pos);
}
int strpos(char *hay, char *needle, int offset)
{
char haystack[strlen(hay)];
strncpy(haystack, hay+offset, strlen(hay)-offset);
char *p = strstr(haystack, needle);
if (p)
return p - haystack+offset;
return -1;
}

Reverse a string using recursion

I got this code from the internet but I couldnt get the whole code.
for example if(*str) . What does this code mean? and also can a string be returned? I thought that an array in main can be changed
directly in a function but here its been returned..
#include<stdio.h>
#define MAX 100
char* getReverse(char[]);
int main(){
char str[MAX],*rev;
printf("Enter any string: ");
scanf("%s",str);
rev = getReverse(str);
printf("Reversed string is: %s\n\n",rev);
return 0;
}
char* getReverse(char str[]){
static int i=0;
static char rev[MAX];
if(*str){
getReverse(str+1);
rev[i++] = *str;
}
return rev;
}
This is not the clearest example of recursion due to the use of the static variables. Hopefully the code generally seems clear to you, I suspect the part that is confusing to you is the same that was confusing to me at first.
if(*str){
getReverse(str+1);
rev[i++] = *str;
}
So line by line.
if(*str){
If we have not reached the null terminator.
getReverse(str+1);
Call the getReverse function on the next character of the string. It seems pretty straight forward up to here. But it also seems like it may not actually reverse anything because this is the next line
rev[i++] = *str;
We assign index i the character at the beginning of str and increment i but here is the tricky part. i may not be what you think. getReverse gets called before i is incremented. And i is static, so changes will persist between function calls. So, lets say we have a 5 letter word, let say "horse" we will end up with 6 calls on the stack to getReverse. The 6th will not do anything because that is where it finds the null terminator. The trick is that we will then go about resolving the calls in reverse order. First the call where str is pointing to 'e' will resolve and increment i because all the other ones are are still waiting for their calls to getReverse to return. So the last letters are actually the first ones to get added and increment i which is what can be confusing here.

Resources