Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从C中的字符串中删除最后几个字符_C - Fatal编程技术网

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

如何从C中的字符串中删除最后几个字符,c,C,我知道我可以使用substr()从字符串中获取第一个n字符数。但是,我想删除最后几个字符。在C语言中使用-2或-3作为结束位置是否有效,就像我在Python中所做的那样?不,您必须像这样使用strlen()来获取最后的字符 substr(strlen(str)-4,3); 请记住,字符串是基于0的,因此这将给出最后3个字符串 所以一般的技术是 substr(strlen(str)-n-1,n); (当然,字符串必须长于n) 如果要获取最后3个,请使用以下命令: substr(0,strlen

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

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

substr(strlen(str)-4,3);
请记住,字符串是基于0的,因此这将给出最后3个字符串

所以一般的技术是

substr(strlen(str)-n-1,n);
(当然,字符串必须长于
n

如果要获取最后3个,请使用以下命令:

substr(0,strlen(str)-4);
或者总体上

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

您只需将空终止字符放在希望字符串结束的位置,如下所示:

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

“我是str”


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

如果要将字符串的最后几个字符作为另一个字符串获取,只需获取指向所需第一个字符的指针即可:

char *endstr = str + (strlen(str) - 3); // get last 3 characters of the string
如果要删除最后几个字符,只需将结尾字符的第k个字符设置为空(
\0
):


我注意到
substr
不是一个标准的C函数,因此在C中使用它是无效的。因此,要通过删除最后几个字符来查找子字符串,可以使用
memcpy(new\u string,old\u string,strlen(old\u string)-3)
下面是
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] = '\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 */
测试输出:

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

在对另一个人的评论中,询问:

为什么这不起作用:
memcpy(新字符串、旧字符串、strlen(旧字符串)-3;
假设
new\u字符串
old\u字符串
都是
char
指针和
strlen(旧字符串)>3

假设您删除了
,则插入缺少的
,指针指向有效的非重叠位置,并且满足长度条件,则可以将旧字符串中除最后3个字符以外的所有字符复制到新字符串中,因为您可以通过将其嵌入某些测试代码进行测试。它不会试图复制旧字符串的最后三个字符,而这正是问题的主要问题

#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);
}
#包括
#包括
内部主(空)
{
char new_字符串[32]=“XXXXXXXXXXXXXX”;
char old_string[]=“string”;
memcpy(新字符串、旧字符串、strlen(旧字符串)-3;
新字符串[strlen(旧字符串)-3]='\0';
printf(“\n”,旧字符串,新字符串);
返回(0);
}
输出:

<<string>> <<str>>
<<dandelion>> <<ion>>

然而,要小心狡猾的巧合;我选择了一个6个字符长的旧字符串示例,-3表示“length-3”也等于3。要获取最后N个字符,您需要类似以下代码:

#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);
}
#包括
#包括
#包括
内部主(空)
{
int N=3;
char new_字符串[32]=“XXXXXXXXXXXXXX”;
char old_string[]=“蒲公英”;
int sublen=strlen(旧字符串)-N;
断言(子项>0);
memcpy(新字符串、旧字符串+子字符串、N);
新的_字符串[N]='\0';
printf(“\n”,旧字符串,新字符串);
返回(0);
}
输出:

<<string>> <<str>>
<<dandelion>> <<ion>>

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

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


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

这给了我最后3个还是删除了最后3个?因为我想删除最后3个。嘿,我只是注意到这是一个C++语法而不是C语法。这在C中也适用吗?值得注意的是,这是因为
s
是一个字符缓冲区,而不是一个常量字符串。是的,在[C]中的许多情况下都适用标签有一个问题,为什么这样的代码在与char*st这样的字符串文字一起使用时会崩溃,而char*st不会给您一个以null结尾的字符串…如果
strlen(old_string)<3
,它也会遇到问题。您能指出一条路吗?我的意思是使用
memcpy
或任何其他方式获得一个以null结尾的字符串?@JonathanLeffler-为什么不起作用:
memcpy(新字符串、旧字符串、strlen(旧字符串)-3;&new字符串[strlen(旧字符串)-3]='\0'
假设
new字符串
old字符串
都是字符指针和strlen(旧字符串)>3