u2dragon
u2dragon

Reputation: 3

c++ string manipulation with pointers, null in middle

I have to write a c++ function with the following specifications:

unique

Deletes the duplicated charters between the two parameter pointers. The string remains on its original place.

param first - pointer to the beginning of the string

param last - pointer to the data after the last charter

return - pointer to the first charater of the new data series

If the input is "H\0elllo C+++++ +!#", the output is "H\0elo C+ +!#". I canot figure out how to ignore the terminating null in the middle. This is my best approach so far:

char *sajat::unique(char *first, char *last){
char* moving = first + 1;
char* follower = first;

while (moving != last)
{
char *sentinel = first; 
    if (*follower == *moving)
    {
    counter++;
    sentinel = follower; //here was the duplication
        while (follower != last)
        {
            *follower = *moving;
            follower++;
            moving++;
        }
        sentinel = follwer;
        moving = follower + 1;
    }
    moving++;         
    follower++;
   }
return first - counter;
}

So this code is obviously wrong...but it can identify successfully the duplication. (I know it is homework and shame on me....but i have been trying to solve it for hours. Sorry for the messed up code.)

Upvotes: 0

Views: 262

Answers (1)

Serge Ballesta
Serge Ballesta

Reputation: 148920

You are given here a char array that is not a C string because it can contain null characters. That means you should forget everething you could know about C strings when processing it.

It is given by 2 pointers, one at the start, one past the end. As it is to be processed in place, the start pointer will not change, so your function should just return the new end pointer (still same definition: one past the last kept character).

Once this is said, you current code is much too complex. You only have to read the string one char at a time, compare the current character with the previous one and keep it only if they are different. A simple way is to use 2 pointers, one for reading and one for writing, increment the read pointer on each iteration and increment the write pointer only if the character has to be kept. As for the previous value, an idiomatic way is to initialize it to an int value that cannot be represented by a character.

The function reduces to:

char *sajat::unique(char *first, char *last){
    char *rd = first, *wr = first;
    int prev = UCHAR_MAX + 1;       // cannot be a character value

    while (rd != last) {
        if (prev != *rd) {
            prev = *wr++ = *rd;
        }
        rd++;
    }

return wr;
}

Demo code:

#include <iostream>
#include <string>
#include <climits>

char *unique(char *first, char *last){
    char *rd = first, *wr = first;
    int prev = UCHAR_MAX + 1;       // cannot be a character value

    while (rd != last) {
        if (prev != *rd) {
            prev = *wr++ = *rd;
        }
        rd++;
    }

return wr;
}

int main() {
    char tst[] = "H\0elllo C+++++ +!#";
    char *last = unique(tst, tst+sizeof(tst) - 1);  // reject the terminating null

    std::cout << std::string(tst, last) << std::endl;  // first display the result as a string

    for (char *ix=tst;ix<last; ix++) {              // then every character in hexa
        std::cout << std::hex << " " << (unsigned int)(unsigned char) *ix;
    }
    std::cout << std::endl;
    return 0;
}

On my ASCII system it shows:

Helo C+ +!#
 48 0 65 6c 6f 20 43 2b 20 2b 21 23

Upvotes: 1

Related Questions