0

私はクラスのためにこのプログラムを書いています。このプログラムは、スタックを使用した単純な括弧チェッカー アプリケーションです。この場合、静的配列を使用してスタック データ構造を実装しました。プログラムは正常にビルドされますが、このランタイム エラーが発生し、これまでのところ問題の原因を特定できませんでした。

malloc を使用して割り当てられていないメモリを解放しようとしたことが問題の原因である可能性があることを私が理解している情報はほとんどありません。しかし、次のコードでは、これがどこで発生しているのかわかりません。

以下は、静的配列を使用したスタックのインターフェース実装コードです。また、スタックに文字を追加するためのスタック インターフェイス コードと、ルーチンをテストするためのドライバー プログラムも追加しました。

#include "stack.h"
#include "stdlib.h" /* malloc, free */
#include "stdio.h"

#define MAXSTACKSIZE 10

struct stack_record {
  generic_ptr base[MAXSTACKSIZE];
  generic_ptr * top;
};

unsigned int num_elements(stack * const p_S)
{
  unsigned int numels = ((*p_S)->top - (*p_S)->base);
  /*  return ((*p_S)->top - (*p_S)->base); */
  printf("number of elements in the stack is: %u\n", numels);
  return numels;
}
status init_stack(stack * const p_S)
{
  stack_record * record = (stack_record *)malloc(sizeof(stack_record));
  if(record == NULL) {
    return ERROR;
  }
  record->top = record->base;
  *p_S = record;
  return OK;
}
bool empty_stack(stack * const p_S)
{
  if(num_elements(p_S) == 0)
    {
      printf("stack is EMPTY!\n");
      return TRUE;
    }
  else
    {
      printf("stack NOT Empty!\n");
      return FALSE;
    }
}
status push(stack * const p_S, generic_ptr const data)
{
  if (num_elements(p_S) == MAXSTACKSIZE)
    return ERROR;

  *( (*p_S)->top ) = data;
  (*p_S)->top++;
   return OK;
}

status pop(stack * const p_S, generic_ptr * const p_data)
{
  if (empty_stack(p_S) == TRUE)
    return ERROR;
  *p_data = *((*p_S)->top);
  (*p_S)->top--;
  /*  ((*p_S)->top)--; */
  return OK;
}

status top(stack *const p_S, generic_ptr * const p_data)
{
   if (pop(p_S, p_data) == ERROR)
    return ERROR;

  return push(p_S, *p_data);
}

void destroy_stack(stack * const p_S, void (* const p_func_f)())
{
  if ((p_func_f) != NULL) {
    generic_ptr * curr;    
    for(curr = (*p_S)->top;
    curr != (*p_S)->base;
    ++curr)
          (*p_func_f)(*curr);
  }
  free(*p_S); /*free the dynamically allocated memory on the heap */
  *p_S = NULL;
 }

以下は、文字用のスタック インターフェイス ルーチンです。

/*************************************************************************/
/* adapted from Esakov and Weiss, Section 5.2                            */
/*************************************************************************/

#include "char_stack.h"
#include "stdlib.h" /* malloc */
#include "stdio.h"
#define DEBUG 1 

status push_char(stack * const p_S, char const c)
{
  /*
   *     Push the character c onto the stack.
   */
  char * p_c = (char *) malloc(sizeof(char));

  if(p_c == NULL)
    return ERROR;
  *p_c = c;

  if(DEBUG)
  /* Debug code: begin */
  {
    printf("Character to PUSH on the stack: %c\n", *p_c);
  }
  /* Debug code: end */

  if (push(p_S, (generic_ptr)p_c) == ERROR) {
    if(DEBUG)
      printf("char_stack: push_char: failed to push the character on the stack!\n");
    free(p_c);
    return ERROR;
  }
  return OK;
}

status pop_char(stack * const p_S, char * const p_c)
{
  /*
   *     Pop the stack. Return the character in p_c.
   */

  generic_ptr p_data;

  if( pop(p_S, &p_data) == ERROR)
    return ERROR;

  *p_c = *((char*)p_data);

  if(DEBUG)
  /*Debug code: begin */
printf("char_stack.c::pop_char: Character to POP on the stack: %c\n", *p_c);

  /*Debug code: end */

   free(p_data);
   return OK;
}

