0

単純なプログラムであるべきものに問題があります。

void*ポインターを使用して、C で単一の連結リストの実装を作成しました。ただし、どこかにメモリリークの可能性があるため、問題がありますが、valgrind を使用してコードをチェックしたところ、そのようなエラーは検出されませんでした。

しかし、すべてのメモリがfree解放されても、まだ解放されていないメモリがあります(コメントを参照)...参照によって追加関数にすべてを渡そうとしましたが、これでも問題は解決しませんでした。

ここの誰かがコードを見てコメントを持っているかどうか疑問に思いました. (これは簡単なはずですよね?)

/*
 Wrapping up singley linked list inside a struct
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* Needed for: memcpy */

void waitKey(){
 printf("Press any key to continue...");
 getchar();
}

/* Define a structure for a list entry */
struct ListEntry {
 void* data;
 struct ListEntry* pNext;
};

/* Struct for list properties */
struct ListProperties {
 struct ListEntry* g_pLast;
 struct ListEntry* g_pHead;
 struct ListEntry* pCurrent;
 unsigned int size;
 int getHead;
};

/* Add:
 args: list, data, dyn (0 if not, else size of dynamic data)
*/
void add(struct ListProperties* l, void* d, unsigned long dyn) {
 struct ListEntry* pNew = malloc(sizeof(struct ListEntry));

 /* Set the data */
 if (dyn > 0){
  /* Allocate and copy array */
  pNew->data = malloc(dyn);
  pNew->data = memcpy(pNew->data,d,dyn);
 } else {
  pNew->data = d;
 }

 /* Set last element to point to new element */
 if (l->g_pLast != NULL){
  l->g_pLast->pNext = pNew;

  /* Get head of list */
  if (l->g_pHead == NULL && l->getHead == 0){
   l->g_pHead = l->g_pLast;
   l->getHead = 1;
  }
 } else {
  /* 1 elem case */
  l->g_pHead = pNew;
  l->pCurrent = pNew;
 }

 /* New element points to NULL */
 pNew->pNext = NULL;

 /* Save last element for setting 
    pointer to next element */
 l->g_pLast = pNew;

 /* Inc size */
 l->size++;
}

/* Create new list and return a pointer to it */
struct ListProperties* newList(){
 struct ListProperties* nList = malloc (sizeof(struct ListProperties));
 nList->g_pHead = NULL;
 nList->g_pLast = NULL;
 nList->getHead = 0;
 nList->size = 0;
 return nList;
}

/* Reset pointer */
int reset(struct ListProperties *l){
 if (l->g_pHead != NULL){
  l->pCurrent = l->g_pHead;
  return 0;
 }
 return -1;
}

/* Get element at pointer */
void* get(struct ListProperties *l) {
 if (l->size > 0){
  if (l->pCurrent != NULL){
   return l->pCurrent->data;
  }
 }
 return NULL;
}

/* Increment pointer */
int next(struct ListProperties *l){
 if (l->pCurrent->pNext != NULL){
  l->pCurrent = l->pCurrent->pNext;
  return 1;
 }
 return 0;
}

/* Get element at n */
void* getatn(struct ListProperties *l, int n) {
 if (l->size > 0){
  int count = 0;
  reset(l);
  while (count <= n){
   if (count == n){
    return l->pCurrent->data;
    break;
   }
   next(l);
   count++; 
  }
 }
 return NULL;
}

/* Free list contents */
void freeList(struct ListProperties *l){
 struct ListEntry* tmp;

 /* Reset pointer */
 if (l->size > 0){
  if (reset(l) == 0){
   /* Free list if elements remain */
   while (l->pCurrent != NULL){
    if (l->pCurrent->data != NULL)
     free(l->pCurrent->data);
    tmp = l->pCurrent->pNext;
    free(l->pCurrent);
    l->pCurrent = tmp;
   }
  }
 }

 l->g_pHead = NULL;
 l->g_pLast = NULL;

 l->size = 0;
 l->getHead = 0;

 free(l);
}

void deleteElem(struct ListProperties *l, int index){
 struct ListEntry* tmp;
 int count = 0;
 if (index != 0)
  index--;
 reset(l);
 while (count <= index){
  if (count == index){ // Prev element
   if (l->pCurrent != NULL){
    if (l->pCurrent->pNext != NULL){
     free(l->pCurrent->pNext->data); // Free payload
     tmp = l->pCurrent->pNext;
     l->pCurrent->pNext = l->pCurrent->pNext->pNext;
     free(tmp);
     if (l->size > 0)
      l->size--;
    } else {
     // Last element
     free(l->pCurrent->data);
     free(l->pCurrent);
     l->g_pHead = NULL;
     l->g_pLast = NULL;
     l->getHead = 0;
     l->size = 0;
    }
   }
   break;
  }
  if (next(l) != 1)
   break;
  count++;
 }
}

