1
#include <Stdio.h>
#include <string.h>

int main(){
    char str[51];
    int k = 1;
    printf("Enter string\n");
    scanf("%s", &str);
    for(int i = 0; i < strlen(str); i++){
        while(str[k] != '\0')){
            if(str[i] == str[k]){
                printf("%c", str[i]);
                k++;
            }
        }
    }

    return 0;
}

It is simple C code that checks for duplicate characters in string and prints the characters. I am not understanding why it is producing an infinite loop. The inner while loop should stop when str[k] reaches the null terminator but the program continues infinitely.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    You don't use `&` when scanning a string. – Barmar Apr 19 '22 at 04:33
  • That code won't even compile, so I seriously doubt it to be producing an infinite loop. Dunno why everyone just dropped their comment, but assuming you fix the blatant syntax error in the posted code, their comments were correct: `k++;` belongs *outside* the `if` block in which it currently resides. – WhozCraig Apr 19 '22 at 04:33
  • 1
    move `k++` after the `if` block, at least – yano Apr 19 '22 at 04:36
  • @WhozCraig If you're talking about ``, that will likely work with a case-insensitive filesystem like Windows. – Barmar Apr 19 '22 at 04:36
  • @Barmar I'm talking about `while(str[k] != '\0')){` – WhozCraig Apr 19 '22 at 04:36
  • Both are probably just copying errors. – Barmar Apr 19 '22 at 04:37
  • Is the intent of this exercise to print each character that appears more than once in the string, once? E.g. given `mississippi` , should the output be `sip` ? Or something else? – WhozCraig Apr 19 '22 at 04:50
  • @WhozCraig Yes, your are right – Darth-CodeX Apr 19 '22 at 07:06
  • Sorry, but when you say I'm "right", does that mean yes, the output should be a *single* character for each one found more than once (such as my example), or yes, it is something else. Details matter. – WhozCraig Apr 19 '22 at 07:17
  • `scanf("%s", &str);`, without a _width_ is poor code. Better as `scanf("%50s", str);` – chux - Reinstate Monica Apr 19 '22 at 08:58
  • @WhozCraig For **mississippi**, the output will be **ips**. If we look the output string was a set(mathematical one), then your **sip** and **ips** are equal. And yes, the program should print single character for each one found to occur more than once. – Darth-CodeX Apr 19 '22 at 09:09
  • @Darth-CodeX That is what the output will be from *your* answer code. I've yet to hear back from the OP. As I said to them, details matter. If a duplicate is determined by foreshadow detection (e.g. scan forward on each new char) the first duplicated char is `i`. If duplicate detection is based on previous encounter the first duplicated char is `s`. And both have the added distraction of "remembering" you already reported a character as a duplicate, and to not do it again; an easy task to accomplish with a lookup table; not so much with a double loop. – WhozCraig Apr 19 '22 at 09:16
  • @WhozCraig In that sense OP should **provide further details**. I had given my answer as most of the people likes in that way to printing duplicate ones – Darth-CodeX Apr 19 '22 at 09:20
  • Thank you all for your feedback. As some users have pointed out, k++ within the if statement was a copying error. It is outside the if statement in the actual code. Not sure why it appears this way here. I have removed the "&" sign from scanf but the code is only printing the first character although that character is not unique. I have also changed the if statement to be true if the string character does not equal another string character. It is also no longer in the infinite loop. – camknight15 Apr 19 '22 at 17:22

2 Answers2

3

Points to know

  • You don't need to pass the address of the variable str to scanf()
  • Don't use "%s", use "%<WIDTH>s", to avoid buffer-overflow
  • Always check whether scanf() conversion was successful or not, by checking its return value
  • Always use size_t to iterator over any array
  • i < strlen(str), makes the loop's time complexity O(n3), instead of O(n2), which also isn't very good you should check whether str[i] != 0. But, many modern compilers of C will optimize it by the way.
  • #include <Stdio.h> it is very wrong, stdio.h != Stdio.h
  • Call to printf() can be optimized using puts() and putc() without any special formatting, here also modern compiler can optimize it
  • while(str[k] != '\0')){ has a bracket (')')
  • Initialize your variable str using {}, this will assign 0 to all the elements of str

Better Implementation

My implementation for this problem is that create a list of character (256 max) with 0 initialized, and then add 1 to ASCII value of the character (from str) in that list. After that print those character whose value was greater than 1.

  • Time Complexity = O(n), where n is the length of the string

  • Space Complexity = O(NO_OF_CHARACTERS), where NO_OF_CHARACTERS is 256


Final Code

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

static void print_dup(const char *str)
{
    size_t *count = calloc(1 << CHAR_BIT, sizeof(size_t));
    for(size_t i = 0; str[i]; i++)
    {
        count[(unsigned char)str[i]]++;
    }
    for (size_t i = 0; i < (1 << CHAR_BIT); i++)
    {
        if(count[i] > 1)
        {
            printf("`%c`, count = %zu\n", i, count[i]);
        }
    }
    free(count);
}

int main(void) {
    char str[51] = {};
    puts("Enter string:");
    if (scanf("%50s", str) != 1)
    {
        perror("bad input");
        return EXIT_FAILURE;
    }
    print_dup(str);
    return EXIT_SUCCESS;
}
Darth-CodeX
  • 2,166
  • 1
  • 6
  • 23
1

Read your code in English: You only increment variable k if character at index k is equal to character at index i. For any string that has different first two characters you will encounter infinite loop: char at index i==0 is not equal to char at index k==1, so k is not incremented and while(str[k]!=0) loops forever.

Mike
  • 4,041
  • 6
  • 20
  • 37
ufok
  • 193
  • 4