Repeating characters that should be deleted are not.

Pages: 12
Hello, I am working on a project where I must read characters from an array and delete any repeating characters from the array. The array contains "mary had a little lamb. its fleece was white as snow." The problem I am encountering is that the program outputs the array unchanged. This is the section that should be deleting the repeating characters but I don't understand why it is not working... Thank you in advance for any help that you can bring to fixing this problem.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 void delete_repeats(char array[], int size)
{
        int i, j, k;
        while ('\0' != array[i])
{
        for (i=0; i<size; i++)
        {
                for (j=1; j>i; j++)
                {
                        if (array[i] == array[j])
                        {
                         for (k=i; k<size, k++)
                         {
                        array[j]=array[j+1];
                        size --;
                         }
                         }
                }
        }
}
        cout << array << endl;
        cout << "size = " << size << endl;
}
Last edited on
A few things look a bit odd here. At line 4, the value of array[i] is tested, but i has not been initialised, so the element being tested could be anywhere at all, even outside the array.

Perhaps the test for a zero element should be incorporated into the for loop at line 8. for (i=0; (i<size) && (array[i] != 0); i++)


At line 10: for (j=1; j>i; j++), the condition j>i looks wrong. Either it will be false and the loop not execute at all or if it is true, the loop will never stop (until j eventually rolls over to a negative).


Edit: while I was typing a reply, the original code was edited. Some of the line numbers may have changed.
Last edited on
At line 10 I was trying to create a loop which would test the value after i. I also tried j<size; in place of j>i; but they both produce the same incorrect result. I suppose what I am not understanding is how to have the program read the character after i? Here is the algorithm which I based my current work on-

Algorithm for delete_duplicates() function
1. For each character in the array
a. For each character beyond the one the outer loop is on
i. If the character from the inner loop matches the one from the outer loop
1. For all characters beyond the current one
a. Copy the character to the prior array element
2. Decrement size

Thanks for your help.

edit: What I am confused about is why line 8 is incorrect, I don't understand what I could change j>i to retain the guideline from the algorithm.
Last edited on
bridgster posted a question about the same homework the other day. You might get ideas from that thread.
Yes, I did check that thread but I am still not understanding what I am doing wrong in my project. Thank you for the direction though.
Well, I'm not convinced that you need three nested loops.

The innermost loop [k] is kind of ok, though I think may be inefficient, it means lots and lots of shifting of data, but we'll let that go for now.

The outermost loop [i] is ok, that's pretty much essential.

But what about the middle loop [j]. Should this be a loop at all? I think the subscript j is needed, to keep track of which character we are looking at, but I'm not sure there should be a loop here, or at any rate,not in its current form.

Alright, what I am having trouble with is understanding how to write the "For each character beyond the one the outer loop is on" section of the algorithm, I need a way to check every character after the character in the inner loop.
Well, as I see it, you only need to check a single character, under normal circumstances.
1
2
3
4
word = "fleece"
i = 0
word[i] == 'f'
word[i+1] == 'l'

Above, we can see that the next character is different, so we can move on to the next value of i. There's no need for an inner loop here.

1
2
3
i = 2
word[i] == e
word[i+1] == e

here we see the characters are the same.
so we could inspect word[i+2].
If there were several consecutive identical characters, yes we would want to loop until we found the last of them. Perhaps that would be better handled as a while loop.
for example
1
2
3
j = i+1;
while (word[j] != 0 && word[i] == word[j])
    j++;


Last edited on
I'm not sure how that would ultimately work. Here is what I have as the code now-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void delete_repeats(char array[], int size)
{
        int i, j, k;
        while ('\0' != array[i])
{
        for (i=0; (i<size)&&(array[i] != 0); i++)
        {
        j = i+1;
                while ((array[j] !=0) && (array[i] == array[j])) 
                {
                j++;
                        if (array[i] == array[j])                       
                       {
                                for (k=i; k<size; k++)
                                {
                                        array[j]=array[j+1];
                                        size --;
                                }
                        }
                }
        }
}
        cout << array << endl;
        cout << "size = " << size << endl;
}



To make things a bit more clear the output that I receive is still "mary had a little lamb. its fleece was white as snow." and I need the output to be changed to something like "mary hd lite lb. s fec ws h n" where all characters repeated are removed.
Well, if j is incremented so long as (array[i] == array[j]) it's pretty clear that if (array[i] == array[j]) at line 12 is bound to fail.

I still think there are too many loops. I count four nested loops there.
Last edited on
Ah, sorry about that... The time has affected my perception.
"mary hd lite lb. s fec ws h n"
Ah. I'd misunderstood the requirement. So you want to remove 'a' in 'had' because there is an 'a' in 'Mary'. But not remove the 'l' in 'lamb' though there was an 'l' in 'fleece' ?

I actually thought you were looking to get this sort of result:
input + output:
mary had a little lammbb. its fleece was whhhiiite as snow.
mary had a litle lamb. its flece was white as snow.

No, that would be another late night mistake in my writing- I want the output to only display the first occurrence of the letter, so the l in little would stay but be removed in lamb and fleece. To do that I need to have the loop check every subsequent character in the array each time it advances and remove the repeated characters.

"mary hdliteb.sfcwn"
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 void delete_repeats(char array[], int size)
{
        int i, j, k;
//        while ('\0' != array[i])  // you have size, so content does not count
// {
        for (i=0; i<size; i++) // 1. For each character in the array
        {
                //  a. For each character beyond the one the outer loop is on
                for (j=1; j>i; j++) // BUT, this does not do **beyond i**
                {
                    // If the character from the inner loop matches the one from the outer loop
                    if (array[i] == array[j])
                     {
                        // 1. For all characters beyond the current one
                        for (k=i; k<size, k++)  // BUT, this does not do **beyond j**
                         {
                          // a. Copy the character to the prior array element
                          array[j]=array[j+1]; // whoa! j? Wrong index.
                          // 2. Decrement size
                          size --; // Notice "1 and 2", not "1a and 1b",
                                   // i.e. How much should size decrease when you remove one duplicate?
                         }
                     }
                }
        }
// }
        cout << array << endl;
        cout << "size = " << size << endl;
}



[EDIT] You had plenty of discussion while I wrote this ...
Last edited on
Thanks for the clarification keskiverto- so the problem I am encountering is that my loops will not process all the characters, just the very next one...
Lines 9, 15, and 18 have to be changed and line 20 has to be pulled out of the loop; line 15 and line 20 should be separate statements at same level.


[EDIT] Lines 1 and 27-28.
Line 27 depends on null-terminated C-string. If original array does not contain null and the size does decrease during operation, then you should add a null.

The contents of the array that the caller passes to delete_repeats() can change but the caller does not learn about changes in size. You probably should use a reference parameter, or return the new size from the function.

Furthermore, one could argue that a "number-crunch" function should do only that and not print anything. The caller can and should use and/or print the result as it sees fit.
Last edited on
I understood and changed 20 but lines 9 and 15 have me baffled, am I able to keep these two as for loops?
Thanks for the clarification - I think some of the things I said earlier may have been misleading as I hadn't properly understood the question. Sorry about that.
I understood and changed ...

Please, show current version.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void delete_repeats(char array[], int size)
{
        int i, j, k;
        for (i=0; (i<size); i++)
        {
                for (j=1; (j>i) && (j != size); j++)
                {

                if  (array[i] == array[j])
                        {
                                for (k=i; k<size; k++)
                                {   
                                     array[j]=array[j+1];
                                }
                                size --;
                        }
                }
        }

        cout << array << endl;
        cout << "size = " << size << endl;
}
Pages: 12