Recursively removing duplicate characters in a string - c

I'm trying to create a recursive function which removes the consecutive duplicate characters from a string. It works fine except the first few characters. For example if my input is MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL or something like this, output is MMuOKLE OL. As you can see except for the first two M's it works fine. How can I make this work for the first part too?
Here is my code:
#include <stdio.h>
char* remove_duplicates (char* str){
if(*(str+1)!='\0'){
if(*str==*(str+1)){
*(str+1)=*(str+2);
remove_duplicates(str+1);
}
remove_duplicates(str+1);
}
return str;
}
int main()
{
char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
printf("OLD: |%s|\n", sample);
printf("NEW: |%s|\n", remove_duplicates(sample));
return 0;
}

Here you are.
#include <stdio.h>
char * remove_duplicates( char *s )
{
if ( *s )
{
if ( *s == *( s + 1 ) )
{
*( s + 1 ) = *( s + 2 );
remove_duplicates( s + 1 );
remove_duplicates( s );
}
else
{
remove_duplicates( s + 1 );
}
}
return s;
}
int main(void)
{
char s[] = "MMMMMuuuuuOOOOOKKKKLLLEE";
remove_duplicates( s );
puts( s );
return 0;
}
The program output is
MuOKLE

I did it this way:
#include <stdio.h>
char* remove_duplicates(char* str)
{
if (*str)
{
char* dest = remove_duplicates(str + 1);
str = (*str == *dest) ? dest : ((*(dest - 1) = *str), (dest - 1));
}
return str;
}
int main()
{
char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
char sample2[] = "AA";
printf("OLD: |%s|\n", sample);
printf("NEW: |%s|\n", remove_duplicates(sample));
printf("OLD: |%s|\n", sample2);
printf("NEW: |%s|\n", remove_duplicates(sample2));
return 0;
}
Output
OLD: |MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL|
NEW: |MuOKLE OL|
OLD: |AA|
NEW: |A|

Thank you all for your help. I walked through my code on paper as you said and realised the problem is it doesn't compare the first and last M.
I add a new if statement if(*str==*(str-1)) *(str)=*(str+1); and it works now.
Now function is:
char* remove_duplicates (char* str){
if(*(str+1)!='\0'){
if(*str==*(str+1)){
*(str+1)=*(str+2);
remove_duplicates(str+1);
}
remove_duplicates(str+1);
}
if(*str==*(str-1)) *(str)=*(str+1);
return str;
}

I am here just adding the recursive function (language: C++) and not the entire code.
void removeConsecutiveDuplicates(char input[]) {
if(input[0] == '\0' || input[1]=='\0') return;
if(input[0]!=input[1]) return removeConsecutiveDuplicates(input+1);
else
{
for(int i=1;i<=strlen(input);i++)
{
input[i-1] = input[i];
}
return removeConsecutiveDuplicates(input);
}
return;
}

