通过删除字符而不创建新字符串来编辑字符串,这是否合法?

edit a string by removing characters without creating a new string, is it legit or not?

编辑:我想我已经理解这个概念是如何工作的,这是我的代码

void delete_duplicate(char* str) {
    if (str == NULL) {
        exit(1); 
    }
    for (size_t i = 0; str[i] != 0; i++) {
        if (str[i] == str[i + 1]) {
            str[i] = '[=10=]';
        }
    }
}


    int main(void) {
    char str[] = "hhhhhhhheeeeeeeeyyyyyyyyyyy"; 
    delete_duplicate(str); 
    return 0; 
} 

输出字符串是“00...0h0...000e0...000y”(有很多零)。如果字符串是“abbbb”,则字符串变为“a”而不是“ab”。


我在考虑这个练习的算法:

given a string, for example "ssttringg" the output must be "string". the function has to remove one character if and only if the current character and the next character are the same.

该练习需要一个像这样声明的函数:

extern void delete_consecutive(char* str);

这是我的算法:

关键部分:动态内存分配。

如果不清楚,我会编辑问题。

如果作为参数传递的字符串是可修改的,您可以修改它。

示例:

void deleteFirstChar(char *str)
{
    if(str && *str)
    {
        
        memmove(str, str + 1, strlen(str));
    }
}

//illegal call
//string literals cannot be changed
void foo(void)
{
    char *str = "Hello";
    deleteFirstChar(str);
}

//legal call
void bar(void)
{
    char str[] = "Hello";
    deleteFirstChar(str);
}

这不是答案,但请考虑以下代码:

    char str[] = "strunqg";
    printf("before: %s\n", str);
    modifystring(str);
    printf("after:  %s\n", str);

其中“modifystring”函数如下所示:

void modifystring(char *p)
{
    p[3] = 'i';
    p[5] = p[6];
    p[6] = '[=11=]';
}

这完全是“合法的”。但是,调用

是行不通的
    char *str = "strunqg";
    modifystring(str);            /* WRONG */

    modifystring("strunqg");      /* WRONG */

后两个中的任何一个都会尝试修改字符串文字,而这并不复杂。

void delete_duplicate(char* str)
{
    if(str && *str)
    {
        char *writeTo = str, *readFrom = str;
        char prev = 0;
        while(*readFrom)
        {
            if(prev != *readFrom)
            {
                prev = *readFrom++;
                *writeTo++ = prev;
            }
            else
            {
                readFrom++;
            }
        }
        *writeTo = 0;
    }
}


int main(void) 
{
    char str[] = "hhhhhhhheeeeeeeeyyyyyyyyyyy"; 
    delete_duplicate(str); 
    printf("`%s`\n", str);
    return 0; 
}  

此模式称为 保留扫描(也称为 缩减扫描,具体取决于您的观点),并且是 非常 在根据某些条件指示丢弃字符同时保留其他字符的算法中很常见。通常情况会发生变化,有时甚至开始扫描的方法也会有所改变

在最简单的形式中,它看起来像这样,例如:一种用于丢弃除数字(数字)字符以外的所有字符的算法:

  1. 从 reader r 和 writer w 指针开始。
  2. 使用 r 从头到尾遍历字符串。 r 指针将始终 每次迭代恰好递增一次。
  3. 对于每次迭代,检查r处的当前字符是否满足保留条件(在这种情况下,字符是数字字符吗?)。如果是,写在 w 并提前 w 一个槽位。
  4. 完成时。 w 将指向您的终止符所在的位置。
#include <ctype.h>

void delete_nondigits(char *s)
{
    if (s && *s)
    {
        char *w = s;
        for (char *r = s; *r; ++r)
        {
            if (isdigit((unsigned char)*r))
                *w++ = *r;
        }
        *w = 0;
    }
}

很简单。

现在,in-place consecutive-run 压缩的算法更复杂,但具有高度相似的模型。因为留存是基于 prior-value already-retained,所以您需要记住 last-kept 值。您 可以 只使用 *w,但如果您将算法保存在单独的备忘录中 char,该算法实际上更容易理解(并推进 w)正如您即将看到的那样:

  1. 像以前一样从 reader r 和 writer w 指针开始,但是从字符串的 second 槽开始,并且单个备忘录 char 变量 c 初始化为字符串的第一个字符。
  2. 使用 r 遍历字符串直到遇到终止。 r 指针将始终 每次迭代恰好递增一次。
  3. 对于每次迭代,检查 *r 处的当前字符是否与备注字符相同 c 如果是,则什么都不做并继续下一次迭代。
  4. 否则,如果 *r 处的字符与备注字符 c 不同,则将其保存为 c 的新值, 写入 *w, 前进 w 一个槽位.
  5. 完成后,通过在 *w 处设置终止符来终止字符串。

该算法的唯一障碍是在开始时支持 zero-length 字符串,通过首先检查单个条件可以轻松规避该字符串。我离开实际实施它作为你的练习。 (提示:仅当 (s && *s) 为真时才执行上述操作)。