从C中的字符串中删除指定数量的字符

时间:2013-08-21 14:49:38

标签: c string

我不能为从字母S中删除N个字符的函数编写一个可行的代码,从位置P开始。你们会怎么写这样的函数?

void remove_substring(char *s, int p, int n) {

    int i;

    if(n == 0) {
        printf("%s", s);
    }

    for (i = 0; i < p - 1; i++) {
        printf("%c", s[i]);
    }

    for (i = strlen(s) - n; i < strlen(s); i++) {
        printf("%c", s[i]);
    }


}

示例:

s: "abcdefghi"
p: 4
n: 3

输出:

abcghi

但对于像n = 0和p = 1这样的情况,它不起作用! 非常感谢!

6 个答案:

答案 0 :(得分:4)

有些人向您展示了如何做到这一点,但他们的大多数解决方案都是高度浓缩的,使用标准库函数或者根本不解释正在发生的事情。这是一个版本,不仅包括一些非常基本的错误检查,还包括对正在发生的事情的一些解释:

void remove_substr(char *s, size_t p, size_t n)
{
  // p is 1-indexed for some reason... adjust it.
  p--;

  // ensure that we're not being asked to access
  // memory past the current end of the string.
  // Note that if p is already past the end of
  // string then p + n will, necessarily, also be
  // past the end of the string so this one check
  // is sufficient.
  if(p + n >= strlen(s))
    return;

  // Offset n to account for the data we will be
  // skipping.  
  n += p;

  // We copy one character at a time until we 
  // find the end-of-string character
  while(s[n] != 0)
    s[p++] = s[n++];

  // And make sure our string is properly terminated.  
  s[p] = 0;
}

需要注意的一点需要注意:请不要将此功能称为:

remove_substr("abcdefghi", 4, 3);

或者像这样:

char *s = "abcdefghi";

remove_substr(s, 4, 3);

这样做会导致未定义的行为,因为字符串文字是只读的,标准不允许修改它们。

答案 1 :(得分:3)

严格来说,您没有实现删除子字符串:您的代码会打印原始字符串并删除一系列字符。

另外需要注意的是,根据您的示例,索引p是基于1的,而不是基于零的,因为它在C中。否则"abcdefghi", 4, 3的输出将是{{ 1}},而不是"abcdhi"

考虑到这一点,让我们做一些改变。首先,你的数学有点偏差:最后一个循环应如下所示:

"abcghi"

Demo on ideone.

如果您想使用C的从零开始的索引方案,请按如下方式更改循环:

for (i = p+n-1; i < strlen(s); i++) {
    printf("%c", s[i]);
}

此外,您应该从顶部的for (i = 0; i < p; i++) { printf("%c", s[i]); } for (i = p+n; i < strlen(s); i++) { printf("%c", s[i]); } 返回,或添加if

else

if(n == 0) {
    printf("%s", s);
    return;
}

或完全删除if(n == 0) { printf("%s", s); } else { // The rest of your code here ... } :它只是一种优化,没有它你的代码也能正常工作。

目前,当ifn时,您的代码会打印两次原始字符串。

如果您想让代码删除子字符串并返回结果,则需要分配结果,并将打印替换为复制,如下所示:

0

请注意,此新版本的代码会返回动态分配的内存,使用后需要char *remove_substring(char *s, int p, int n) { // You need to do some checking before calling malloc if (n == 0) return s; size_t len = strlen(s); if (n < 0 || p < 0 || p+n > len) return NULL; size_t rlen = len-n+1; char *res = malloc(rlen); if (res == NULL) return NULL; char *pt = res; // Now let's use the two familiar loops, // except printf("%c"...) will be replaced with *p++ = ... for (int i = 0; i < p; i++) { *pt++ = s[i]; } for (int i = p+n; i < strlen(s); i++) { *pt++ = s[i]; } *pt='\0'; return res; } d。

这是demo of this modified version on ideone

答案 2 :(得分:2)

尝试复制字符串的第一部分,然后复制第二部分

char result[10];
const char input[] = "abcdefg";

int n = 3;
int p = 4;

strncpy(result, input, p);
strncpy(result+p, input+p+n, length(input)-p-n);

printf("%s", result);

答案 3 :(得分:2)

如果您希望在不使用strcpystrncpy等功能的情况下执行此操作(我在评论中看到您这样做),请使用类似的方法strcpy(或者至少有一种可能的变体)在引擎盖下工作:

void strnewcpy(char *dest, char *origin, int n, int p) {
    while(p-- && *dest++ = *origin++)
        ;
    origin += n;
    while(*dest++ = *origin++)
        ;
}

答案 4 :(得分:1)

你尝试了什么? strcpy(s+p, s+p+n)不起作用吗?

编辑:已修复以不依赖strcpy中的未定义行为:

void remove_substring(char *s, int p, int n)
{
    p--; // 1 indexed - why?
    memmove(s+p, s+p+n, strlen(s) - n);
}

如果您的心脏确实设置了它,您还可以用循环替换memmove来电:

char *dst = s + p;
char *src = s + p + n;
for (int i = 0; i < strlen(s) - n; i++)
    *dst++ = *src++;

如果你这样做,你也可以删除strlen电话:

while ((*dst++ = *src++) != '\0);

但我不确定我是否建议将其压缩得那么多。

答案 5 :(得分:1)

元代码:

  • 为目的地分配缓冲区
  • decalre指向源字符串的指针
  • 推进源字符串中的指针“p-1”位置,并将它们即时复制到目标
  • 提前“n”位置
  • 将休息时间复制到目的地