【问题标题】:C String Pointer Function strdelC 字符串指针函数 strdel
【发布时间】:2013-11-10 20:35:32
【问题描述】:

谁能解释一下为什么我得到“Segmentation fault...”以及如何在这段代码上修复它?

#include<stdio.h>

int str_length(char *s) {
    int length = 0, i;
    for(i = 0; *s; i++) {
        s++;
    }
    return i;
}

char *strdel(char *s, int pos, int n) {
    int i;
    char *p, str[] = "";
    p = str;
    for(i = 0; i < str_length(s) - n + 1; i++)  {
        if(i >= pos) {
            *(p + i) = *(s + i + n);
        }
        else {
            *(p + i) = *(s + i);
        }
    }
    s = str;
    return s;
}

int main() {
    char *str = "abcdef";
    printf("str_lengh: %d\n", str_length(str));
    printf("strdel: %s\n", strdel(str, 1, 2));
    return 0;
}

我得到这个输出:

str_lengh: 6
strdel: adef
Segmentation fault (core dumped)

另外,有没有更好的方法来创建一个函数: char *strdel(char *s, int pos, int n); 从位置 pos 删除的 n 个字符比我删除的字符多?

【问题讨论】:

  • 为了解决您的第二个问题,我会使用memmove()。你有一个循环来计算每次迭代的字符串长度,这不会很有效。
  • char * strdel(char * s, int pos, int n){ memmove(s + pos, s + pos + n, strlen(s) - n + 1); return s; } 应该这样,尽管它不会复制。它也不做任何边界检查。

标签: c arrays function pointers cstring


【解决方案1】:

我认为你在这里写的都是堆栈......

char *strdel(char *s, int pos, int n) {
    int i;
    char *p, str[] = "";
    p = str; // p points to str which is "" and is on the stack with length 0.
    for(i = 0; i < str_length(s) - n + 1; i++)  {
        if(i >= pos) {
            *(p + i) = *(s + i + n); // now you are writing onto the stack past p
        }
        else {
            *(p + i) = *(s + i);// now you are writing onto the stack past p
        }
    }
    s = str; // now s points to space on stack
    return s; // now you return a pointer to the stack which is about to disapear 
}

每当你写超过 p 时,通常情况下,你都会遇到未定义的行为。 UB 您正在写入尚未在堆或堆栈上分配的空间。

您可以编写一个仅适用于 s 的 strdel 版本。如果我理解 strdel 是这样的:(大致上,未经测试!,需要对 pos 和 n 进行边界检查)

char *strdel(char *s, int pos, int n) {
    char *dst = s + pos, *src = s + pos + n;
    while(*src) {
        *dst++ = *src++;
    }
    *dst = 0;
    return s;
}

【讨论】:

    【解决方案2】:

    为了解决您问题的第二部分,我会这样写(假设您要传入字符串常量,因此必须复制传入的字符串):

    /*
     * Returns a copy of the NUL terminated string at s, with the
     * portion n characters long starting at position pos removed.
     */
    char* strdel(char* s, int pos, int n)
    {
        int size = strlen(s);
        char* t = malloc(size - n);
        memcpy(t, s, pos);
        memmove(t + pos, s + pos + n, size - n + 1);
        return t;
    }
    

    【讨论】:

      【解决方案3】:

      我也会为第二部分提供我的解决方案。这是我的strdel

      char * strdel(char * s, int pos, int n){ 
          memmove(s + pos, s + pos + n, strlen(s) - pos - n + 1); 
          return s;
      }
      

      它不复制,不做边界检查,而且返回值相当多余(因为它等于输入s)。总而言之,它非常类似于标准的 C 库。

      警告!不能用于字符串常量,因为它修改了s(因此没有const char * s)。

      【讨论】:

      • @Mike 在 question-cmets 中给出了非常有用的提示。 :)
      • 是的,这也是我一直在考虑的解决方案,直到我看到他正在传递字符串常量。 =)
      • 一个简单的char str[] = "..."; 应该可以解决这种情况。
      • 循环直到你点击'\0'实际上可能更有效,因为你不必计算字符串的长度然后再次遍历它。
      • 也许,请记住 memmove 可能已经过高度优化 [需要引用],所以它可能同样快。
      猜你喜欢
      • 1970-01-01
      • 2012-03-10
      • 1970-01-01
      • 2016-10-12
      • 2014-10-29
      • 1970-01-01
      • 2022-08-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多