Remove duplicates chars recursively - c

I'm trying to write a recursive function which remove all duplicate chars from a given string recursively.
For example "Hello world" -> "Helo wrd".
The limitations I have are:
No loops allowed.
No more arguments can be added to the original function (remove_duplicates).
No functions from string.h library allowed, although I'm allowed to write them recursively.
I'm allowed to use another auxiliary recursive functions.
The function I wrote so far works only for short strings, it calls the function too many times. Any recommendations how to make it more efficient?
void remove_duplicates3(char string[], int index)//(str,RecursiveStrlen(str, 0)-1)
{
int length = RecursiveStrlen(string + 1, 0);
if (string[index] == '\0' || index == 0)
{
return;
}
if (string[0] != string[index])
{
remove_duplicates3(string, index - 1);
}
else
{
BackspaceString(string, index);
remove_duplicates3(string, length - 1);
}
remove_duplicates3(string + 1, length - 1);
}
int RecursiveStrlen(char str[], int index)
{
if (str[index] == '\0')
return index;
return RecursiveStrlen(str, index + 1);
}
void BackspaceString(char string[],int index)//deletes one char from string in a specific index
{
if (string[index] == '\0')//end of string
return;
string[index] = string[index + 1];
BackspaceString(string, index + 1);
}

Pure recursive solution:
void remove_char(char string[], char c, int read_index, int write_index) {
if (string[read_index] == 0) {
string[write_index] = 0;
return;
}
if (c == string[read_index]) {
remove_char(string, c, read_index + 1, write_index);
} else {
string[write_index] = string[read_index];
remove_char(string, c, read_index + 1, write_index + 1);
}
}
void remove_duplicates(char string[], int index) {
if (string[index] != 0 && string[index + 1] != 0) {
remove_char(string, string[index], index + 1, index + 1);
remove_duplicates(string, index + 1);
}
}

If you can use a global variable to store the resultant string, you could do this:
char result[30]="";
char over[30]="";
int check(char *over, char c)
{
if(*over != '\0')
{
if(*over == c)
{
return 1; //exists
}
else
{
return check(over+1, c);
}
}
return 0; //doesn't exist
}
int strLen(char *str)
{
if(*str=='\0')
{
return 0;
}
return strLen(str+1)+1;
}
void remove_duplicates(char *str)
{
if(*str != '\0')
{
if(check(over, *str)==0)
{
int len=strLen(result);
result[len++]=*str;
result[len]='\0';
len=strLen(over);
over[len++]=*str;
over[len]='\0';
}
remove_duplicates(str+1);
}
}
The resultant string is stored in result and over is a string which will store the already encountered characters as a string. over is checked by the check() function against a character c to return 0 if c was not found in over.
check() checks the value of over to determine if its argument c is present in over.
remove_duplicates() will check each character in the input string str. If the character was not encountered before in str, it is added to the list of already encountered characters to over and also appended to the result string.
This goes on till the input string str is over.

If your string is having only ASCII characters -
int arr[256] = {0};
/*
* str - Input string
* presult - Pointer to the buffer contain result
*/
void remove_duplicates(char *str, char *presult)
{
if(*str != '\0')
{
if(arr[*str] == 0)
{
*presult = *str;
arr[*str] = 1;
remove_duplicates(str+1, presult+1);
}
remove_duplicates(str+1, presult);
}
}

Simple Recursive Solution
I originally wrote this function in Scheme, but have translated it into C for you.
/*
* #params
* src -> input string from which to remove duplicates
* dest -> output string (initially empty)
* iter -> elements visited (initially 0)
*/
void remove_Dups_recursively(char *src, char *dest, int iter){
if(strlen(src) <= 1){
dest = src;
return;
}
if(iter == strlen(src)){
return;
}
if(strchr(dest, src[iter]) == NULL){
dest[strlen(dest)] = src[iter];
iter++;
remov(src, dest, iter);
}
else{
iter++;
remov(src, dest, iter);
}
}