int size(struct ListProperties *l){
 return l->size;
}

int main( int argc, char* argv )
{
 int j = 0;
 unsigned long sz = 0;

 /*=====| Test 1: Dynamic strings |=====*/

 /* Create new list */
 struct ListProperties* list = newList();

 if (list == NULL)
  return 1;

 char *str;
 str = malloc(2);
 str = strncat(str,"A",1);
 sz = 2;

 printf("Dynamic Strings\n===============\n");

 /* Check memory usage here (pre-allocation) */
 waitKey();

 /* Add to list */
 for (j = 0; j < 10000; j++){
  add(list,(char*)str, sz);
  str = realloc(str, sz+2);

  if (str != NULL){
   str = strncat(str,"a",1);
   sz++;
  }
 }

 /* Allocated strings */
 waitKey();

 /* TESTING */
 freeList(list);
 free(str);

 /* Check memory usage here (Not original size!?) */
 waitKey();
 return 0;
}

ありがとう!

4

3 に答える 3

3

メモリ使用量をどのようにチェックしているのかはわかりませんがps、OSがプロセスに与えたメモリ量を確認するために、または同様のものを使用していると推測します。

メモリ アロケータによっては、呼び出しによってfreeメモリが OS に返される場合と返されない場合があります。したがって、 を呼び出してもfree、OS の観点からはメモリ フットプリントが減少することはありません。

アロケータは、OS によって割り当てられたメモリのキャッシュを保持する場合があります。への呼び出しmallocは、最初にこのキャッシュを調べて、十分な大きさのブロックを見つけることができるかどうかを確認します。見つかった場合mallocは、OS に追加のメモリを要求せずに戻ることができます。十分な大きさのブロックが見つからない場合はmalloc、OS にメモリの追加を要求し、それをキャッシュに追加します。

ただしfree、メモリをキャッシュに戻すだけで、OS に戻すことはありません。

したがって、アロケーターのキャッシュが表示され、メモリ リークが表示されない可能性があります。

于 2010-03-05T20:23:50.540 に答える
0

前述のように、タスクマネージャーによって報告されたメモリ使用量は信頼できません。タスクマネージャーに影響を与える他の要因(malloc / freeの実装方法など)が制御できないためです。

メモリリークをテストする1つの方法は、既存のラッパー関数と次のような関数を作成するmallocことfreeです。

void* my_malloc(size_t len) {
    void* ptr = malloc(len);
    printf("Allocated %u bytes at %p\n", len, ptr);
    return ptr;
}

void my_free(void* ptr) {
    printf("Freeing memory at %p\n", ptr);
    free(ptr);
}

これで、動的に割り当てまたは解放されたすべてのメモリのログを取得できます。ここから、メモリのブロックをリークするかどうかはかなり明白です(プログラムが複雑になるほど、ログが長くなり、このタスクが難しくなります)。

于 2010-03-05T21:31:03.020 に答える
0

あなたのプログラムにはargv、主な誤り、誤った使用法strncat、および奇妙なメモリ割り当てが含まれています。これらのいくつかは、警告として表示されるはずです。argv は問題ではありませんが、他のものが警告として表示された場合は、それらに注意する必要があります。警告を無視しないでください。

これらの変更により、クリーンアップされます。NULL 最大の問題は、C 文字列を終了するために使用される NUL ('\0') 文字 ( pointerとは異なる) と、それがどのように影響するかについてよく理解していないようだということstr(n)catです。

str* 関数とメモリ関数 (*alloc/free) の混合使用は、おそらく混乱の一部でした。気をつけて。

 #include <assert.h>
 ...
 int main( int argc, char* argv[] )       /* or int main(void) */
 ...
 sz = 2;
 str = (char*) malloc(sz);       /* allocate 2 bytes, shortest non-trivial C string */
 assert(str != NULL);
 strncpy(str, "A", sz);          /* copy 'A' and '\0' into the memory that str points to */
 ...
/* Add to list */
 for (j = 0; j < 10000; j++){
  add(list, str, sz);
  str = realloc(str, ++sz);      /* realloc str to be one (1) byte larger */
  assert(str != NULL);

  strncat(str, "a", sz - strlen(str));    /* now insert an 'a' between last 'A' or 'a' and '\0' */
  assert(str != NULL);
 }
于 2010-03-05T21:53:29.407 に答える