0

I have been running into issues with the strcpy() function in C. In this function I take a string in buffer and the string contains a something along the lines of '(213);' and I am trying to remove the brackets so the output would be something like 200;.

for (i = 0; i < bufferlen; i++) {
        // check for '(' followed by a naked number followed by ')'
        // remove ')' by shifting the tail end of the expression
        // remove '(' by shifting the beginning of the expression
        if((buffer[i] == '(') && (isdigit(buffer[i+1]))){

            int numberLen = 0;
            int test =0;
            i++;
            while((isdigit(buffer[i]))){
                i++;
                numberLen++;
            }


            if(buffer[i] == ')'){
                int numberStart = i - numberLen-1;
                strcpy(&buffer[i], &buffer[i+1]);
                strcpy(&buffer[numberStart], &buffer[numberStart+1]);

                printf("buffer = %s\n", buffer);
            }
        }
    }

However, the output is as follows

buffer before strcpy(&buffer[i], &buffer[i+1]); = (213);

buffer after strcpy(&buffer[i], &buffer[i+1]); = (213;

buffer after strcpy(&buffer[numberStart], &buffer[numberStart+1]); = 23;;

for some reason the second strcpy function removes the second value of the string. I have also tried strcpy(&buffer[0], &buffer[1]); and still end up with the same results. Any insight as to why this is occurring would be greatly appreciated.

ksss
  • 35
  • 5
  • 4
    `strcpy(&buffer[i], &buffer[i+1]);` where `source` and `dest` overlap results in *Undefined Behavior*, use `memmov` instead. See [C11 Standard - 7.24.2.3 The strcpy function](http://port70.net/~nsz/c/c11/n1570.html#7.24.2.3) – David C. Rankin Oct 21 '19 at 04:30
  • It looks like some optimization in `strcpy()` may be causing loss of information, as the source and destination overlap and `strcpy()` is not supposed to support that. You can try to workaround that by writing your own version of `strcpy()` that ensures only one character is copied at a time and in the expected order. – Havenard Oct 21 '19 at 05:02
  • Why would 23 change to 200? Or is that a typo? – Jonathan Leffler Oct 21 '19 at 06:34

1 Answers1

4

Continuing from the comment, strcpy(&buffer[i], &buffer[i+1]); where source and dest overlap results in Undefined Behavior, use memmove, or simply use a couple of pointers instead.

The prohibition on using strings that overlap (i.e. are the same string) is found in C11 Standard - 7.24.2.3 The strcpy function

If I understand your question and you simply want to turn "'(213)'" into "213", you don't need any of the string.h functions at all. You can simply use a couple of pointers and walk down the source-string until you find a digit. Start copying digits to dest at that point by simple assignment. When the first non-digit is encountered, break your copy loop. Keeping a flag to indicate when you are "in" a number copying digits will allow you to break on the 1st non-digit to limit your copy to the first sequence of digits found (e.g. so from the string "'(213)' (423)", only 213 is returned instead of 213423). You could do somehting like:

char *extractdigits (char *dest, const char *src)
{
    /* you can check src != NULL here */
    char *p = dest;     /* pointer to dest (to preserve dest for return) */
    int in = 0;         /* simple flag to break loop when non-digit found */

    while (*src) {              /* loop over each char in src */
        if (isdigit(*src)) {    /* if it is a digit */
            *p++ = *src;        /* copy to dest */
            in = 1;             /* set in-number flag */
        }
        else if (in)            /* if in-number, break on non-digit */
            break;
        src++;                  /* increment src pointer */
    }
    *p = 0;             /* nul-terminate dest */

    return dest;        /* return pointer to dest (for convenience) */
}

A short example would be:

#include <stdio.h>
#include <ctype.h>

#define MAXC 32

char *extractdigits (char *dest, const char *src)
{
    /* you can check src != NULL here */
    char *p = dest;     /* pointer to dest (to preserve dest for return) */
    int in = 0;         /* simple flag to break loop when non-digit found */

    while (*src) {              /* loop over each char in src */
        if (isdigit(*src)) {    /* if it is a digit */
            *p++ = *src;        /* copy to dest */
            in = 1;             /* set in-number flag */
        }
        else if (in)            /* if in-number, break on non-digit */
            break;
        src++;                  /* increment src pointer */
    }
    *p = 0;             /* nul-terminate dest */

    return dest;        /* return pointer to dest (for convenience) */
}

int main (void) {

    char digits[MAXC] = "";
    const char *string = "'(213}'";

    printf ("in : %s\nout: %s\n", string, extractdigits (digits, string));
}

Example Use/Output

$ ./bin/extractdigits
in : '(213}'
out: 213

Look things over and let me know if you have further questions.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85