Related

I am trying to implent my own strpbrk function in C

The function is supposed to work similarly to the strpbrk function in C. When I run the code, I get a segmentation fault. I did a rubber duck debug yet couldn't figure out any problem with the code. I am using a gcc compiler on WSL. The main.h header file contains the function declaration char *_strpbrk(char *s, char *accept). Please what am I missing?
#include "main.h"
/**
* _strpbrk - searches the string s for any of a set of bytes
*
* #s: String to be searched
* #accept: Substring of bytes to search for
* Return: Return a pointer to the byte in s that matches one of the bytes in
* accept, or NULL if no such byte is found
*/
char *_strpbrk(char *s, char *accept)
{
int i, j, check = 0, position = 0;
i = 0;
while (*(s + i) != '\0')
{
for (j = 0; *(accept + j) != '\0'; j++) /* Check if character of s in focus is a character in accept. Break out of the for loop if true*/
{
if (*(s + i) == *(accept + j))
{
check = 1;
position = i;
break;
}
}
if (check == 1) /* check if the character of s in focus was found to be in accept. Break out of the while loop if true */
{
break;
}
i++;
}
if (position == 0) /* Check for return value. Return null if whole string traversed*/
{
return ('\0');
}
else
{
return (s + position);
}
}
Forgot to mention that the gcc flags -Wall -pedantic -Werror -Wextra -std=gnu89 are used during compilation.
Do not use _ as a prefix.
This task shows how useful is use of the functions
char *mystrchr(const char *str, const char c)
{
while(*str)
{
if(*str == c) return (char *)str;
str++;
}
return NULL;
}
char *mystrbrk(const char *str, const char *brk)
{
while(*str)
{
if(mystrchr(brk, *str)) return (char *)str;
str++;
}
return NULL;
}
Now your code:
return ('\0');
This is not returning pointer. You are lucky as '\0' will convert to pointer NULL. Basically, it is very hard to analyze as you overthink many things.
#include "main.h"
/**
* _strpbrk - searches the string s for any of a set of bytes
*
* #s: String to be searched
* #accept: Substring of bytes to search for
* Return: Return a pointer to the byte in s that matches one of the bytes in
* accept, or NULL if no such byte is found
*/
char *_strpbrk(char *s, char *accept)
{
int i, j, check = 0, position = 0;
i = 0;
while (*(s + i) != '\0')
{
for (j = 0; *(accept + j) != '\0'; j++) /* Check if character of s in focus is a character in accept. Break out of the for loop if true*/
{
if (*(s + i) == *(accept + j))
{
check = 1;
position = i;
break;
}
}
if (check == 1) /* check if the character of s in focus was found to be in accept. Break out of the while loop if true */
{
break;
}
i++;
}
if (position == 0) /* Check for return value. Return null if whole string traversed*/
{
return ('\0');
}
else
{
return (s + position);
}
}

I cant solve chaning characters

