Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.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_Algorithm - Fatal编程技术网

C 从字符串中删除字符并在删除时动态调整其大小的算法

C 从字符串中删除字符并在删除时动态调整其大小的算法,c,algorithm,C,Algorithm,我正在编写一个算法,从动态大小的数组中删除所有引号,并在删除时减少其长度。以下是我目前的代码: void remove_quotations(char *str) { int len = strlen(str); for (int i = 0; i < len; i++) { if (str[i] == '\'') { for (int j = i; j < len - 1; j++) { st

我正在编写一个算法,从动态大小的数组中删除所有引号,并在删除时减少其长度。以下是我目前的代码:

void remove_quotations(char *str)
{
    int len = strlen(str);

    for (int i = 0; i < len; i++) {
        if (str[i] == '\'') {
            for (int j = i; j < len - 1; j++) {
                str[j] = str[j + 1];
            }
            len--;
            str = realloc(str, len);
        }
    }
}
输入示例:“1357”、“名称”、“主题”、“2”

预期输出:1357,名称,主题,2

我得到的:1357,名字,主题,2

正如您所看到的,引号按预期移动到了末尾,但是字符串并没有像应该的那样缩短


注意:我不是故意做任何错误检查。

当您向上移动字符串时,必须在新字符串的末尾添加0:

for (int j = i; j < len - 1; j++) {
    str[j] = str[j + 1];
}
str = realloc(str, len);
if (str) {
    str[j] = 0; //String ends with 0, so force 0 at the end of string.
}

关键是,您必须在字符串末尾插入0字符来手动关闭字符串。

当您向上移动字符串时,必须在新字符串的末尾添加0:

for (int j = i; j < len - 1; j++) {
    str[j] = str[j + 1];
}
str = realloc(str, len);
if (str) {
    str[j] = 0; //String ends with 0, so force 0 at the end of string.
}
关键是您必须通过在末尾插入0字符来手动关闭字符串

正如您所看到的,引号按预期移动到了末尾,但是字符串并没有像应该的那样缩短

好的,缩短的是分配给你的绳子的区域,这就是realloc做的。您忘记了缩短实际字符串:字符串的结尾总是有一个\0字节

因此,当您使用printf或put输出此字符串时,程序会导致未定义的行为-这些函数将一直读取,直到找到\0终止符为止,并且它不在realloc之后您可以合法访问的区域内

事实上,这似乎是完全偶然的:realloc没有给你一个新的地址,旧的内容仍然存在

代码中还有另一个错误:如果realloc给您一个不同的地址,它将无法工作,因为调用代码无法收回指针

旁注:

使用realloc时,将结果分配给临时变量。如果返回NULL,则必须释放原始变量

在循环之后,您只需要调用一次realloc

作为参考,固定和注释版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *remove_quotations(char *str)
{
    // always use the correct type, strlen returns size_t:
    // (int would only be a problem here for **huge** strings, still it's better
    //  getting used to ALWAYS use size_t for sizes.)
    size_t len = strlen(str);

    for (size_t i = 0; i < len; ++i)
    {
        if (str[i] == '\'')
        {
            // move following bytes *including* the final 0 terminator:
            memmove(str+i, str+i+1, len-i);
            --len;
        }
    }

    // include space for 0 terminator when shortening:
    char *tmp = realloc(str, len+1);
    if (!tmp)
    {
        free(str);
        return 0;
    }
    return tmp;
}

int main(void)
{
    char test[] = "'1357', 'name', 'topic', '2'";
    char *foo = malloc(strlen(test)+1);
    strcpy(foo, test);
    foo = remove_quotations(foo);
    if (foo)
    {
        puts(foo);
        free(foo);
    }
    return 0;
}
正如您所看到的,引号按预期移动到了末尾,但是字符串并没有像应该的那样缩短

好的,缩短的是分配给你的绳子的区域,这就是realloc做的。您忘记了缩短实际字符串:字符串的结尾总是有一个\0字节

因此,当您使用printf或put输出此字符串时,程序会导致未定义的行为-这些函数将一直读取,直到找到\0终止符为止,并且它不在realloc之后您可以合法访问的区域内

事实上,这似乎是完全偶然的:realloc没有给你一个新的地址,旧的内容仍然存在

代码中还有另一个错误:如果realloc给您一个不同的地址,它将无法工作,因为调用代码无法收回指针

旁注:

使用realloc时,将结果分配给临时变量。如果返回NULL,则必须释放原始变量

在循环之后,您只需要调用一次realloc

作为参考,固定和注释版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *remove_quotations(char *str)
{
    // always use the correct type, strlen returns size_t:
    // (int would only be a problem here for **huge** strings, still it's better
    //  getting used to ALWAYS use size_t for sizes.)
    size_t len = strlen(str);

    for (size_t i = 0; i < len; ++i)
    {
        if (str[i] == '\'')
        {
            // move following bytes *including* the final 0 terminator:
            memmove(str+i, str+i+1, len-i);
            --len;
        }
    }

    // include space for 0 terminator when shortening:
    char *tmp = realloc(str, len+1);
    if (!tmp)
    {
        free(str);
        return 0;
    }
    return tmp;
}

int main(void)
{
    char test[] = "'1357', 'name', 'topic', '2'";
    char *foo = malloc(strlen(test)+1);
    strcpy(foo, test);
    foo = remove_quotations(foo);
    if (foo)
    {
        puts(foo);
        free(foo);
    }
    return 0;
}

您最后需要放置“\0”

下线,

str[j]='\0'

以前


len-

您需要在最后放置'\0'

下线,

str[j]='\0'

以前


len-

我假设您使用类似的方法来检查字符串的内容:

printf("%s\n", str);
因此,问题是printf将输出它在内存中找到的所有字符,直到它到达一个终止\0字符

我会像这样更新您的函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *remove_quotations(const char *str)
{
    size_t len = strlen(str);
    char *dst = malloc(len+1);
    const char *r = str;
    char *w = dst;

    while (*r)
    {
        if (*r == '\'') --len;
        else *w++ = *r;
        ++r;
    }
    *w = 0;

    char *tmp = realloc(dst, len+1);
    if (!tmp)
    {
        free(dst);
        return 0;
    }
    return tmp;
}

int main(void)
{
    const char *test = "'1357', 'name', 'topic', '2'";
    char *foo = remove_quotations(test);
    if (foo)
    {
        puts(foo);
        free(foo);
    }
    return 0;
}
char* remove_quotations(char *str)
{
    int len = strlen(str);
    char *str_temp;

    for (int i = 0; i < len; i++) {
        if (str[i] == '\'') {
            /* go until len so that you shift the '\0' one position to the left */
            for (int j = i; j < len; j++) {
                str[j] = str[j + 1];
            }
            len--;
            /* no need to call realloc here every time */
        }
    }

    str_temp = realloc(str, len + 1);
    if (!str_temp) {
        printf("Memory allocation error!\n");
        free(str);

        return NULL;
    }

    return str_tmp;
}

我假设您使用类似这样的方法来检查字符串的内容:

printf("%s\n", str);
因此,问题是printf将输出它在内存中找到的所有字符,直到它到达一个终止\0字符

我会像这样更新您的函数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *remove_quotations(const char *str)
{
    size_t len = strlen(str);
    char *dst = malloc(len+1);
    const char *r = str;
    char *w = dst;

    while (*r)
    {
        if (*r == '\'') --len;
        else *w++ = *r;
        ++r;
    }
    *w = 0;

    char *tmp = realloc(dst, len+1);
    if (!tmp)
    {
        free(dst);
        return 0;
    }
    return tmp;
}

int main(void)
{
    const char *test = "'1357', 'name', 'topic', '2'";
    char *foo = remove_quotations(test);
    if (foo)
    {
        puts(foo);
        free(foo);
    }
    return 0;
}
char* remove_quotations(char *str)
{
    int len = strlen(str);
    char *str_temp;

    for (int i = 0; i < len; i++) {
        if (str[i] == '\'') {
            /* go until len so that you shift the '\0' one position to the left */
            for (int j = i; j < len; j++) {
                str[j] = str[j + 1];
            }
            len--;
            /* no need to call realloc here every time */
        }
    }

    str_temp = realloc(str, len + 1);
    if (!str_temp) {
        printf("Memory allocation error!\n");
        free(str);

        return NULL;
    }

    return str_tmp;
}

你所做的事情太复杂了。应保存源和目标索引,并将每个符号复制到目标:

void remove_quotations(char *str)
{
    int j = 0;
    for (int i = 0; str[i]; i++) {
        if (str[i] != '\'') {
            str[j++] = str[i];
        }
    }
    str[j] = 0;
}
这就是你所要做的


工作示例:

您正在做的事情太复杂了。应保存源和目标索引,并将每个符号复制到目标:

void remove_quotations(char *str)
{
    int j = 0;
    for (int i = 0; str[i]; i++) {
        if (str[i] != '\'') {
            str[j++] = str[i];
        }
    }
    str[j] = 0;
}
这就是你所要做的


工作示例:

您进行了哪些调试?您是否在调试器中运行了程序,或者做了其他任何尝试来查找问题?是的,我的预期输出来自调试。这是测试,而不是调试。调试意味着在代码运行时单步检查代码。如果您已经调试过,那么您将能够准确地告诉我们哪里/什么时候开始出错。@PoVa您可以通过使用链表来提高效率。首先,将字符存储到LL的节点中,遍历LL并在旁边删除带有“in it note”的节点。此处删除只需1次。最后从LL中形成一个字符数组。全面的

复杂性。虽然不相关,但在评论中回答了您的一个问题。@JohnZwinck-the-realloc不仅效率低下,而且是错误的。str是调用指针的本地副本,因此更改其值不会更改原始指针的值。您进行了哪些调试?您是否在调试器中运行了程序,或者做了其他任何尝试来查找问题?是的,我的预期输出来自调试。这是测试,而不是调试。调试意味着在代码运行时单步检查代码。如果您已经调试过,那么您将能够准确地告诉我们哪里/什么时候开始出错。@PoVa您可以通过使用链表来提高效率。首先,将字符存储到LL的节点中,遍历LL并在旁边删除带有“in it note”的节点。此处删除只需1次。最后从LL中形成一个字符数组。总体复杂性取决于。虽然不相关,但在评论中回答了您的一个问题。@JohnZwinck-the-realloc不仅效率低下,而且是错误的。str是调用指针的本地副本,因此更改其值不会更改原始指针的值。realloc调用是错误的,它会使调用指针无效,而不会更改它。它只更改本地副本字符串。realloc参数应为len+1。@Gurang VYAS他的循环没有在末尾添加“\0”。是的,@mch是正确的。我只是想指出他在这次活动中的主要问题。我将更新realloc调用以使其正确。realloc调用错误,它会使调用指针无效,而不会更改它。它只更改本地副本字符串。realloc参数应为len+1。@Gurang VYAS他的循环没有在末尾添加“\0”。是的,@mch是正确的。我只是想指出他在这次活动中的主要问题。我将更新realloc调用以使其正确。据我所知,您的版本也会因为memmove而修改主字符串。我一直在寻找一个不需要的解决方案。@PoVa但这正是您的原始代码所尝试的,在适当的位置执行此操作!复制时剥离字符的版本实际上看起来更简单。抱歉,我把事情弄混了:据我所知,您的版本也会修改主字符串,因为memmove。我一直在寻找一个不需要的解决方案。@PoVa但这正是您的原始代码所尝试的,在适当的位置执行此操作!复制时剥离字符的版本实际上看起来更简单一些。对不起,我把事情搞混了:Dlooks很好,可能需要更多的解释,我建议在这里也使用size\u t,谁知道字符串可以有多长;仍然+1看起来不错,也许有更多的解释,我建议在这里也使用size\u t,谁知道字符串可以有多长;仍然+1