How to cut part of a string in c?

strncpy will only copy up to n characters. Optionally you can move a pointer around in the string, and also stick a \0 into the array to terminate it early if you have writable memory.


strstr would be perfect for you, if you know the contents of the string.

Example:

char *str = "A dog died because a car hit him while he was crossing the road.";
char *pCh = strstr(str, "dog");

pCh will have the address of the 'd' in "dog".


For such problem, it is better to write own function, it will take time, but it will pay off. A code of a function str_slice is shown below, is very similar to the JavaScripts's function string.slice (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) and to the Python's feature for making a slice on strings or arrays (https://docs.python.org/3.5/library/functions.html#slice).

It also based only on the C standard library, so must be cross-platform and to working with any compiler. If in doubt, to look on tests.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


/**
 * Extracts a selection of string and return a new string or NULL.
 * It supports both negative and positive indexes.
 */
char *
str_slice(char str[], int slice_from, int slice_to)
{
    // if a string is empty, returns nothing
    if (str[0] == '\0')
        return NULL;

    char *buffer;
    size_t str_len, buffer_len;

    // for negative indexes "slice_from" must be less "slice_to"
    if (slice_to < 0 && slice_from < slice_to) {
        str_len = strlen(str);

        // if "slice_to" goes beyond permissible limits
        if (abs(slice_to) > str_len - 1)
            return NULL;

        // if "slice_from" goes beyond permissible limits
        if (abs(slice_from) > str_len)
            slice_from = (-1) * str_len;

        buffer_len = slice_to - slice_from;
        str += (str_len + slice_from);

    // for positive indexes "slice_from" must be more "slice_to"
    } else if (slice_from >= 0 && slice_to > slice_from) {
        str_len = strlen(str);

        // if "slice_from" goes beyond permissible limits
        if (slice_from > str_len - 1)
            return NULL;

        buffer_len = slice_to - slice_from;
        str += slice_from;

    // otherwise, returns NULL
    } else
        return NULL;

    buffer = calloc(buffer_len, sizeof(char));
    strncpy(buffer, str, buffer_len);
    return buffer;
}

Tests

#include <assert.h>

void
test_str_slice()
{
    char str[] = "abcdefghijkl";

    assert(NULL == str_slice(str, -3, -10));
    assert(NULL == str_slice(str, -1, -2));
    assert(NULL == str_slice(str, -1, 0));
    assert(NULL == str_slice(str, 1, 0));
    assert(NULL == str_slice(str, 5, 4));
    assert(NULL == str_slice(str, 0, 0));
    assert(NULL == str_slice(str, 10, 10));
    assert(NULL == str_slice(str, -2, -2));
    assert(NULL == str_slice(str, -20, -12));
    assert(NULL == str_slice(str, -20, -13));
    assert(NULL == str_slice(str, 12, 13));
    assert(NULL == str_slice(str, 12, 20));
    assert(NULL == str_slice("", 1, 2));
    assert(NULL == str_slice("", -2, -1));
    assert(strcmp(str_slice(str, -3, -1), "jk") == 0);
    assert(strcmp(str_slice(str, -8, -3), "efghi") == 0);
    assert(strcmp(str_slice(str, -10, -9), "c") == 0);
    assert(strcmp(str_slice(str, -2, -1), "k") == 0);
    assert(strcmp(str_slice(str, -15, -1), "abcdefghijk") == 0);
    assert(strcmp(str_slice(str, -12, -2), "abcdefghij") == 0);
    assert(strcmp(str_slice(str, -15, -8), "abcd") == 0);
    assert(strcmp(str_slice(str, -15, -11), "a") == 0);
    assert(strcmp(str_slice(str, 1, 3), "bc") == 0);
    assert(strcmp(str_slice(str, 11, 100), "l") == 0);
    assert(strcmp(str_slice(str, 2, 4), "cd") == 0);
    assert(strcmp(str_slice(str, 3, 6), "def") == 0);
    assert(strcmp(str_slice(str, 0, 1), "a") == 0);
    assert(strcmp(str_slice(str, 4, 6), "ef") == 0);
    assert(strcmp(str_slice(str, 1, 2), "b") == 0);
    assert(strcmp(str_slice(str, 0, 3), "abc") == 0);
    assert(strcmp(str_slice(str, 0, 11), "abcdefghijk") == 0);
    assert(strcmp(str_slice(str, 2, 10), "cdefghij") == 0);
    assert(strcmp(str_slice(str, 0, 50), "abcdefghijkl") == 0);
}

As you can see in the tests, the function to returns a string or NULL. It also has support both negative and positive indexes. This idea taken from the mentioned early features from the JavaScript and Python. So, do not pollute this answer large amount of a text, I to recommend to you to read the docs of the JavaScript and the Python.


The following function cuts a given range out of a char buffer. The range is identified by startng index and length. A negative length may be specified to indicate the range from the starting index to the end of the string.

/*
 *      Remove given section from string. Negative len means remove
 *      everything up to the end.
 */
int str_cut(char *str, int begin, int len)
{
    int l = strlen(str);

    if (len < 0) len = l - begin;
    if (begin + len > l) len = l - begin;
    memmove(str + begin, str + begin + len, l - len + 1);

    return len;
}

The char range is cut out by moving everything after the range including the terminating '\0' to the starting index with memmove, thereby overwriting the range. The text in the range is lost.

Note that you need to pass a char buffer whose contents can be changed. Don't pass string literals that are stored in read-only memory.

Tags:

C

String

Cut