C语言 如何从C中的字符串中删除最后几个字符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14544920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:09:52  来源:igfitidea点击:

How do I remove last few characters from a string in C

c

提问by TheRookierLearner

I know I can use substr()to have the first nnumber of characters from a string. However, i want to remove the last few character. Is it valid to use -2or -3as the end position in C like the way I can do it in Python?

我知道我可以使用字符串中substr()的第n一个字符数。但是,我想删除最后几个字符。像我在 Python 中那样使用-2-3作为 C 中的结束位置是否有效?

采纳答案by Jonathan Leffler

Here's a possible implementation of a substr()function, including test code. Note that the test code does not push the boundaries —?buffer length shorter than requested string or buffer length of zero.

这是一个substr()函数的可能实现,包括测试代码。请注意,测试代码并没有突破界限——缓冲区长度比请求的字符串短或缓冲区长度为零。

#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] = '
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
        -Wold-style-definition -Werror -DTEST substr.c -o substr 
'; } #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 should be in an appropriate header. The variable sublenhelps the code compile cleanly under:

函数声明应该在适当的头文件中。该变量sublen有助于代码在以下情况下干净利落地编译:

== 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

Test output:

测试输出:

#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] = '
<<string>> <<str>>
'; printf("<<%s>> <<%s>>\n", old_string, new_string); return(0); }


In a comment to another answer, cool_sopsasks:

在对另一个答案的评论中,cool_sops问道:

Why wouldn't this work: memcpy(new_string, old_string, strlen(old_string) - 3; &new_string[strlen(old_string) - 3] = '\0'Assuming new_stringand old_stringboth are charpointers and strlen(old_string) > 3?

为什么这不起作用:memcpy(new_string, old_string, strlen(old_string) - 3; &new_string[strlen(old_string) - 3] = '\0'假设new_stringold_string都是char指针和strlen(old_string) > 3?

Assuming you remove the &, insert the missing )and ;, the pointers point at valid non-overlapping locations, and the length condition is satisfied, then that should be OK for copying all but the last 3 characters from the old string into the new string, as you could test by embedding it into some test code. It doesn't attempt to deal with copying the last three characters of the old string which is what the question primarily seemed to ask about.

假设您删除&,插入缺失的);,指针指向有效的非重叠位置,并且满足长度条件,那么将旧字符串中除最后 3 个字符以外的所有字符复制到新字符串中应该没问题,如您可以通过将其嵌入到一些测试代码中来进行测试。它不会尝试处理复制旧字符串的最后三个字符,这似乎是问题主要提出的问题。

#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] = '
<<dandelion>> <<ion>>
'; printf("<<%s>> <<%s>>\n", old_string, new_string); return(0); }

Output:

输出:

int main()
{
    char s[] = "I am a string";
    int len = strlen(s);
    s[len-3] = '
char *endstr = str + (strlen(str) - 3); // get last 3 characters of the string
'; printf("%s\n",s); }

However, beware of tricky coincidences; I chose a sample old string that is 6 characters long, and the -3 give 'length -3' equal to 3 too. To get the last N characters, you need code more like:

但是,请注意棘手的巧合;我选择了一个 6 个字符长的示例旧字符串,并且 -3 给出的 'length -3' 也等于 3。要获取最后 N 个字符,您需要更类似的代码:

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

Output:

输出:

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

Note, writing little programs like this is good practice, and can be educational. Writing lots of code is one way to get better at writing code.

请注意,编写这样的小程序是一种很好的做法,并且具有教育意义。编写大量代码是提高编写代码水平的一种方法。

The only trap to be aware of is that if you are testing 'undefined behaviour', you simply get the response from a single compiler, but other compilers may generate code that behaves differently. This code is not exercising undefined behaviour, so it's fine. Identifying undefined behaviour is tricky, so you can partially ignore this commentary, but make sure you compile with the stringent warning options on your compiler that you can stomach — they help identify undefined behaviour.

唯一需要注意的陷阱是,如果您正在测试“未定义行为”,您只需从单个编译器获得响应,但其他编译器可能会生成行为不同的代码。这段代码没有执行未定义的行为,所以很好。识别未定义的行为很棘手,因此您可以部分忽略此评论,但请确保在编译器上使用您可以忍受的严格警告选项进行编译——它们有助于识别未定义的行为。

I have a supply of sample programs that I keep (under source control) in a directory called vignettes; they are little cameos of programs that illustrate a technique that I can refer to if I think I might need it again in the future. They're complete; they work; (they're more complex than these specific examples, but I've been programming in C longer than you have;) but they are toys — useful toys.

我在一个名为vignettes;的目录中保存了一些示例程序(在源代码控制下)。它们是一些程序的小角色,它们说明了一种技术,如果我认为将来可能再次需要它,我可以参考它们。他们是完整的;他们工作; (它们比这些具体的例子更复杂,但我用 C 编程的时间比你长;)但它们是玩具——有用的玩具。

回答by Lefteris

You can simply place a null termination character right where you want the string to end like so:

您可以简单地在您希望字符串结束的地方放置一个空终止字符,如下所示:

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

This would give you:

这会给你:

"I am a str"

“我是一个str”

回答by nneonneo

C is not like Python; string indices are not "smart". Saying str[-3]quite literally means "the character three bytes before the start"; accessing this memory is undefined behaviour.

C 不像 Python;字符串索引不是“智能”。话说str[-3]相当字面意思是“字符开始前三个字节”; 访问此内存是未定义的行为

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

如果你想把一个字符串的最后几个字符作为另一个字符串,获取一个指向你想要的第一个字符的指针就足够了:

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

If you want to deletethe last few characters, it suffices to set the kth-from-the-end character to a null (\0):

如果要删除最后几个字符,只需将第 k 个从末尾字符设置为空 ( \0) 即可:

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

回答by Hogan

No you have to use strlen() like this to get the last characters.

不,您必须像这样使用 strlen() 来获取最后一个字符。

##代码##

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

记住字符串是基于 0 的,所以这给你最后 3。

So the general technique is

所以一般的技术是

##代码##

(of course the string has to be longer than n)

(当然字符串必须长于n

If you want to get the last 3 use this:

如果您想获得最后 3 个,请使用以下命令:

##代码##

Or in general

或者一般

##代码##

回答by TheRookierLearner

I noted that substris not a standard C function and hence its not valid to use it in C. So, to find a substring by eliminating the last few characters one can use memcpy(new_string, old_string, strlen(old_string) - 3)

我注意到这substr不是标准的 C 函数,因此在 C 中使用它是无效的。因此,通过消除可以使用的最后几个字符来查找子字符串memcpy(new_string, old_string, strlen(old_string) - 3)