Recursion is too complicated I think.
Lets start with 2 cursor at the begining of the str
First a loop on the string.
While we don't reach the end *p of the string look forward p++
while (*p++) {
if (*p == *current)
continue;
If next char is the same as the current continue to search the next different char.
current++;
*current = *p;
When a different char is found just put it after current.
#include <stdio.h>
char* remove_duplicates (char* str){
char *p = str;
char *current = p;
while (*p++) {
if (*p == *current)
continue;
current++;
*current = *p;
}
return str;
}
int main()
{
char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
printf("OLD: |%s|\n", sample);
printf("NEW: |%s|\n", remove_duplicates(sample));
printf("NEW: |%s|\n", remove_duplicates(""));
return 0;
}
OLD: |MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL|
NEW: |MuOKLE OL|
NEW: ||
Detail with AAAB
c for current
p
v
AAAB0
^
c
p
v
AAAB0
^
c
p
v
AAAB0
^
c
p
v
ABAB0
^
c
p
v
ABAB0
^
c
p
v
ABAB0
^
c
p
v
AB0B0
^
c
We get AB

Related

Why my returned value of strchr is ignored?

I have to make a function, that will code my sentence like this: I want to code all words with an o, so for example I love ice cream becomes I **** ice cream.
But my function ignores the result of strchr. And I don't know why.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define LEN 1000
char *Shift(char *str, char *let) {
const char *limits = " ,-;+.";
char copy[LEN];
strcpy(copy, str);
char *p;
char *ptr;
ptr = strtok(copy, limits);
for (int j = 0; ptr != NULL; ptr = strtok(NULL, limits), ++j) {
int len = 0;
if (strchr(ptr, let) != NULL) {
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
}
}
return str;
}
int main() {
char *s = Shift("I love my cocktail", "o");
puts(s);
}
Expected output is: I **** my ********
but I've got just printed the original string
For starters the function strchr is declared like
char *strchr(const char *s, int c);
that is its second parameter has the type int and the expected argument must represent a character. While you are calling the function passing an object of the type char * that results in undefined behavior
if (strchr(ptr, let) != NULL) {
It seems you mean
if (strchr(ptr, *let) != NULL) {
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior and this code snippet
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
tries to change the string literal passed to the function
char *s = Shift("I love my cocktail", "o");
And moreover in this statement
p[i] = "*";
you are trying to assign a pointer of the type char * to a character. At least you should write
p[i] = '*';
If you want to change an original string you need to store it in an array and pass to the function the array instead of a string literal. For example
char s[] = "I love my cocktail";
puts( Shift( s, "o" ) );
Pay attention to that there is no great sense to declare the second parameter as having the type char *. Declare its type as char.
Also the function name Shift is confusing. You could name it for example like Hide or something else.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
char * Hide( char *s, char c )
{
const char *delim = " ,-;+.";
for ( char *p = s += strspn( s, delim ); *p; p += strspn( p, delim ) )
{
char *q = p;
p += strcspn( p, delim );
char *tmp = q;
while ( tmp != p && *tmp != c ) ++tmp;
if ( tmp != p )
{
for ( ; q != p; ++q ) *q = '*';
}
}
return s;
}
int main( void )
{
char s[] = "I love my cocktail";
puts(s);
puts( Hide( s, 'o' ) );
}
The program output is
I love my cocktail
I **** my ********
The for loop
for ( ; q != p; ++q ) *q = '*';
within the function can be rewritten as a call of memset
memset( q, '*', p - q );
There are multiple problems:
copying the string to a fixed length local array char copy[LEN] will cause undefined behavior if the string is longer than LEN-1. You should allocate memory from the heap instead.
you work on a copy of the string to use strtok to split the words, but you do not use the correct method to identify the parts of the original string to patch.
you should pass a character to strchr(), not a string.
patching the string with p[i] = "*" does not work: the address of the string literal "*" is converted to a char and stored into p[i]... this conversion is meaningless: you should use p[i] = '*' instead.
attempting to modify a string literal has undefined behavior anyway. You should define a modifiable array in main and pass the to Shift.
Here is a corrected version:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *Shift(char *str, char letter) {
const char *limits = " ,-;+.";
char *copy = strdup(str);
char *ptr = strtok(copy, limits);
while (ptr != NULL) {
if (strchr(ptr, letter)) {
while (*ptr != '\0') {
str[ptr - copy] = '*';
ptr++;
}
}
ptr = strtok(NULL, limits);
}
free(copy);
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
The above code still has undefined behavior if the memory cannot be allocated. Here is a modified version that operates in place to avoid this problem:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, char letter) {
char *ptr = str;
while ((ptr = strchr(ptr, letter)) != NULL) {
char *p = ptr;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
Note that you can also search for multiple characters at a time use strcspn():
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, const char *letters) {
char *ptr = str;
while (*(ptr += strcspn(ptr, letters)) != '\0') {
char *p = str;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my Xtabentun cocktail";
puts(Shift(s, "oOxX"));
return 0;
}

Recreate the strstr() function

Hello i am trying to make my own strstr() function and i can't figure out why it is returning a segmentation fault.I am trying to search a string within another string and then return a pointer to the first 'same' letter. Any help would be appreciated.
This is my code:
char* ms_search(char *Str1,char* Str2){
char* p = NULL;
int i,k=0,j = 0;
for(i = 0;i < ms_length(Str1); i++){
if(Str1[i] == Str2[k]){
if(k == 0){
p = &Str1[i];
j= i;
}
if(k == ms_length(Str2)){
break;
}
k++;
}
else{
if(Str1[i] == Str2[0]){
p = &Str1[i];
k=1;
j= i;
}
else{
j=0;
k = 0;
p = NULL;
}
}
}
if(p != NULL){
Str1[ms_length(Str2)+1] = '\0';
}
return &Str1[j];
}
int main(){
int i;
char* p2;
char* p="lolaaa";
char* p1= "aaa";
//char ar2[] = "aaa4";
//ms_copy(p,p1);
//printf("%s",p);
//ms_nconcat(p,p1,3);
//if(ms_ncompare(p,p1,3) == 1) printf("einai idia");
p2 = ms_search(p,p1);
printf("%s",p2);
return 0;
}
Hello i am trying to make my own strstr()
First of all you have to follow the C standard.
The C89/C99 prototype is:
char *strstr(const char *s1, const char *s2);
Standard strstr() function will NOT change the passed buffers.
The functionality is described as:
strstr() function locates the first occurrence in the string pointed to by s1 of the sequence of characters (excluding the terminating null character) in the string pointed to by s2.
The strstr function returns a pointer to the located string, or a null pointer if the string is not found. If s2 points to a string with zero length, the function returns s1.
In standard C, this can be implemented as:
#include <string.h> /* size_t memcmp() strlen() */
char *strstr(const char *s1, const char *s2)
{
size_t n = strlen(s2);
while(*s1)
if(!memcmp(s1++,s2,n))
return (char *) (s1-1);
return 0;
}
The standalone implementation is given below:
#include <stdio.h>
char *strstr1(const char *str, const char *substring)
{
const char *a;
const char *b;
b = substring;
if (*b == 0) {
return (char *) str;
}
for ( ; *str != 0; str += 1) {
if (*str != *b) {
continue;
}
a = str;
while (1) {
if (*b == 0) {
return (char *) str;
}
if (*a++ != *b++) {
break;
}
}
b = substring;
}
return NULL;
}
int main (void)
{
char string[64] ="This is a test string for testing strstr";
char *p;
p = strstr1 (string,"test");
if(p)
{
printf("String found:\n" );
printf ("First occurrence of string \"test\" in \"%s\" is:\n%s", string, p);
}
else
{
printf("String not found!\n" );
}
return 0;
}
Output:
String found:
First occurrence of string "test" in "This is a test string for testing strstr" is:
test string for testing strstr
Your standalone strstrl is correct.
I have my preferences, and you have yours.
Neither is perfect.
You prefer
if ( *b == 0 ) {
return (char *) s1;
}
I prefer
if ( ! *b ) return (char *) s1;
You prefer
str += 1;
I prefer
str++;
You prefer
while (1)
I prefer
for (;;)
If I rewrite your strstrl with my preferences, we get
char *strstr1(const char *str, const char *substring)
{
const char *a, *b = substring;
if ( !*b ) return (char *) str;
for ( ; *str ; str++) {
if (*str != *b) continue;
a = str;
for (;;) {
if ( !*b ) return (char *) str;
if (*a++ != *b++) break;
}
b = substring;
}
return NULL;
}
Note that this version has the same snippet
if ( ! *b ) return (char *) str;
in two locations. Can we rearrange to do that test only once?
Note how we do two tests when lead character matches
if ( *str != *b )
and again later for the same lead char
a = str ; if ( *a++ != *b++)
Can we rearrange that to do a single test?
My rewrite of your standalone strstr is below. It might not be
your style, but it is in many ways similar to your standalone strstr.
My rewrite is shorter and, I want to believe, easier to understand.
char *strstr(const char *str, const char *substring)
{
const char *a = str, *b = substring;
for (;;) {
if ( !*b ) return (char *) str;
if ( !*a ) return NULL;
if ( *a++ != *b++) { a = ++str; b = substring; }
}
}

Reverse String function in C without library functions

This is my task:
Realize function that reverses null terminated string. The prototype of the function is void Reverse(char *ptr);. Do not use standard library functions.
This is my code for now:
void Reverse(char *ptr) {
char *newString;
char ch = *ptr;
unsigned int size = 0;
for (int i = 1; ch != '\0'; i++) {
ch = *(ptr + i);
size++;
}
newString = (char*)malloc(size);
for (int left = 0, right = size - 1; left < size; left++, right--) {
*(newString + left) = *(ptr + right);
}
printf("%s", newString);
printf("\n");
}
It reverses the string and saves it in the newString
My first problem is that when I print the newString to see if the functions works the string is reversed, but after it there are some symbols.
For example:
If I have char *str = "hello"; and Reverse(str); in the main method
the result of printf("%s", newString) will be olleh****.
But if change the
newString = (char*)malloc(size); to
newString = (char*)malloc(1); it works fine.
My second problem is that I don't know how to save the newString into the given one. I am using a new String because the given one can't be changed.
For starters it is better to declare the function like
char * Reverse( char *ptr );
^^^^^^
because standard C string functions usually return pointers to destination strings.
The function should reverse the original string. It may not create a dynamic string because the caller of the function will be unable to free it provided that the function has return type void.
The function can look as it is shown in the following demonstrative program.
#include <stdio.h>
char * Reverse( char *ptr )
{
char *first = ptr, *last = ptr;
while ( *last ) ++last;
if ( first < last )
{
for ( ; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return ptr;
}
int main( void )
{
char s[] = "Hello World!";
puts( s );
puts( Reverse( s ) );
return 0;
}
Its output is
Hello World!
!dlroW olleH
Take into account that you may not call the function like
puts( Reverse( "Hello World!" ) );
because string literals are immutable in C.
If you are going to declare the function like
void Reverse( char *ptr );
then just remove the return statement in the shown function. For example
#include <stdio.h>
void Reverse( char *ptr )
{
char *first = ptr, *last = ptr;
while ( *last ) ++last;
if ( first < last )
{
for ( ; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
}
int main( void )
{
char s[] = "Hello World!";
puts( s );
Reverse( s )
puts( s );
return 0;
}
If to use your approach with indices then the function can look like
#include <stdio.h>
void Reverse( char *ptr )
{
size_t size = 0;
while ( *( ptr + size ) ) ++size;
if ( size != 0 )
{
for ( size_t left = 0, right = size - 1; left < right; left++, right-- )
{
char c = ptr[left]; // or char c = *( ptr + left ); and so on
ptr[left] = ptr[right];
ptr[right] = c;
}
}
}
int main( void )
{
char s[] = "Hello World!";
puts( s );
Reverse( s );
puts( s );
return 0;
}
In your loop to get the size, you're not counting the null terminator. So your newString is missing the null terminator as well. make sure to do newString = malloc(size + 1);, and to place the null terminator onto the end of newString.
You have several problems in your code:
you do not allocate enough space for the resulting string, you must allocate size+1 bytes and set the \0 terminator at the end of the string.
you only copy half the characters from ptr to newString.
you are not even supposed to allocate memory, since you cannot call any library functions. You should instead reverse the string in place.
Your test fails because modifying a string literal invokes undefined behavior. You should pass an initialized array as shown below.
Here is an improved version:
#include <stdio.h>
void Reverse(char *ptr) {
unsigned int left, right;
for (right = 0; *(ptr + right) != '\0'; right++) {
continue;
}
for (left = 0; left < right; left++, right--) {
char ch = ptr[left];
ptr[left] = ptr[right - 1];
ptr[right - 1] = ch;
}
}
int main(void) {
char buf[] = "Hello world";
Reverse(buf);
printf("%s\n", buf);
return 0;
}
It should print dlrow olleH.
Simple string reverse function without string.h library functions :
#include <stdio.h>
void reverse(char *str, int n);
int main()
{
char str[100];
int n;
printf("Enter a string\n");
scanf("%s",&str);
for( n = 0; str[n] != '\0'; n++)
{
}
reverse(str,n);
puts(str);
return 0;
}
void reverse(char *str,int n)
{
printf("Length = %d\n",n);
printf("Reversed :\n");
int i;
char ch;
for(i = 0; i<n/2; i++)
{
ch = str[i];
str[i] = str[n-i-1];
str[n-i-1] = ch;
}
}

Restarting while loop in c without integers

I'm trying to get this code to work, but I have no idea how to restart the inner while loop. How would I do it?
/*
* Return a pointer to the first occurrence of any character in <stop>
* in the given <string> or NULL if the <string> contains no characters
* in <stop>.
*****
* YOU MAY *NOT* USE INTEGERS OR ARRAY INDEXING.
*****
*/
char *find_any_ptr(char *string, char* stop) {
char *newstring = (char*)0;
while(*stop != '\0'){
while(*string != '\0') {
if(*string == *stop){
if(newstring < string || newstring != (char*)0){
string++;
}else{
newstring = string;
string++;
}
}
}
stop++;
}
return newstring; // placeholder
}
Use a temporary variable for string pointer, and use this temp variable instead inside the inner loop.
while(*stop != '\0'){
char *p = string;
while (*p != '\0') {
... /* use 'p' in place of 'string' */
}
stop++;
}
This is relatively simple using nothing but a character pointer to the string and a pointer to stop. For each character in your string, you compare against each character in stop, returning the character in string on match, or NULL if no match is found:
#include <stdio.h>
char *find_any_index(char string[], char stop[]) {
char *p = string;
char *sp = NULL;
while (*p)
{
sp = stop;
while (*sp)
{
if (*sp == *p)
return p;
sp++;
}
p++;
}
return NULL;
}
int main (int argc, char **argv) {
if (argc < 3) {
printf ("usage: %s string stoplist\n", argv[0]);
}
printf ("\n string: %s\n stop : %s\n\n", argv[1], argv[2]);
printf (" first char in string matching a char in stop: %s\n\n", find_any_index (argv[1], argv[2]));
return 0;
}
Output
$ ./bin/find_substr_str thisIsAstring mase
string: thisIsAstring
stop : mase
first char in string matching a char in stop: sIsAstring
Here is a demonstrative program that shows how the function can be written
#include <stdio.h>
char * find_any_ptr( const char *string, const char* stop )
{
const char *p, *q;
_Bool found = 0;
p = string;
do
{
q = stop;
while ( *q && *q != *p ) ++q;
} while ( !( found = *q ) && *++p );
return ( char * )( found ? p : NULL );
}
int main(void)
{
const char *p = find_any_ptr( "abc9de", "1234567890" );
if ( p ) puts( p );
return 0;
}
The program output is
9de
Only I would name the function find_any_char instead of find_any_ptr:)
This is my implementation:
#include <stdio.h>
#include <stdlib.h>
char * findany(char *string, char *stop) {
char * app;
//To avoid segmentation fault!
if (stop==NULL || string==NULL || !*stop || !*string)
return NULL;
do {
app=string;
while(*app!=0 && *app!=*stop)
app++;
stop++;
} while(*app==0 && *stop!=0);
return (*app!=0)?app:NULL;
}
int main(void)
{
char string[100];
char stop[100];
char * found;
for(;;) {
printf("Insert a string without spaces[q<Enter> to exit]: ");
scanf("%s",string);
if (!strcmp(string,"q"))
break;
printf("Insert the chars to search without spaces: ");
scanf("%s",stop);
printf("Searching any occurence of a char in \"%s\""
" inside \"%s\"\n",stop,string);
found=findany(string,stop);
printf("%s\n",(found!=NULL)?found:"NULL");
}
return 0;
}
I think that is better to use also the following way to implement the function findany():
char * _findany(char *string, char *stop) {
char * app; // to start the first loop
//To avoid segmentation fault!
if (stop==NULL || string==NULL || !*stop || !*string)
return NULL;
do {
app=stop;
while(*app!=0 && *app!=*string)
app++;
string++;
} while(*app==0 && *string!=0);
return (*app!=0)?(string-1):NULL;
}
You may observe the difference between the two functions adding the function _findany in the code above and to call the new function adding the following code after (or before) the printf in the main above.
found=_findany(string,stop);
printf("%s\n",(found!=NULL)?found:"NULL");

string parsing occurrence in c

I have a string as const char *str = "Hello, this is an example of my string";
How could I get everything after the first comma. So for this instance: this is an example of my string
Thanks
You can do something similar to what you've posted:
char *a, *b;
int i = 0;
while (a[i] && a[i] != ',')
i++;
if (a[i] == ',') {
printf("%s", a + i + 1);
} else {
printf("Comma separator not found");
}
Alternatively, you can take a look at strtok and strstr.
With strstr you can do:
char *a = "hello, this is an example of my string";
char *b = ",";
char *c;
c = strstr(a, b);
if (c != NULL)
printf("%s", c + 1);
else
printf("Comma separator not found");
Since you want a tail of the original string, there's no need to copy or modify anything, so:
#include <string.h>
...
const char *result = strchr(str, ',');
if (result) {
printf("Found: %s\n", result+1);
} else {
printf("Not found\n");
}
If you want ideas how to do it yourself (useful if you later want to do something similar but not identical), take a look at an implementation of strchr.
const char *result;
for(result = str; *result; result++)
if(*result == ',')
{
result++;
break;
}
//result points to the first character after the comma
After this code, result points to the string starting right after the comma. Or to the final '\0' (empty string), if there is no comma in the string.
You have the right idea, the following programs is one way to do it:
#include <stdio.h>
#include <string.h>
static char *comma (char *s) {
char *cpos = strchr (s, ',');
if (cpos == NULL)
return s;
return cpos + 1;
}
int main (int c, char *v[]) {
int i;
if (c >1 )
for (i = 1; i < c; i++)
printf ("[%s] -> [%s]\n", v[i], comma (v[i]));
return 0;
}
It produced the following output:
$ commas hello,there goodbye two,commas,here
[hello,there] -> [there]
[goodbye] -> [goodbye]
[two,commas,here] -> [commas,here]

Resources