strlen function using recursion in c - c

I'm kida new to the recursion subject and i've been trying to write the "strlen" function using recurion, thats what i tried:
int strlen ( char str[], int i)
{
if ( str[i] == 0) return i+1;
return strlen(str,i++);
}
and i tried something very similiar
int strlen( char str[], int i)
{
if ( str[i] == 0) return 1;
return strlen(str,i++) + 1;
}
and in my main function
int main()
{
char word[MAX_DIGITS];
scanf("%s",word);
printf("%d", strlen(word,0));
return 0;
}
but my program would crash whenever i run it, what am I missing? (I'm using C90 btw)

Your problem starts here:
i++
This is called a postfix.
Just use ++i or i + 1
Postfix sends the value and just then increments the variable. It's like writing this:
return strlen(str,i);
i = i + 1;
You have to use Prefix, which increments the variable and then sends the value. A prefix (++i) will act like that:
i = i + 1;
return strlen(str,i);
Or just send the value without changing the variable:
return strlen(str, i + 1);
Which, in my opinion, is the simplest way to do that.

size_t strlen (char* str) {
if (*str == 0) {
return 0;
}
return strlen (str+1) +1;
}
So :
strlen ("") == 0
strlen ("a") -> strln("") + 1 == 1
strlen ("he") -> strln("e") + 1) = (strln("") + 1) + 1 == 2
etc

return strlen(str,i++);
You are using the wrong increment operator. i++ means the original value of i is passed as argument, and then it's incremented. That means infinite recursion.
You should try ++i instead, or better, i + 1.

If you want to keep the same prototype as strlen does.
This is how i see a strlen with recursion.
size_t strlen(char *str)
{
static int i = 0;
if (*str != '\0')
{
i++;
return ft_strlen(++str);
}
return i;
}
I know it's not the best way to do it. Just my implementation.

Related

Function that returns 1 if two arrays are completely different and 0 if there's a common element

