user6005857
user6005857

Reputation: 631

How to write a C function that removes a portion of a string?

I want to write a C function that removes a portion of a string for a given index range.

For example, if the input string is "ABCDEFGHIJK" and the start index is 2 and the end index is 5 then the output should be: "ABGHIJK".

I am attempting to do this using two functions, one function that gets the substring we want to delete:

void get_substring(char string[], char substring[], int start, int end) {
    strncpy(substring, string + start, end - start + 1);
}

and then a second function that deletes this substring:

void remove_portion(char string[], char substring[]) {
    // memmove?
}

Another possibility I was thinking about is to directly modify the original string without using a substring:

void remove_portion(char string[], int start, int end) {
    // if end is less then the length of the string, then
    // copy everything after string[end] into a temp string
    // Then replace string[start] with '\0' and then concatenate
    // string and temp.
    // If end is greater than the length of string then just replace
    // string[start] with '\0'.
}

Is this the correct approach? Are there any built in functions from string.h that can be useful here?

Upvotes: 5

Views: 531

Answers (4)

ad absurdum
ad absurdum

Reputation: 21320

It was pointed out to me that using strcpy() for this is wrong, because "copying that takes place between objects that overlap" is undefined in the standard (ISO/IEC 9899:1999 7.21.2.4).

Here is a version that uses memmove(), with some checks for valid indices. It swaps the indices if the first is larger than the second, and returns NULL if the indices are out of bounds:

char * remove_portion(char *str, int start, int end)
{
    int str_len = strlen(str);
    int temp;

    if (start > end) {
        temp = start;
        start = end;
        end = temp;
    }

    if (end > (str_len - 1) || start < 0 || end < 0) {
        str = NULL;
    } else {
        int ncopy = str_len - end; 
        memmove(&str[start], &str[end+1], ncopy);
    }

    return str;
}

Of memmove() the standard says: "Copying takes place as if the n characters from the object pointed to by s2 are first copied into a temporary array of n characters that does not overlap the objects pointed to by s1 and s2, and then the n characters from the temporary array are copied into the object pointed to by s1." (ISO/IEC 9899:1999 7.21.2.2)

So memmove() is specifically designed to handle situations such as copying a part of an array to itself.

Upvotes: 0

Aidenhjj
Aidenhjj

Reputation: 1289

New to C myself, but this worked for me:

void remove_portion(char str[], int start, int end) {
    assert((end > start) && (strlen(str) > end));
    char out[strlen(str) - (end - start)];
    int i, j = 0;
    for (i = 0; str[i] != '\0'; i++) {
        if ((i < start) || (i > end))
            out[j++] = str[i];
    }
    out[j] = '\0';
    strcpy(str, out);
}

Upvotes: 1

Anachronism
Anachronism

Reputation: 417

I would go with using memmove as in the 2nd approach:

void remove_portion(char string[], int start, int end) 
{
    if (start>=0 && end>=start && start<strlen(string) && end<strlen(string)) {  // some more sanity checking (EDIT added later)
         memmove(string+start, string+end+1, strlen(string)-(end+1)+1);  // final +1 to copy string terminator
    }
}

Also note that in your first example (with strncpy) is not going to to copy the ending string terminator \0 to substring. So you'll need to add

substring[end - start + 1]= '\0'; 

to that.

Upvotes: 5

Sashank
Sashank

Reputation: 107

Use this :

void remove_portion( char * str, int start, int end){
char* stro = calloc(strlen(str - (end-start+1)), sizeof(char));
strncpy(stro,str,start);
strcat(stro,&str[end]);
strcpy(str,stro);
}

Add conditions also.

Upvotes: 1

Related Questions