从字符串数组中删除字符串(C)

时间:2013-11-24 22:32:31

标签: c string memory-management malloc realloc

我有一个包含一些字符串的指针数组(char **)。数组以空字符串('\ 0')结尾。我应该在该字符串数组中搜索特定单词并删除整行(ofc使用realloc并缩短字符串数组)。我很难做到这一点,我一直得到'糟糕的ptr'错误。

我的代码:

void deleteSentence(char **text){
    char *word,*fptr;
    int i=0;
    word=(char*)calloc(BUFFER,sizeof(char));
    printf("Enter word to delete sentences:\n");
    gets(word);
    while(text[i][0]!='\0'){
        char *str=(char*)malloc((strlen(text[i])+1)*sizeof(char));
        strcpy(str,text[i]);
        fptr=strtok(str,DELIM);
        while(fptr!=NULL){
            if(strcmp(fptr,word)==0){
                int j=i;
                while(text[j][0]!='\0'){
                    text[j]=(char*)realloc(text[j],(strlen(text[j+1]))*sizeof(char));
                    strcpy(text[j],text[j+1]);
                    j++;
                }
                free(text[j]);
            }
            fptr=strtok(NULL,DELIM);
            if(fptr!=NULL)
                i++;
        }
    }
}

非常感谢:)

1 个答案:

答案 0 :(得分:2)

你正在泄漏记忆,就像筛子漏水,并且至少在两个地方超过你的阵列。此外,输入与此代码的功能目的的集成实际上 nothing 可以提供帮助。该函数应该只做一件事:

  

给定指向以空字符串(或NULL)结尾的char*指针数组的指针,删除指针数组中包含 word 的所有字符串。生成的可能压缩的数组是函数的返回值。

考虑一下:

char ** deleteSentances(char **text, const char *word)
{
    char **dst = text, **src = text, **res = text;
    size_t size = 1, deleted = 0;

    // loop while we have a non-null string that isn't empty
    while (*src && (*src)[0])
    {
        char *tmp = strdup(*src);
        if (tmp == NULL)
        {
            perror("Failed to allocate tmp");
            exit(EXIT_FAILURE);
        }

        char *token = strtok(tmp, DELIM);

        // search for matching word
        while (token && strcmp(word, token))
            token = strtok(NULL, DELIM);

        // if not found, keep the string. otherwise delete it.
        if (!token)
        {
            *dst++ = *src++;
            size++;
        }
        else
        {
            free(*src++);
            ++deleted;
        }

        // don't need this.
        free(tmp);
    }

    // resize the original array (which could have only gotten smaller)
    if (deleted > 0)
    {
        res = realloc(text, size * sizeof(*res));
        if (res == NULL)
        {
            perror("Failed to allocate res");
            exit(EXIT_FAILURE);
        }
        res[size-1] = *src;
    }

    return res;
}

希望这足以解释。代码的调用方式如下:

char **text, *word;

//... populate text with strings
//... populate word with prospect word

text = deleteSentances(text, word);

内存泄漏O'Festival

OP希望了解原始发布算法中内存泄漏的位置。首先考虑以下几点:对于每个分配,应该有一个已知的点,即释放那个记忆。这个例子有点难以说明这个概念,因为你动态分配带到函数中,并且中的一些将被保留。

尽管如此,请考虑以下景点。我们假设在某种程度上我们分配了这种形式的指针数组:

char **text = malloc(N * sizeof(*text));

即。我们有N个字符点。在每一个中,我们进一步假设字符串的动态分配也已经发生:

for (int i=0; i<(N-1); ++i)
{
    //... compute length of next string

    text[i] = malloc(length * sizeof(**text));

    //... copy in next string to text[i]

}

最后,text数组中的最后一个字符指针是NULL或指向长度为0的动态字符串(即0长度终止的字符串)。

呼。好。毕竟,让我们来看看你的算法:

void deleteSentence(char **text)
{
    char *word,*fptr;
    int i=0;

    // Leak 1: allocate a single buffer of BUFFER-length.
    //  this is never freed anywhere in this function
    word=(char*)calloc(BUFFER,sizeof(char));

    printf("Enter word to delete sentences:\n");

    // Problem: gets() is so evil and bad it has been deprecated from
    //  the C langage and will not be available in the next release.
    //  use fgets() instead.
    gets(word);

    while(text[i][0]!='\0')
    {
        // Leak 2: Done N times, where N is the number of strings in
        //  your original array. again, this is never freed.
        char *str=(char*)malloc((strlen(text[i])+1)*sizeof(char));
        strcpy(str,text[i]);
        fptr=strtok(str,DELIM);

        while(fptr!=NULL)
        {

            if(strcmp(fptr,word)==0)
            {
                int j=i;
                while(text[j][0]!='\0')
                {
                    // Leak 3: Done M-N times for ever string we find in position
                    //  M of the original array. This can be *huge* if there are
                    //  a decent number of number of reductions that crunch your
                    //  original array down.
                    text[j]=(char*)realloc(text[j],(strlen(text[j+1]))*sizeof(char));
                    strcpy(text[j],text[j+1]);
                    j++;
                }

                // Problem: this just freed the termination string, which should
                //  never be done. We now have undefined behavior for the rest
                //  of this algorithm since the terminatingg string is invalid.
                free(text[j]);

                // Problem: You shoud break right here. See below for why
            }

            // Problem: you're missing an else condition here. At this point
            //  if the strcmp() found a match there is no reason to continue
            //  the loop. You found a match and deleted the string, crunching
            //  all the other string down one slot in a most-inefficient
            //  memory-leaking algorihm.

            fptr=strtok(NULL,DELIM);

            // Problem: the logic here is completely wrong. The i in this case
            //  should be incremented OUTSIDE the inner while loop. Furthermore
            //  the test is backwards.
            if(fptr!=NULL)
                i++;
        }
    }
}

简而言之,如果有可能泄漏更多内存,那么我很难看到如何。我提供的发布代码将在我提供的描述的范围内工作,并且应该仔细查看,甚至通过调试器行y线,以更好地理解它是如何工作的。< / p>