1

私はCを学習していますが、malloc()を解放する方法を見つけるのに問題があります。

プログラムは正しく実行されます。しかし、im valgrindを使用すると、8つの割り当てと5つの解放が発生します。さらに3つ解放できるようにする必要があります。私は自分が解放していないと信じているところにコメントしましたが、解決策はわかりません。

それらの割り当てを解放する方法はありますか、それともtokenizer()の書き直しを検討する必要がありますか?

これがファイル全体のコードです。

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

char *substr(const char *s, int from, int nchars) {

   char *result = (char *) malloc((nchars * sizeof(char))+1);
   strncpy(result, s+from, nchars);

   return result;
}

/**
 Extracts white-space separated tokens from s.
 @param s A string containing 0 or more tokens.
 @param ntokens The number of tokens found in s.
 @return A pointer to a list of tokens. The list and tokens must be freed
 by the caller.
 */ 
char **tokenize(const char *s, int *ntokens) {
    int fromIndex = 0;
    int toIndex = 0;
    char **list;
    int finalCount = *ntokens;
    int count = 0;

    list = malloc(*ntokens * sizeof(char*));

    while ( count < finalCount) {

        char *m = strchr(s,' ');
        toIndex = m - s;

        if(toIndex >= 0) {
            list[count] = substr(s,fromIndex,toIndex); // This substr() gets free'ed from main()        
            s = substr(s, toIndex+1, strlen(s));    // I believe This is where I am making extra mallocs that are not being freed
            count++;
        } else {        
            list[count] = substr(s,fromIndex,strlen(s)); // This substr() gets free'ed from main()
            count++;
        }
    }   

    return list;
} 

int main(int argc, char **argv) {
  char **list;
  char *string = "terrific radiant humble pig";

  int count = 4; // Hard-Coded

  list = tokenize(string, &count);

  for (int i=0;i<count;i++) {
    printf("list[%d] = %s\n", i, list[i]);
  }

  // Free mallocs()'s
  for (int i=0;i<count;i++) {
    free(list[i]);
  }
  // Free List
  free(list);

  return 0;
}  
4

3 に答える 3

2

トークンを1つ取得した後は、毎回substrを使用する必要はありません。これは、時間とスペースの両方の点で無駄が多すぎます。sの値を変更して、必要な文字列を指すようにすることができます。

//s = substr(s, toIndex+1, strlen(s));    // You don't need have to generate a new string
s = s + toIndex + 1;//You can just change the value of s to make it point to the string you need
于 2013-03-02T03:28:21.830 に答える
0

問題はまさにあなたが思っていた場所です!幸いなことに、cでは、文字列が存在するポイントを移動するのは非常に簡単です。もう一度呼び出す必要はありませんsubstr。ポインタのため;-)

// s = substr(s, toIndex+1, strlen(s));   
s += toIndex+1;
于 2013-03-02T03:29:18.173 に答える
0

上書きする前に s の現在の値を別のポインターに格納するだけで、私が考えることができる簡単な回避策です。また、パラメータとして直接取得した s の最初の値を に解放しないように注意してくださいtokenize()

char **tokenize(const char *s, int *ntokens) {
    int fromIndex = 0;
    int toIndex = 0;
    char **list;
    int finalCount = *ntokens;
    int count = 0;
    bool firstTime = true; // Use this to make sure you do not free up the memory for the initial s passed as the function arg

    list = malloc(*ntokens * sizeof(char*));

    while ( count < finalCount) {
        char *m = strchr(s,' ');
        toIndex = m - s;

        if(toIndex >= 0) {
            const char* previous_s = s; // Store the current value of s
            list[count] = substr(s,fromIndex,toIndex); // This substr() gets free'ed from main()        
            s = substr(previous_s, toIndex+1, strlen(previous_s));
            if (!firstTime)
            {
                free(previous_s); // Since we're done with the previous_s, we can free up the memory
            }
            firstTime = false;
            count++;
        } else {        
            list[count] = substr(s,fromIndex,strlen(s)); // This substr() gets free'ed from main()
            count++;
        }
    }   

    if (!firstTime)
    {
        free(s); // There could be a block allocated last time which needs to be freed as well
    }

    return list;
}
于 2013-03-02T02:25:59.967 に答える