-3

So given a string, im trying to find the repeated chars (or letters) and then print them out. I've tried everything and below is my code:

void char_counter(char *str){ int n = strlen(str); int i =0; int j; char substring[] ={0}; for(i; i < n; i++){ j = i + 1; if(str[i]== str[j]){ substring[i] = str[i]; printf("%c\n", substring[i]); } } } 

I know that in python, this would be something as simple as:

def char_counter_dup(str): char_dict = {} list_of_duplicates =[] for idx, letter in enumerate(str): if letter not in char_dict: char_dict[letter] = 1 list_of_duplicates.append(letter) else: char_dict[letter] +=1 return list_of_duplicates, char_dict my_string = "acabcabcff" print("List of duplicates is: {}".format(char_counter_dup(my_string)[0])) 

Since there is not equivalent of if not in in C, how do i go about it?

I tried using pointers, while loops, double indexing.

9
  • 1
    char substring[] ={0}; the size of your array is 1, you don't have space to store n characters in it. Commented Feb 10, 2024 at 18:50
  • 1
    there is not equivalent of if not in in C, there is if (!strchr(char_dict, letter)) Commented Feb 10, 2024 at 18:51
  • 2
    What is a "repeated character"? Take for example the string "Follow"... Are both the o and l characters repeated? Only the l? Commented Feb 10, 2024 at 18:52
  • @Someprogrammerdude the comparison to Python's in suggest that the o's in "follow" would be considered repeated. As does the output from that Python snippet. Commented Feb 10, 2024 at 18:54
  • 1
    There is a lack of clarity here. "So given a string, im trying to find the repeated chars (or letters) and then print them out." What is a "letter" here? Are ASCII characters sufficient, or does the broader class of Unicode letters need to be handled? Does OP desire to only print the duplicate letters, or does OP desire to build a list of duplicates (as in the Python code)? From the Python example it seems that "repeated" means duplicates from the input string, not only letters that are sequentially repeated. Commented Feb 10, 2024 at 19:58

2 Answers 2

2

You could use memchr to find if a character occurs in the remainder of the string, replicating the functionality of in in Python, but algorithmically, you're better off sorting the string first and then looping over it, because then all repeated characters will be contiguous.

Caveat: I'm not testing to ensure strdup succeeded in the following.

#include <stdlib.h> #include <string.h> #include <stdio.h> int compare_chars(const void *a, const void *b) { char c = *(char *)a; char d = *(char *)b; return c == d ? 0 : c < d ? -1 : 1; } int main(void) { const char *s = "dacabcabcff"; char *s2 = strdup(s); qsort(s2, strlen(s2), 1, compare_chars); char last_char = '\0'; for (size_t i = 0; s2[i]; i++) { if (s2[i] == last_char) { printf("%c\n", s2[i]); // Skip to the next unique character // to avoid printing repeated characters // more than once. while (s2[i] && s2[i] == last_char) i++; } last_char = s2[i]; } free(s2); } 

Of course, the table mentioned by @SomeProgrammerDude in comments scales better as it's an O(n) solution rather than O(n * log n), but it does not scale to data sets which involve much larger possible values.

Consider how this would work if we had an array of 32-bit integers. The table to hold them would have to hold ~4 billion values.

A naive approach would simply iterate over the rest of the string to determine if the same character occurs again.

int main(void) { const char *s = "dacabcabcff"; size_t len = strlen(s); for (size_t i = 0; i < len - 1; i++) { int found_again = 0; for (size_t j = i + 1; !found_again && j < len; j++) { if (s[i] == s[j]) { found_again = 1; } } if (found_again) { printf("%c\n", s[i]); } } } 

This poses a problem as it has quadratic or O(n^2) runtime complexity, but also because it may print the same character multiple times.

We could write code to remove that character from the remainder of the string, but that adds further work to a solution which is already working too hard.

E.g.

int main(void) { // Not a string literal so it can be modified. char s[] = "dacabcabcff"; for (size_t i = 0; i < strlen(s) - 1; i++) { int found_again = 0; for (size_t j = i + 1; !found_again && j < strlen(s); j++) { if (s[i] == s[j]) { found_again = 1; } } // Avoiding wrapping everything after this // in a conditional block. if (!found_again) continue; printf("%c\n", s[i]); // Eliminate s[i] from the rest of the string. size_t k = i+1; for (size_t j = i+1; j < strlen(s); j++) { if (s[j] != s[i]) s[k++] = s[j]; } s[k] = '\0'; } } 
Sign up to request clarification or add additional context in comments.

3 Comments

isn't it an overkill?
loop executes 45 times. for string length of 11
The naive version I added, or my original code?
-1

You need the table where you will store the number of occurrences of the char. Then you can print them if that count is larger than 1

If o in follow is considered as "repeat" character.

void char_counter(const char *str) { size_t chars['~'-' ' + 1] = {0,}; // only from ' ' to `~` while(*str) { if(*str >= ' ' && *str <= '~') chars[*str - ' ']++; str++; } for(size_t index = 0; index < sizeof(chars) / sizeof(chars[0]); index++) { if(chars[index] > 1) printf("'%c' - %zu times\n", (char)index + ' ', chars[index]); } } int main(void) { char_counter("dfslgkdjlfk als sdlk sakl jsdakl jsdlkfasdjkfdlgfjgalk!@#@#%$#%^*&^~~~~dfgdf54fdsdd;lfdf;dsfakl3456459657438553985476"); } 

https://godbolt.org/z/hbcvTsMcb

6 Comments

Any comment? What is wrong here in your opinion?
I didn't downvote, but perhaps because you're making an assumption that the character set is ASCII. I have redeeming qualities, but mind-reading isn't one of them.
One note: str can be const char *.
@Chris it is not a real program. only something which demonstrates the idea
@gulpr: Re “it is not a real program. only something which demonstrates the idea”: That is an excuse for claiming the answer is okay. You do not make improvements by excusing things as okay. You look for things that can be improved. If you were criticizing this post, how many issues could you find?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.