status top_char(stack * const p_S, char * const p_c)
{
  /*
   *     Return the top character from the stack in p_c
   */
  generic_ptr p_data;

  if (top(p_S, &p_data) == ERROR)
    return ERROR;

  *p_c = *((char *)p_data); 
  return OK;
}

アプリケーションのドライバー プログラム:

/**************************************************************************/
/* adapted from Esakov and Weiss, Section 5.2                             */
/**************************************************************************/

#include "stdio.h"
#include "stdlib.h"
#include "char_stack.h"

char matching_symbol(char const c)
{
  switch(c) {
    case '(': return ')';
    case ')': return '(';
    case '}': return '{';
    case '{': return '}';
    case '[': return ']';
    case ']': return '[';
  }
  return 0;
}

status consume_char(stack * const p_S, char input)
{
  switch (input) {
    case '(':
    case '{':  
    case '[':
      return push_char(p_S, input); 
    case ')':
    case '}':
    case ']':
      { 
        char c;    
        if (pop_char(p_S, &c) == ERROR || c != matching_symbol(input)) { 
          return ERROR;
        } else {
          return OK;
        }
      }
    default:
      return OK; 
  }
}

int main(int argc, char * argv[])
{

  if (argc == 1) {
    exit(EXIT_SUCCESS);
  }

  {
    stack S;

    init_stack(&S);

    {
      char *ptr;
      for (ptr = argv[1];
           *ptr != '\0' && consume_char(&S, *ptr) == OK;
           ++ptr); 
      if (*ptr == '\0' && empty_stack(&S)) { 

    destroy_stack(&S,free);
        exit(EXIT_SUCCESS);
      } else {
    destroy_stack(&S,free);
        exit(EXIT_FAILURE);
      }
    }
  }  

  exit(EXIT_SUCCESS);  
}

ドライバープログラムに追加したいのですが、スタックを破棄する呼び出しがこの問題の原因であると絞り込みました。しかし、このコードを確認したところ、このコードは問題なく、問題は別の場所にあると考えています。

[編集 1]: 完全を期すために、これらの関数が呼び出されているドライバー コードを追加しました。[編集 2]: キャラクター用のスタック インターフェイス ルーチンを追加しました。

4

2 に答える 2

1

エラー メッセージは、値 0x7b を に渡したことを示していますfree。このような小さな数値は、 から返されるメモリ ブロックのアドレスにはなりませんmalloc。というわけで、大まかに以下の3つの可能性があります。

  1. 完全に初期化されていないポインタがたまたま 0x7b になっていて、それを に渡していfreeます。
  2. 0 を含むポインターで開始し、0x7b ずつインクリメントして、それを に渡しましたfree
  3. 有効なポインター値を 0x7b に置き換えた、より創造的なメモリ破損エラーがあります。

最速の方法は、プログラムを valgrind の下で実行し、これがどこで起こっているかを教えてもらうことです。gdb のあちこちにブレークポイントを配置して、表示される内容を確認することもできます。

于 2012-10-14T21:20:27.957 に答える
0

関数の最後で、の 2 番目の引数として関数ポインタとしてmain渡します。これのポイントは、現在スタック上にあるすべてのデータ要素 (残っている場合) です。ただし、アイテムがスタックに追加されたときに関数がメモリの割り当てに使用された場合にのみ、このメモリを解放できます。freedestroy_stackfreepushmalloc

指定された実装では、スタックはアイテムにメモリを割り当てる責任を負わないため、おそらくそのメモリを解放しようとするべきではありません。どちらの場合でも、不一致を探す場所はおそらく関数内にありますpush_char

スタックが期待するように作成されたメモリへのポインタではなくpush_char、単純な「{」文字(BTWこれは)をプッシュしようとしているようです。0x7Bmalloc

アップデート

push_char前の段落で私が言ったことをスクラッチしてください - 問題はdestroy_stack次の行にあります:

(*p_func_f)(*curr);    /* Incorrect */

currは、単一の文字に割り当てられた (によって割り当てられたpush_char)メモリへのポインタで*p_func_fあり、free()関数です。問題が見えますか?

currに渡すときに逆参照するとエラーになり*p_func_fます。代わりに、生のポインターを渡すだけです。

(*p_func_f)(curr);     /* Correct */

これを発見する鍵は、上で述べたのと同じです。「メモリ アドレス」0x7bは、実際には、スタックに格納されたデータである文字「{」です。これは、free関数が、そのデータへのポインタ。

于 2012-10-15T05:04:24.407 に答える