11

I'm trying to figure out how to cut part of a string in C. For example you have this character string "The dog died because a car hit him while it was crossing the road" how would a function go making the sentence "a car hit him while crossing the road" or "a car hit him"

How do you go about this with C's library (or/and) a custom function?

ok I don't have the main code but this is going to be the structure of this experiment

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include "display_usage.c"/*If the user enters wrong arguments it will tell them how it should be */


void cut( const char *file, int option, int first, int last );


int main(int argc, char *argv[] ) {
FILE *fp;
    char ch;
    fp = fopen("test.txt", "r"); // Open file in Read mode

    while (ch!=EOF) {
        ch = fgetc(fp); // Read a Character

        printf("%c", ch);
    }
    fclose(fp); // Close File after Reading
   return 0;
}

void cut( const char *file, int reverse, int first, int last ) {



    return;
}
4
  • Show us what you have tried and we will help you Commented Dec 3, 2013 at 3:56
  • Would be possible if you either had a keyword to cut the sentence at or had a specific length where the sentence needs to be cut
    – smac89
    Commented Dec 3, 2013 at 3:56
  • 9
    Well at least it wasn't a duck crossing the road.
    – Duck
    Commented Dec 3, 2013 at 3:56
  • How are you going to define the operations you want to perform? If you are only interested in the result strings, you simply specify them as literals. If you want to do the job more generically, you have to specify how you are going to identify what you want removed, or what you want kept. Are you going to do it in a single function call? Are you going to modify the string in situ or are you copying parts of a string to another location altogether? There are two deletion operations for the first target sentence (there's an 'it' missing); similarly for the second target sentence, too. Commented Dec 3, 2013 at 4:02

6 Answers 6

8

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.

1
  • 2
    You can't use strncpy() if the source and destination overlap. Commented Dec 3, 2013 at 3:57
6

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.

3
  • Please show me an example of this function actually working.
    – MadHatter
    Commented Oct 21, 2018 at 15:34
  • I am trying to use this function in a repl. Please help me understand how to use it-- I get that the parameter *str is a string, and I get that the parameter begin is the index address where I want to start slicing, but I don't get what the parameter len is supposed to be. Please help me grasp this and show me this function in action.
    – MadHatter
    Commented Oct 21, 2018 at 15:46
  • len is the length of the part to remove. The calculations in the functions ensure that len doesn't exceed the actual length. See it in action here. (I'm not so sure whether that function is useful in a find/replace function, though. You should probably move the contens so that after removing the word, there is a gap that can hold the replacement. Careful with replacements that are longer than the original word.)
    – M Oehm
    Commented Oct 21, 2018 at 17:09
3

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.

1

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".

1
  • 4
    How does strstr shorten a string? I might help to locate the char range to cut, but that's not what the OP asked for.
    – M Oehm
    Commented Dec 3, 2013 at 8:35
0

http://www.cplusplus.com/reference/cstring/

You can use functions like strstr (to get substring), strtok (split using some token),

0

You can use something similar to Python's [n:m] cut operator via a simple code but involves dynamic allocation and also preserve the original string that is an input.

char* cutoff(const char* str, int from , int to)
{
    if (from >= to)
        return  NULL;

    char* cut = calloc(sizeof(char), (to - from) + 1);
    char* begin = cut;
    if (!cut)
        return  NULL;

    const char* fromit = str+from;
    const char* toit = str+to;
    (void)toit;
    memcpy(cut, fromit, to);
    return begin;
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.