How to remove the last few characters from a string in C

I know that I can use substr() to have the first n number of characters from a string. However, I want to delete the last few characters. Is it possible to use -2 or -3 as the end position in C, similar to how I can do this in Python?

+4
source share
5 answers

Here it is possible to execute the substr() function, including test code. Please note that the test code does not push boundaries - the length of the buffer is shorter than the requested line or the length of the buffer is zero.

 #include <string.h> extern void substr(char *buffer, size_t buflen, char const *source, int len); /* ** Given substr(buffer, sizeof(buffer), "string", len), then the output ** in buffer for different values of len is: ** For positive values of len: ** 0 "" ** 1 "s" ** 2 "st" ** ... ** 6 "string" ** 7 "string" ** ... ** For negative values of len: ** -1 "g" ** -2 "ng" ** ... ** -6 "string" ** -7 "string" ** ... ** Subject to buffer being long enough. ** If buffer is too short, the empty string is set (unless buflen is 0, ** in which case, everything is left untouched). */ void substr(char *buffer, size_t buflen, char const *source, int len) { size_t srclen = strlen(source); size_t nbytes = 0; size_t offset = 0; size_t sublen; if (buflen == 0) /* Can't write anything anywhere */ return; if (len > 0) { sublen = len; nbytes = (sublen > srclen) ? srclen : sublen; offset = 0; } else if (len < 0) { sublen = -len; nbytes = (sublen > srclen) ? srclen : sublen; offset = srclen - nbytes; } if (nbytes >= buflen) nbytes = 0; if (nbytes > 0) memmove(buffer, source + offset, nbytes); buffer[nbytes] = '\0'; } #ifdef TEST #include <stdio.h> struct test_case { const char *source; int length; const char *result; }; static struct test_case tests[] = { { "string", 0, "" }, { "string", +1, "s" }, { "string", +2, "st" }, { "string", +3, "str" }, { "string", +4, "stri" }, { "string", +5, "strin" }, { "string", +6, "string" }, { "string", +7, "string" }, { "string", -1, "g" }, { "string", -2, "ng" }, { "string", -3, "ing" }, { "string", -4, "ring" }, { "string", -5, "tring" }, { "string", -6, "string" }, { "string", -7, "string" }, }; enum { NUM_TESTS = sizeof(tests) / sizeof(tests[0]) }; int main(void) { int pass = 0; int fail = 0; for (int i = 0; i < NUM_TESTS; i++) { char buffer[20]; substr(buffer, sizeof(buffer), tests[i].source, tests[i].length); if (strcmp(buffer, tests[i].result) == 0) { printf("== PASS == %2d: substr(buffer, %zu, \"%s\", %d) = \"%s\"\n", i, sizeof(buffer), tests[i].source, tests[i].length, buffer); pass++; } else { printf("!! FAIL !! %2d: substr(buffer, %zu, \"%s\", %d) wanted \"%s\" actual \"%s\"\n", i, sizeof(buffer), tests[i].source, tests[i].length, tests[i].result, buffer); fail++; } } if (fail == 0) { printf("== PASS == %d tests passed\n", NUM_TESTS); return(0); } else { printf("!! FAIL !! %d tests out of %d failed\n", fail, NUM_TESTS); return(1); } } #endif /* TEST */ 

The function declaration must be in the appropriate heading. The variable sublen helps compile the code as follows:

 gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \ -Wold-style-definition -Werror -DTEST substr.c -o substr 

Test output:

 == PASS == 0: substr(buffer, 20, "string", 0) = "" == PASS == 1: substr(buffer, 20, "string", 1) = "s" == PASS == 2: substr(buffer, 20, "string", 2) = "st" == PASS == 3: substr(buffer, 20, "string", 3) = "str" == PASS == 4: substr(buffer, 20, "string", 4) = "stri" == PASS == 5: substr(buffer, 20, "string", 5) = "strin" == PASS == 6: substr(buffer, 20, "string", 6) = "string" == PASS == 7: substr(buffer, 20, "string", 7) = "string" == PASS == 8: substr(buffer, 20, "string", -1) = "g" == PASS == 9: substr(buffer, 20, "string", -2) = "ng" == PASS == 10: substr(buffer, 20, "string", -3) = "ing" == PASS == 11: substr(buffer, 20, "string", -4) = "ring" == PASS == 12: substr(buffer, 20, "string", -5) = "tring" == PASS == 13: substr(buffer, 20, "string", -6) = "string" == PASS == 14: substr(buffer, 20, "string", -7) = "string" == PASS == 15 tests passed 