I've tried this code but it doesn't seem to be working, how to break out of the nested loop ?
#include <stdio.h>
#include <string.h>
int meme(char s1[], char s2[])
{
int i = 0, j = 0;
int different;
while (i <= strlen(s1) && different == 1) {
while (j <= strlen(s2)) {
if (s1[i] != s2[j]) {
different = 1;
} else {
different = 0;
}
j = j + 1;
}
i = i + 1;
}
return different;
}
You have to initialize different as it is undefined if not - this probably breaks your first while loop as different probably is a random number > 1.
strlen gives you the number of characters in the string excluding the null-character which terminates the string (see here). However, you do not only compare the characters of the two strings, but also the null-character, probably to implicitely check if the length of the strings is the same. While this should work, it is better to do this check explicitely by comparing the length of the strings first as it is less error-prone.
It isn't necessary to do a nested loop here if you compare the length of the strings first. Also, you now know the length of both strings, so this function can be change to use a for loop, which makes it even simpler.
A possible solution based on the points above:
#include <stdio.h>
#include <string.h>
int meme(char s1[], char s2[]){
int i = 0;
int len_s1 = 0;
int len_s2 = 0;
int different = 0;
len_s1 = strlen(s1);
len_s2 = strlen(s2);
if (len_s1 == len_s2) {
for (i = 0 ; i < len_s1 ; i++) {
if (s1[i] != s2[i]) {
different = 1;
break;
}
}
else {
different = 1;
}
return different;
}
One more thing - do yourself and everyone else a favor and intend your code as it is extremely hard to read otherwise!
Your code is not optimized and you are not using a good approach for doing the task. I have modified the code and it will do the job with minimized complexity.
Here I assume that both the arrays are of same size as your problem shows
bool meme(char s1[], char s2[])
{
int i=0;
while(s1[i] != NULL && s2[i] != NULL)
{
if(s1[i] == s2[i])
return false;
i += 1;
}
return true;
}
When you call this function then declare a variable of type bool and store the returned value of this function in that variable.
For example :
bool check;
bool = meme(array 1 , array 2);
and then check if returned value is true, then both the arrays are totally different else not. You can do that by the below code :
if(check)
printf("Arrays are different");
else
printf("Arrays are not different");
You can also use int in place of bool if it suits you better but remember, whatever code you write, must be least complex. And think that if you are using int then also you are returning only 0 or 1; but int takes 2 bytes in 32-bit compiler and 4 bytes in 64-bit compiler, but bool takes only 1 byte and even 1 bit in some languages like pascal (if I am not wrong).
And don't get confused with return true; and return false;. True simply means 1 and false means 0. And a boolean type variable can store only binary number (1 or 0).
There is so much wrong with your code.
Why are you calling strlen() in while()? It will get executed every time till the loop doesn't exit and will cost on performance.
Also the variable different is not initialized with value 1, so how can you be so sure about the initial value of that variable?
I have tried to simplify your function still, there is scope for optimization:
int meme(char s1[], char s2[])
{
int i = 0;
int different;
int str1_len = strlen(s1);
int str2_len = strlen(s2);
if(str1_len > str2_len)
str1_len = str2_len;
do{
if(s1[i] == s2[i])
{
printf("Common\n");
different = 0;
}
else
{
different = 1;
}
i++;
}while(str1_len--);
return different;
}

What does a return statement within a loop do?

In the code below, str_replace_all replaces all occurrences of oldc with newc. str_replace_first is only supposed to replace the first occurrence of oldc with newc.
So str_replace_all loops through and it replaces all occurrences of oldc with newc, easy enough to understand. In the second function str_replace_first the code is identical, except for return 1 after finding and replacing the char. I don't exactly understand what return 1 does in this case. From what I am understanding it "breaks" the loop? I was hoping somebody could give me an explanation on how it replaces only the first occurrence.
size_t str_replace_all(char s[], int oldc, int newc)
{
size_t i;
size_t count = 0;
for (i=0; s[i]!='\0'; i++)
{
if (s[i] == (char)oldc)
{
s[i] = (char)newc;
count++;
}
}
return count;
}
int str_replace_first(char s[], int oldc, int newc)
{
size_t i;
for (i=0; s[i]!='\0'; i++)
{
if (s[i] == (char)oldc)
{
s[i] = (char)newc;
return 1; /* What exactly does this do? */
}
}
return 0;
}
return 1 escapes the function and returns a 1 to whatever has called it. return effectively escapes any function when it is called, this can be used in many applications to exit a function before it is 'complete'.
In this case:
int str_replace_first(char s[], int oldc, int newc)
{
size_t i;
for (i=0; s[i]!='\0'; i++)
{
if (s[i] == (char)oldc)
{
s[i] = (char)newc;
return 1; /* What exactly does this do? */
}
}
return 0;
}
The loop continues until it finds a character that matches oldc then replaces it with newc, then exits immediately before continuing on again. So as soon as it finds a match it will replace it then exit.
Here in str_replace_first when
s[i] == (char)oldc
condition becomes true in the loop, then then that character(old character) is replaced by the new one. and then return 1 returns the control to the calling function with a value of 1.(i.e neither the loop nor the function continues further).
1 was returned to mark that only 1 character was replaced.

Struggling to figure out how to write a certain function

I've been trying for quite a while now to write a function in my C program which will perform a task if a given array does not contain a certain letter, otherwise if the array does contain this letter, another function is called and the program continues on elsewhere.
Here is an example of one such function I attempted:
int Asterisk(){
int v;
for(v=0; v<sizeof Mask; v++){
if(Mask[v] != '*'){
return 1;
}
else{
return 0;
}
}
}
As you can see, this function returns 1 when
Mask[0] != '*'
I can't figure out how to check every element of the array before returning a value, rather than just checking the first element.
Any help/guidance would be much appreciated!
Try the following
int Asterisk()
{
int i = 0;
while ( i < sizeof Mask && Mask[i] != '*' ) ++i;
return i == sizeof Mask;
}
Though as for me I would write the function such a way that if an asterisk is present in the array then the function returns 1.
int Asterisk()
{
int i = 0;
while ( i < sizeof Mask && Mask[i] != '*' ) ++i;
return i != sizeof Mask;
}
and in the caller use it like
if ( !Asterisk() ) { /* do something */ }
That is if an asterisk is present in the array then the function returns 1 otherwise returns 0.
If the character array contains strings then you could simply use standard C function strchr declared in header <string.h>
By array, you mean a simple string ? If it that case, you just need to write a function taking a string and the letter to find and return 0 if the string doesn't contain this letter else 1 at the first occurrence of the letter.
int Asterisk()
{
int v;
bool exists = false;
for(v=0; v<sizeof Mask; v++){
if(Mask[v] != '*'){
exists = true;
break;
}
}
return exists;
}

Remove substring of string

So i was doing some coding exercice on Talentbuddy (for those who know), and i cant get why i cant finish this one.
The exercice is removing a substring from a string, given as input the string, the position P where beginning to remove characters and N the number of characters needed to be remove.
Here is what i've done :
#include <stdio.h>
#include <unistd.h>
void remove_substring(char *s, int p, int n)
{
int idx;
idx = -1;
while (s[++idx] != '\0')
write(1, &s[idx == p - 1 ? idx + n : idx], 1);
}
When the input is "abcdefghi", P = 9 and N = 1, the result given is "abcdefgh" exactly the same as the one i get with my function. But TalentBuddy keep saying me that my output is wrong and i dont thing he (talentbuddy) is wrong.
Maybe there is a blank space or something between the "h" and the '\0'.
But i cant figure it cause when i add another write(1, "END", 3) at the end it appears like "abcdefghEND".
If the question is exclusively for strings( NULL Terminated )
Why can't this be as simple as this, unless it is a homework.
void removesubstr( const char *string, const char *substring )
{
char *p = strstr(string, substring);
if(p)
{
strcpy(p,p+strlen(substring));
}
}
Your problem is that you write something for every original index, even if it should be suppressed. What you write looks like abcdefgh, but it is abcdefgh<nul>, where the terminal doesn't render the <nul>.
You are mixing two methods here. Either filter out the removed substring:
void remove_substring(char *s, int p, int n)
{
int i = 0;
p--; /* convert to C-style index */
while (s[i] != '\0') {
if (i < p || i >= p + n) putchar(s[i]);
i++;
}
}
or skip the substring by jumping over it:
void remove_substring(char *s, int p, int n)
{
int i = 0;
int l = strlen(s);
while (i < l) {
if (i + 1 == p) {
i += n;
} else {
putchar(s[i++]);
}
}
}
You're trying to do a bit of both.
(I've avoided the awkward combination of prefix increment and starting at minus 1. And I've used putchar instead of unistd's write. And the termination by length is so you don't inadvertently jump beyond the terminating <nul>.)

remove a specified number of characters from a string in C

I can't write a workable code for a function that deletes N characters from the string S, starting from position P. How you guys would you write such a function?
void remove_substring(char *s, int p, int n) {
int i;
if(n == 0) {
printf("%s", s);
}
for (i = 0; i < p - 1; i++) {
printf("%c", s[i]);
}
for (i = strlen(s) - n; i < strlen(s); i++) {
printf("%c", s[i]);
}
}
Example:
s: "abcdefghi"
p: 4
n: 3
output:
abcghi
But for a case like n = 0 and p = 1 it's not working!
Thanks a lot!
A few people have shown you how to do this, but most of their solutions are highly condensed, use standard library functions or simply don't explain what's going on. Here's a version that includes not only some very basic error checking but some explanation of what's happening:
void remove_substr(char *s, size_t p, size_t n)
{
// p is 1-indexed for some reason... adjust it.
p--;
// ensure that we're not being asked to access
// memory past the current end of the string.
// Note that if p is already past the end of
// string then p + n will, necessarily, also be
// past the end of the string so this one check
// is sufficient.
if(p + n >= strlen(s))
return;
// Offset n to account for the data we will be
// skipping.
n += p;
// We copy one character at a time until we
// find the end-of-string character
while(s[n] != 0)
s[p++] = s[n++];
// And make sure our string is properly terminated.
s[p] = 0;
}
One caveat to watch out for: please don't call this function like this:
remove_substr("abcdefghi", 4, 3);
Or like this:
char *s = "abcdefghi";
remove_substr(s, 4, 3);
Doing so will result in undefined behavior, as string literals are read-only and modifying them is not allowed by the standard.
Strictly speaking, you didn't implement a removal of a substring: your code prints the original string with a range of characters removed.
Another thing to note is that according to your example, the index p is one-based, not zero-based like it is in C. Otherwise the output for "abcdefghi", 4, 3 would have been "abcdhi", not "abcghi".
With this in mind, let's make some changes. First, your math is a little off: the last loop should look like this:
for (i = p+n-1; i < strlen(s); i++) {
printf("%c", s[i]);
}
Demo on ideone.
If you would like to use C's zero-based indexing scheme, change your loops as follows:
for (i = 0; i < p; i++) {
printf("%c", s[i]);
}
for (i = p+n; i < strlen(s); i++) {
printf("%c", s[i]);
}
In addition, you should return from the if at the top, or add an else:
if(n == 0) {
printf("%s", s);
return;
}
or
if(n == 0) {
printf("%s", s);
} else {
// The rest of your code here
...
}
or remove the if altogether: it's only an optimization, your code is going to work fine without it, too.
Currently, you code would print the original string twice when n is 0.
If you would like to make your code remove the substring and return a result, you need to allocate the result, and replace printing with copying, like this:
char *remove_substring(char *s, int p, int n) {
// You need to do some checking before calling malloc
if (n == 0) return s;
size_t len = strlen(s);
if (n < 0 || p < 0 || p+n > len) return NULL;
size_t rlen = len-n+1;
char *res = malloc(rlen);
if (res == NULL) return NULL;
char *pt = res;
// Now let's use the two familiar loops,
// except printf("%c"...) will be replaced with *p++ = ...
for (int i = 0; i < p; i++) {
*pt++ = s[i];
}
for (int i = p+n; i < strlen(s); i++) {
*pt++ = s[i];
}
*pt='\0';
return res;
}
Note that this new version of your code returns dynamically allocated memory, which needs to be freed after use.
Here is a demo of this modified version on ideone.
Try copying the first part of the string, then the second
char result[10];
const char input[] = "abcdefg";
int n = 3;
int p = 4;
strncpy(result, input, p);
strncpy(result+p, input+p+n, length(input)-p-n);
printf("%s", result);
If you are looking to do this without the use of functions like strcpy or strncpy (which I see you said in a comment) then use a similar approach to how strcpy (or at least one possible variant) works under the hood:
void strnewcpy(char *dest, char *origin, int n, int p) {
while(p-- && *dest++ = *origin++)
;
origin += n;
while(*dest++ = *origin++)
;
}
metacode:
allocate a buffer for the destination
decalre a pointer s to your source string
advance the pointer "p-1" positions in your source string and copy them on the fly to destination
advance "n" positions
copy rest to destination
What did you try? Doesn't strcpy(s+p, s+p+n) work?
Edit: Fixed to not rely on undefined behaviour in strcpy:
void remove_substring(char *s, int p, int n)
{
p--; // 1 indexed - why?
memmove(s+p, s+p+n, strlen(s) - n);
}
If your heart's really set on it, you can also replace the memmove call with a loop:
char *dst = s + p;
char *src = s + p + n;
for (int i = 0; i < strlen(s) - n; i++)
*dst++ = *src++;
And if you do that, you can strip out the strlen call, too:
while ((*dst++ = *src++) != '\0);
But I'm not sure I recommend compressing it that much.

Resources