Removing the first char from a string...

Posted by Aqueus on Thu 22 Feb 2007 05:23 AM — 6 posts, 23,710 views.

USA #0
Ok, I'm a novice to average coder, but I'm mostly familiar with C++ functions, and for the life of me I can't find a way to break apart a string and simply remove (as in not replace it with a character - shift all the characters over, or at least make that character not display, whatever is easiest) a character (the first character) from a string.

The reason is rather silly, but I wanted it to be my first session with string manipulation, from there I'll branch out and get into more complex things. Oh, and this is for channel-stuff, so that when you type OOC *goes to take a shower... it removes the first character (the asterisk), and I also think it'd be nice to check and see if the last character is an asterisk, too, if so, then make it the terminate character.
USA #1
well i could see two different options, you could make a function like so:

// remove first character
char *rfc( char *original )
{
    static char new[MAX_STRING_LENGTH];
    int x;

    new[0] = '\0';

    if ( original[0] != '\0' )
    {
        for ( x = 0; x < strlen(original); x++ )
        {
            new[x] = original[x+1];
        }
        new[x] = '\0';
    }
    return new;
}

or you could modify your ooc function, i did something like this for my roleplaying channel like so:

void do_rp( CHAR_DATA *ch, char *argument )
{
    int x;
    char emote[MAX_STRING_LENGTH];
    bool rpemote = FALSE;

    if ( !IS_NPC(ch) && !IS_SET(ch->pcdata->flags, PCFLAG_CANRP) )
    {
        ch_printf( ch, "You are not authorized to use the rp channels.\n\r" );
        return;
    }

    if ( !sysdata.chan_rp && !IS_IMMORTAL(ch) )
    {
        stc( "The RP channel is currently disabled.\n\r", ch);
        return;
    }

    if ( argument[0] == '*' ) /*Emote Signifier*/
        rpemote = TRUE;

    if ( rpemote )
    {
        for ( x = 0; x<strlen(argument); x++)
        {
            emote[x] = argument[x+1];
        }
        talk_channel( ch, emote, CHANNEL_RPEMOTE, "rp" );
    }
    else
        talk_channel( ch, argument, CHANNEL_RP, "rp" );
    return;
}

Amended on Thu 22 Feb 2007 05:39 AM by Gohan_TheDragonball
USA #2
It really depends on what you want to do with the string. If all you are going to do is read it once and not keep it around in memory, you can just do str+1 -- that will be the same string as str, except starting one character in.

Of course, that's not necessarily a safe pointer to keep, because the original string could change at any point, and it's unclear is the new string is still valid.

What Gohan proposed is a way to copy the entire string into a static buffer. It's still not a safe buffer to keep around, because future calls to the function will change the contents of the buffer -- therefore changing the string it returned.

If you really, really want unique strings that you can hold on to, you will have to allocate a block of memory and do basically what Gohan's function does, except that you use the malloc'ed memory instead of the static buffer.
USA #3
You could just check do_config, since that eliminates the first char (+ or -) if you need more examples.
USA #4
Thanks for the example code that helps a lot. One more quick question before I go back to the coding grindstone:

strlen returns the exact length of the string, right? So I could do something like...

if ( argument[strlen(argument)] == '*' )
argument[strlen(argument)] = '\0';

...to replace the last character, right?

Oh and just to clear things up, the strings are for channels, so I don't care what happens to them after they get displayed.
Amended on Thu 22 Feb 2007 03:53 PM by Aqueus
USA #5
Yes, strlen returns the exact length of the string. But these things are zero-indexed, so you're off by one.

str[strlen(str)] will get you the last character, meaning the trailing \0. What you really want is str[strlen(str) - 1], except that in that case you of course need to make sure the string is not empty.

If you don't care about what happens to the string, and just need to print it once, I would recommend not copying it but simply advancing the pointer by one.