In a comment on another answer , cool_sops asks:

Why not work: memcpy(new_string, old_string, strlen(old_string) - 3; &new_string[strlen(old_string) - 3] = '\0' Assuming new_string and old_string , both are pointers char and strlen(old_string) > 3 ?

Assuming you remove & , insert the missing ) and ; , the pointers point to valid non-overlapping locations and the length condition is satisfied, then it should be OK to copy all but the last 3 characters from the old line to the new line, as you could check by pasting it into some test code. He does not try to cope with the copying of the last three characters of the old line, about which he first of all asked a question.

 #include <string.h> #include <stdio.h> int main(void) { char new_string[32] = "XXXXXXXXXXXXXXXX"; char old_string[] = "string"; memcpy(new_string, old_string, strlen(old_string) - 3); new_string[strlen(old_string) - 3] = '\0'; printf("<<%s>> <<%s>>\n", old_string, new_string); return(0); } 

Output:

 <<string>> <<str>> 

However, beware of complex matches; I selected a sample of the old string with a length of 6 characters, and -3 - "length -3", equal to 3. To get the last N characters, you need more code:

 #include <assert.h> #include <string.h> #include <stdio.h> int main(void) { int N = 3; char new_string[32] = "XXXXXXXXXXXXXXXX"; char old_string[] = "dandelion"; int sublen = strlen(old_string) - N; assert(sublen > 0); memcpy(new_string, old_string + sublen, N); new_string[N] = '\0'; printf("<<%s>> <<%s>>\n", old_string, new_string); return(0); } 

Output:

 <<dandelion>> <<ion>> 

Please note: writing small programs like this is good practice and can be educational. Writing a lot of code is one way to improve the writing code.

The only thing you need to know is that if you test undefined behavior, you just get a response from one compiler, but other compilers can generate code that behaves differently. This code does not implement undefined behavior, so this is normal. Identifying undefined behavior is complex, so you can partially ignore this comment, but make sure you are compiled with strict warning options on your compiler that you can embed - they help identify undefined behavior.

I have a set of sample programs that I save (under source control) in a directory called vignettes ; they are small cameo programs that illustrate a technique that I can refer to if I think I might need it again in the future. They are full; they work; (they are more complicated than these specific examples, but I have been programming in C longer than yours;) but they are toys - useful toys.

+4
source

You can simply put the null termination character to the right where you want the line to end like this:

 int main() { char s[] = "I am a string"; int len = strlen(s); s[len-3] = '\0'; printf("%s\n",s); } 

This will give you:

"I am str"

+8
source

C is not like Python; String indexes are not smart. The expression str[-3] quite literally means "the character is three bytes before the start"; access to this memory is undefined behavior.

If you want to get the last few characters of a string as another string, just get a pointer to the first character you want:

 char *endstr = str + (strlen(str) - 3); // get last 3 characters of the string 

If you want to delete the last few characters, just set the kth-from-end character to zero ( \0 ):

 str[strlen(str)-3] = 0; // delete last three characters 
+4
source

No, you need to use strlen () to get the last characters.

 substr(strlen(str)-4,3); 

Remember that strings are based on 0, so this gives you the last 3.

So the general method

 substr(strlen(str)-n-1,n); 

(of course, the string must be longer than n )

If you want the last 3 to use this:

 substr(0,strlen(str)-4); 

Or even

 substr(0,strlen(str)-n-1); 
+2
source

I noted that substr not a standard C function and therefore not valid for use in C. So, to find a substring by excluding the last few characters, you can use memcpy(new_string, old_string, strlen(old_string) - 3)

0
source

All Articles