Required use of the function that returns the length of the string.
Write a function that receives two character chains (n1, n2). The function of the function is to check if the string n2 is the subscription of the string n1. The function returns the index of the first occurrence of the string n2 in the string n1 (if n2 is the string n1) or -1 (if n2 is not the string n1). assumption: the inscription n2 is shorter than the inscription n1.
Example: inscription n1: "Computer" inscription n2: "er" Function returns: 6
i did it and it work
#include <stdio.h>
#define LIMIT 50
char * string_in(char *string, char *substring);
char * get(char *string, int n);
int main(void)
{
// test string_in()
char string[LIMIT];
char substring[LIMIT];
char *substr_loc;
printf("Enter a string: ");
get(string, LIMIT);
while (string[0] != '\0')
{
printf("Enter a substring to look for: ");
get(substring, LIMIT);
substr_loc = string_in(string, substring);
if (substr_loc == NULL)
printf("%s not in %s\n", substring, string);
else
printf("%s found in %s at index %lu\n",
substring, string, substr_loc - string);
printf("Enter a string (empty line to quit): ");
get(string, LIMIT);
}
puts("Bye");
return 0;
}
char * string_in(char *string, char *substring)
{
// checks if substring is in string
// returns pointer to first location of substring
// in string or NULL if substring not in string
int i;
while (*string != '\0')
{
i = 0;
// check for substring at current location
while (*(string + i) == *(substring + i))
{
i++;
// if next char in substring is null, then match
// is found. return current location
if (*(substring + i) == '\0')
return string;
}
string++;
}
// no match
return NULL;
}
char * get(char *string, int n)
{
// wrapper for fgets that replaces first newline with null
char *return_value = fgets(string, n, stdin);
while (*string != '\0')
{
if (*string == '\n')
{
*string = '\0';
break;
}
string++;
}
return return_value;
}
the next step is
Write a part of the program that will replace all occurrences of the n2 string in the string n1 with the string (the character '*'). Use the function from a task point. Please tell me how to write this function
Example: n1: "Spectacle" n2: "c" string n1 after change. "Spe*ta*le"
void function(char * get, char * string_in)
int i = 0;
for ( i = 0; get[i]=!'\0';i++){
if (get[i] == string_in[o]
get[i] = '*';}
dont work;<
it is a bit more complicated if you the string which replaces another string is longer. Here you have simple functions.
size_t strstrIndex(const char *heap, const char *needle) // returns SIZE_MAX if not found
{
char *result = strstr(heap,needle);
return result ? result - heap : SIZE_MAX;
}
char *replace(const char *heap, const char *needle, const char *rep)
{
size_t pos = 0, nocc = 0;
size_t len = strlen(heap), nlen = strlen(needle), rlen = strlen(rep);
char *string;
char *wstr = (char *)heap;
while((pos = strstrIndex(wstr, needle)) != SIZE_MAX)
{
nocc++;
wstr += pos + nlen;
}
string = calloc(1, len + ((rlen > nlen) ? (rlen - nlen) * nocc : 0) + 1);
if(string)
{
wstr = string;
while((pos = strstrIndex(heap, needle)) != SIZE_MAX)
{
strncpy(wstr, heap, pos);
heap += pos + nlen;
wstr += pos;
strcpy(wstr, rep);
wstr += rlen;
}
if(*heap)
{
strcpy(wstr, heap);
}
}
return string;
}
int main()
{
char *heap = "Spectaclec";
printf("%s\n", replace(heap, "c", "*"));
printf("%s\n", replace(heap, "c", "*****"));
printf("%s\n", replace("ccSpecctaccleccX", "cc", "*****"));
}
This task is easy if you use the functions that comes with the C library:
void ReplaceString(char *pTarget, const char *pPattern)
{
char *p;
size_t PatternLength = strlen(pPattern);
// for all occurances of the pattern..
while (p = strstr(pTarget, pPattern))
{
// The function strstr found an occurance of the pattern.
// So it must be sufficient space in the target starting at the pointer p..
// replace the characters in the target
memset(p, '*', PatternLength);
}
}
If you should avoid functions for some academic purposes, you can implement your own versions of strlen, strstr, and memset. Your example shows a function string_in that looks like such version of `strstr.

C - function to search a substring.. need to simplify

To begin with, I am a novie in C. So please bear with me.
I am referring a tutorial on pointers, which asked me to write a function to find a substring (and if found, the function should return the location of the substring in the original string).
I wrote the code and it works perfectly, the only problem is its too lengthy and I was wondering, if there was a way I can make it less complex.
Following is the code -
*s - contains the base address of the string,
*t - contains the base address of the substring,
num - contains the number of characters in substring (calculated by using strlen)
char *search(char *s, char *t, int num)
{
int i = 0, flag = 0;
/* increment str1 until first matching character (of substring) is encountered */
while((*s != *t) && (*s != '\0'))
{
s++;
}
if(*s == *t)
{
/* comparing the str and substr, and incrementing flag.. if flag is incremented num times, the strings match */
while((*(s+i) == *(t+i)) && (i<num))
{
flag++;
i++;
}
}
if(flag == num)
return s;
else
/* recursive function - str is incremented by 1, to start new comparison */
return search((s+1), t, num);
}
Any help would be appreaciated. Thank you, in advance.
I don't think you need to special-case finding the first character:
char * search(char *s, char *t, int num)
{
while (*s) {
int i;
for (i = 0; i < num; i++) {
if (!s[i]) {
return NULL;
}
if (s[i] != t[i]) {
break;
}
}
if (i == num) {
return s;
}
s++;
}
return NULL;
}
I think it's alread done quite well, just a few litte things:
char * search(char *s, char *t, int num)
{
int i = 0, flag = 0;
/* increment str1 until first matching character (of substring) is encountered */
/* It can be written on one line: */
while((*s != *t) && (*s != '\0')) s++;
/* comparing the str and substr, and incrementing flag.. if flag is incremented num times, the strings match */
/* The if is not needed, a for loop is shorter: */
for(; (*(s+i) == *(t+i)) && (i<num); flag++, i++);
if(flag == num)
return s;
else
/* recursive function - str is incremented by 1, to start new comparison */
return search((s+1), t, num);
}
You can use the strstr() function
return strstr(s, t);
http://www.tutorialspoint.com/c_standard_library/c_function_strstr.htm

Does a string contains a word from a list

I have a string and an array of keywords. If the string contains one of the keywords on the list, I want to check if the keyword is the only element of this string. If it's not, I want to return an error. Last thing, the string will always end with \n.
My keyword array is the following:
const char * keywordsTable[] =
{
"INIT",
"BEGIN",
"END",
"ROUTINES",
"ENDROUTINES",
"ENDWHEN",
"WHEN",
"WHILE"
};
For instance if my string is "BEGIN\n", everything is fine. If my string is "BEGIN FOO\n" or "FOO BEGIN\n", I have to return an error. Finally if my string is "BEGINFOO\n", everything is fine. (error code is 1, else it's 0)
I've tried something (I don't know how to proceed):
int CheckKeyword(char * str)
{
int nKeywords = sizeof(keywordsTable) / sizeof(keywordsTable[0]);
char * strTok = NULL;
char * keywrdWithLF = malloc(20);
// I don't want to check for the last two keywords nor the first
for (int i = 1; i < nKeywords - 2; i++)
{
strcpy_s(keywrdWithLF, 20, keywordsTable[i]);
strcat_s(keywrdWithLF, 20, "\n");
strTok = strstr(str, keywrdWithLF);
// If my string contains a keyword
if (strTok != NULL)
{
// If the string contains other characters... and I'm stuck
if (strcmp(str, keywrdWithLF))
{
}
else
{
free(keywrdWithLF);
return 1;
}
}
}
free(keywrdWithLF);
return 0;
}
Thank you in advance (please don't complain bout my indent style, I have to use Whitesmith indent) !
int CheckKeyword(char * str)
{
int nKeywords = sizeof(keywordsTable) / sizeof(keywordsTable[0]);
char * strTok = NULL;
for (int i = 1; i < nKeywords - 2; i++)
{
if(NULL!=(strTok = strstr(str, keywordsTable[i])))
{
int len = strlen(keywordsTable[i]);
if(strTok == str)
{
if(str[len]==' ' || str[len]=='\t')
return 1;
}
else
{
if((strTok[-1]==' ' || strTok[-1]=='\t') && isspace(strTok[len]))//isspace in <ctype.h>
return 1;
}
}
}
return 0;
}
Perhaps another method?
int CheckKeyword(char * str)
{
int rCode=0;
int nKeywords = sizeof(keywordsTable) / sizeof(keywordsTable[0]);
char *keyword;
char *cp = keywordsTable;
I assume that since str is defined as "char * str" and not "const char * str", it is OK to modify the input string. Hence, why not just eliminate the '\n' problem from the equation?
/* Elininate the newline character from the end of the string. */
if((cp = strchr(str, '\n'))
*cp = \0;
// I don't want to check for the last two keywords nor the first.
nKeywords -= 3;
++keyword;
/* Loop through the keywords. */
while(nKeywords)
{
// "I want to check if the keyword is the only element of this string."
// "If it's not, I want to return an error."
if((cp=strstr(str, keyword))
{
/* Check for stuff prior to the keyword. */
if(cp != str)
rCode=1;
/* Check for stuff after the keyword. */
// Finally if my string is "BEGINFOO\n", everything is fine.
if(' ' == str[strlen[keyword])
rCode=1;
if(strcmp(cp, keyword))
rCode=1
break;
}
++keyword;
--nKeywords;
}
return(rCode);
}

Tokenize String by using pointer

I'm trying to tokenize a sting and here is my attempt.
char new_str[1024];
void tokenize_init(const char str[]){//copy the string into global section
strcpy(new_str,str);
}
int i = 0;
char *tokenize_next() {
const int len = strlen(new_str);
for(; i <= len; i++) {
if ( i == len) {
return NULL;
}
if ((new_str[i] >= 'a' && new_str[i] <= 'z') ||
(new_str[i] >= 'A' && new_str[i] <= 'Z')) {
continue;
}else {
new_str[i] = '\0';
i = i + 1;
return new_str;
}
}
return NULL;
}
//main function
int main(void) {
char sentence[] = "This is a good-sentence for_testing 1 neat function.";
printf("%s\n", sentence);
tokenize_init(sentence);
for (char *nt = tokenize_next();
nt != NULL;
nt = tokenize_next())
printf("%s\n",nt);
}
However, it just print out the first word of the sentence(which is "This") and then stop. Can someone tell me why? My guess is my new_str is not persisent and when the main function recall tokenize_next() the new_str become just the first word of the sentence. Thanks in advance.
The reason that it only prints out "This" is because you iterate to the first non-letter character which happens to be a space, and you replace this with a null terminating character at this line:
new_str[i] = '\0';
After that, it doesn't matter what you do to the rest of the string, it will only print up to that point. The next time tokenize_next is called the length of the string is no longer what you think it is because it is only counting the word "This" and since "i" has already reached that amount the function returns and so does every successive call to it:
if ( i == len)
{
return NULL;
}
To fix the function you would need to somehow update your pointer to look past that character on the next iteration.
However, this is quite kludgy. You are much better off using one of the mentioned functions such as strtok or strsep
UPDATE:
If you cannot use those functions then a redesign of your function would be ideal, however, per your request, try the following modifications:
#include <string.h>
#include <cstdio>
char new_str[1024];
char* str_accessor;
void tokenize_init(const char str[]){//copy the string into global section
strcpy(new_str,str);
str_accessor = new_str;
}
int i = 0;
char* tokenize_next(void) {
const int len = strlen(str_accessor);
for(i = 0; i <= len; i++) {
if ( i == len) {
return NULL;
}
if ((str_accessor[i] >= 'a' && str_accessor[i] <= 'z') ||
(str_accessor[i] >= 'A' && str_accessor[i] <= 'Z')) {
continue;
}
else {
str_accessor[i] = '\0';
char* output = str_accessor;
str_accessor = str_accessor + i + 1;
if (strlen(output) <= 0)
{
str_accessor++;
continue;
}
return output;
}
}
return NULL;
}
//main function
int main(void) {
char sentence[] = "This is a good-sentence for_testing 1 neater function.";
printf("%s\n", sentence);
tokenize_init(sentence);
for (char *nt = tokenize_next(); nt != NULL; nt = tokenize_next())
printf("%s\n",nt);
}

Resources