-1

こんにちは、誰かが問題の原因を見つけるのを手伝ってくれますか? 何らかの理由で find_hash 関数が問題を引き起こしています。それは失敗するはずですが、そうif(table -> buckets_array[i] != NULL){if(table -> buckets_array[i] != '\0'){はなく、次のチェックに進み、セグメンテーション違反が発生します。最初に table ->buckets_array[i] = NULL に設定したため、最初の 2 つの if ステートメントが通過する原因は何ですか?

編集: wildplasserfind_hash 関数のより良い解決策を考えてくれてありがとう。

if(table->buckets_array[table->hash_func(key)] == NULL){
    return NULL;
  }else{
    return table -> buckets_array[table->hash_func(key)] -> data;
  }

助けてくれてありがとう。

/*hash.h*/
#include<stdio.h>
#include<stdlib.h>

typedef struct data_{
  char *key;
  void *data;
  struct data_ *next;
}data_el;

typedef struct hash_table_ {
  void **order;
  int *number_next_calls;
  int *number_buckets;
  int *buckets_size;
  int *worst;
  int *total;
  float *average;
  int (*hash_func)(char *);
  int (*comp_func)(void*, void*);
  data_el **buckets_array;
} hash_table, *Phash_table;

Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *, void *));
void free_hash(Phash_table table);
void insert_hash(Phash_table table, char *key, void *data);
void *find_hash(Phash_table table, char *key);
void stat_hash(Phash_table table, int *total, int *largest, float *average);
void *start_hash_walk(Phash_table table);
void *next_hash_walk(Phash_table table);

static void lower_case_word(char *w);

/*hash.c*/
#include"hash.h"

Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *, void *)){
  int i;

  Phash_table table_p;
  hash_table hash_table;

  table_p = (Phash_table)malloc(sizeof(hash_table));

  /*Setting function pointers*/
  table_p->hash_func = hash_func;
  table_p->comp_func = cmp_func;

  /*Create buckets array*/
  table_p->buckets_array = (data_el **)malloc(sizeof(data_el *)*(size+1));
  table_p->buckets_size = (int *)malloc(sizeof(int)*(size+1));

  /*Setting order array*/
  table_p->order = NULL;

  /*Setting inital condictions*/
  table_p->worst = (int *)malloc(sizeof(int));
  table_p->total = (int *)malloc(sizeof(int));
  table_p->average = (float *)malloc(sizeof(float));
  table_p->number_buckets = (int *)malloc(sizeof(int));

  *(table_p->number_buckets) = size;

  for(i = 0; i < size; i++){
    table_p->buckets_array[i] = NULL;
  }
  return table_p;
}

void free_hash(Phash_table table){

  int i;
  i = 0;
  data_el *cur;
  data_el *prev;

  /*Free order array*/
  if(table->order != NULL){
    free(table->order);
  }

  /*Free Buckets array and buckets_size array*/
  if(table ->buckets_array != NULL){
    for(i=0; i < *(table->number_buckets); i++){
      if(table->buckets_array[i] != NULL){

    /*Travers the linked list and free it*/
    cur = table->buckets_array[i];
    prev = cur;

    while((cur = cur->next) != NULL){
      free(prev);
      prev = cur;
    }
    /*Free the last node*/
    free(cur);
    }
    }
  }
  free(table);
}

void insert_hash(Phash_table table, char *key, void *data){
  int index;
  data_el *p, *cur;

  index = table->hash_func(key);

  /*Head insertion*/
  if(table->buckets_array[index] == NULL){
    table->buckets_array[index] = (data_el *)malloc(sizeof(data_el));
    table->buckets_array[index]->data = data;
    table->buckets_array[index]->next =  NULL;
    table->buckets_array[index]->key = key;
  }else{
    cur = table->buckets_array[index];
    p = (data_el *)malloc(sizeof(data_el));
    p->key = key;
    p->data = data;
    p->next = cur;
    cur = p;
    table->buckets_array[index] = cur;
  }

  /*Update Total*/
  *table->total += 1;

  /*Update Bucket Size*/
  (table->buckets_size[index]) +=1;

  /*Updates Worst Case*/
  if((table->buckets_size[index]) > *(table->worst)){
    *(table->worst) = (table->buckets_size[index]);
  }else{
    *(table->worst) +=1;
  }

  /*Update Average*/
  int temp_total,temp_buckets;

  temp_total = *(table->total);
  temp_buckets = *(table->number_buckets);
  *(table->average)= (float)temp_total/(float)temp_buckets;
}

void *find_hash(Phash_table table, char *key){
  int i;
  i = 0;

  while(1){
    if(table->buckets_array[i] == '\0'){
      printf("End of Array");
      break;
    }
    if(table->buckets_array[i] != NULL){
      printf("%Checking");
      if(table->buckets_array[i] != '\0'){
    if(table->buckets_array[i]->key != NULL){
      if( strcmp(table->buckets_array[i]->key,key) == 0 ){
        printf("Found it\n");
        break;
      }
    }
      }
    }
    i++;
  }

  if(table->buckets_array[i] != NULL){
    printf("new asdasd %d", *((int *)table->buckets_array[i]->data));
    return table->buckets_array[i]->data;
  }else{
    return NULL;
  }
}

void stat_hash(Phash_table table, int *total, int *largest, float *average){
  total =  (table->total);
  largest = (table->worst);
  average =  (table->average);
}

void *start_hash_walk(Phash_table table){
  int i, max_buckets,step,next_calls;
  step = 0;
  data_el *cur;
  next_calls = 0;

  max_buckets = *(table ->number_buckets);
  table->order = (void**)malloc(sizeof(void *)*(*(table->total)));

  /*Set number_next_calls to 0*/
  table->number_next_calls = &next_calls;
  *(table->number_next_calls) = 0;

  /*Traverse the ADT and put all data into order array*/
  for(i = 0; i < max_buckets; i++){
    if(table->buckets_array[i] != NULL){
      cur = table->buckets_array[i];
      while(cur){
    table->order[step] = cur->data;
    step ++;
    cur = cur->next;
      }
    }
  }

  /*Bubble Short*/
  int j,k;

  for(j = 0; j < (step - 1);j++){
    for(k = 0;k < (step -(j+1));k ++){
      if((table->comp_func)(table->order[j],table->order[j+1]) < 5){
    void *temp;

    temp = table->order[j];
    table->order[j] = table->order[j+1];
    table->order[j+1] =  temp;
    printf("Swaping %s with %s\n",table->order[j],table->order[j+1]);
      }
    }
  }
  return table->order;
}

void *next_hash_walk(Phash_table table){

  /*
    Check the amount of times next_has_walk has been
    if higher than total, it will return null
  */

  if(*(table->number_next_calls) >= *(table->total)){
    return NULL;
  }else{
    *(table->number_next_calls) = *(table->number_next_calls) + 1;
    return table->order[*(table->number_next_calls)];
  }
}

/*project4.c*/

#include"hash.h"

#define WORD_SIZE 40
#define DICTIONARY_SIZE 1000
#define TRUE 1
#define FALSE 0

int hash_function(char *word){

  int sum,i;
  i = 0;
  sum = 0;
  while(word[i] != '\0'){
    sum = sum + word[i];
    i++;
  }
  return sum%1000;
}

int main(void){

  /*Creating buckets array*/
  Phash_table dictionary;
  void *test;

  dictionary = new_hash(DICTIONARY_SIZE,hash_function,comp);

  int i;
  i = 0;
  void *frequency[DICTIONARY_SIZE];
  int char_index = 0, dictionary_size = 0, num_words = 0;
  char c, word[WORD_SIZE];

  printf("Parsing input ...\n");

  while ((c = getchar()) != EOF) {
    if ((c == ' ') || (c == ',') || (c == '.') || (c == '!') || (c == '"') ||
    (c == ':') || (c == '\n')) {

      /* End of a word */
      if (char_index) {
    /* Word is not empty */
    word[char_index] = '\0';
    lower_case_word(word);
    if(!find_hash(dictionary,word) ){
      insert_hash(dictionary,word,frequency[hash_function(word)]);
    }
    frequency[hash_function(word)]++;
    char_index = 0;
    num_words++;
      }
    }else{
      word[char_index++] = c;
    }
  }

  printf("There were %d words; %d unique words.\n", num_words,dictionary_size);
}

void lower_case_word(char *w){
  int i = 0;

  while (w[i] != '\0') {
    w[i] = tolower(w[i]);
    i++;
  }
}
4

3 に答える 3

2

find_hash()関数は値を返しません。

一部の関数を省略しました:

Phash_table new_hash(int size, int (*hash)(char *), int (*comp)(void *, void *));
void lower_case_word(char *word);
int hash_function(char *);
int comp_function(void *, void *);

DICTIONARY_SIZE または WORD_SIZE が指定されていません。

cで宣言していませんmain()

int main(void)(または)を定義していませんint main(int argc, char **argv)。戻り値の型はintで、0 個または 2 個の引数を取ります。

を定義も初期化もしていませんchar_index。を定義していませんword。を定義または初期化しませんでしたnum_words

通常、コンパイル可能なコードを SO に提出する必要があります。欠落している関数と標準ヘッダーは 1 つのことです。それらの定義を省略した場合、それは正当です (ただし、軽度の迷惑です)。

比較関数が;だけでなくvoid const *(または) 引数を取る必要があるかどうかを検討することをお勧めします。またはなどで、より一般的に使用できるようになります。const void *void *qsort()bsearch()

ハッシュ関数が;のvoid *代わりに aを使用することでメリットがあるかどうかはわかりません。char *おそらく、修飾されていないポインターではなくchar const *orである必要があります。void const *

->スタイル上、または.演算子の前後にスペースを入れないでください。彼らは何よりもきつく縛ります。通常、 などの二項演算子の前後にはスペースを入れます/。一般に、コンマの後にスペースを入れます (ただし、さらに一貫性を持たせてください)。


ハッシュ.h

(通常 — これは通常のケースです) ヘッダーで静的関数を宣言しないでください。静的関数は 1 つのファイルでのみ必要です。ヘッダーに入れても意味がありません。ヘッダーは、ソース ファイル間で情報を共有するためのものです。他のファイルで使用されないものがある場合、それを宣言しても意味がありません。

再包含からヘッダーを保護します:

#ifndef HASH_H_INCLUDED
#define HASH_H_INCLUDED

...rest of header here...

#endif /* HASH_H_INCLUDED */

ヘッダーの使用に必要のないものはヘッダーに含めないでください。「hash.h」の素材はいずれも必要とし<stdlib.h>ない<stdio.h>ため、おそらくそこにあるべきではありません。

C 標準では、#includeとヘッダー名の間にスペースを使用します。彼らにとって十分なものは、あなたにとって十分なものであるべきです。

project4.c

コンパイラの警告に十分な注意を払っていないか、十分なコンパイラの警告が設定されていません。GCC を使用している場合は-Wall、少なくともコンパイルします。テスト コンパイルを行っていたときは、たとえば次のように使用しました。

gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -c project4.c

この一連のオプションの下でコードがきれいにコンパイルされることを期待しています。

#include <ctype.h>宣言する必要がありますtolower()

関数comp()はどこにも定義されていません。追加した:

static int comp(void *v1, void *v2)
{
    char const *s1 = v1; 
    char const *s2 = v2; 
    return strcmp(s1, s2);
}

また、外部定義が必要になるstaticのを避けるために、の前に置きます。hash_function()

コンパイルしたときに、次の警告が表示されました。

project4.c:51: warning: comparison is always false due to limited range of data type

それは問題を示しています。cとして宣言しましcharたが、次のように書きました。

while ((c = getchar()) != EOF)

これはノーノーです。関数getchar()は an を返しますint(はい、名前が良くありません)。返される値のセットには、すべての文字個別の値 EOF が含まれます。int信頼できる動作を得るには、 を使用する必要があります。2 つの問題のうちの 1 つが発生します。割り当てが (暗黙的に) 符号なしの型に割り当てられているため、EOF を取得できず、-1 が 0xFF にマップされ、0xFF が に昇格すると、int正であり、したがって -1 と等しくありません。または、有効な文字 (多くの場合、U+00FF、ÿ、分音符付きの小文字の Y、口語では y ウムラウト) を EOF と誤って解釈します。

!isalnum()条件の代わりに次のようなものを使用することを検討する必要があります。

 if ((c == ' ') || (c == ',') || (c == '.') || (c == '!') || (c == '"') ||
     (c == ':') || (c == '\n'))

hash.c

コード省略#include <string.h>

コンパイラは次のように述べています。

hash.c: In function ‘find_hash’:
hash.c:142: warning: too few arguments for format
hash.c: In function ‘start_hash_walk’:
hash.c:219: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘void *’
hash.c:219: warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘void *’

行番号は、ひとつまみの塩で処理する必要があります。私は Allman スタイルのレイアウトを使用しているため、コードをフォーマットしたときにコードに多くの行を追加しました。しかし、コンパイラがこの種のアドバイスを提供しない場合は、提供するコンパイラを探す必要があります。

行 142 には以下が含まれます。

printf("%Checking");

%不要です。ただし、何かが改行を出力するか、 を使用fflush(stdout);してデータを強制的に出力するまで、出力が表示されない場合があります。

printf("Checking\n");

原則として、特にデバッグ中は、出力されたメッセージを改行で終了します。

219 行目は次のとおりです。

 printf("Swaping %s with %s\n",table->order[j],table->order[j+1]);

おそらく次のように読む必要があります。

 printf("Swapping %s with %s\n", (char *)table->order[j], (char *)table->order[j+1]);

orderですのでvoid **。もちろん、それが である方が良いかもしれませんchar **


オペレーション

これらの (マイナーな) 問題が修正されると、コードがコンパイルされてリンクされます。テキストに対して実行すると、出力は次のようになります。

Parsing input ...
End of ArrayEnd of ArrayEnd of ArrayEnd of ArrayEnd of ArrayEnd of Array

改行を出力!また、処理したばかりの文字列と、それを追加したか、データ内で既に検出したかを出力することもおそらく価値があります。

の 1 つの問題main(): 使用する前に配列を初期化しませんfrequency。さらに、配列が存在する理由は完全には明らかではありません。頻度情報がハッシュテーブルに適切に保持されていないのはなぜですか? そして、周波数情報void *が、たとえば ではなく、なぜ配列なのintですか?

サンプル データの 1 つのロットについて、プログラムは次のように入力を要約しました。

There were 68 words; 0 unique words.

一意の単語の数は最初は気になりますdictionary_sizeが、出力の大部分が正しいように、0 に初期化して変更せずに出力することがわかりました。


構造ダンパーを自分で作成する必要があると思います。これは、構造体 (へのポインター) を指定すると、構造体のデータに関する適切な診断情報を出力する関数です。私は一般的な形式を使用します:

void dump_xyzstructure(FILE *fp, char const *tag, xyzstructure const *data);

次に、次のように記述できます。

dump_xyzstructure(stdout, "After initialization", &xyz);

dump_xyzstructure(logfp, "At this point", &xyz);

等。


ハッシュ テーブルはかなり複雑です。ただし、ハッシュ関数を呼び出すハッシュ テーブルの外部にコードがあり、それが良い考えかどうかはわかりません。ほとんどの場合、その必要はありません。頻度カウントをサポートするにはハッシュ テーブルが必要なので、ハッシュ テーブルは頻度を記録する必要があります。メインプログラムの補助コードでそれを行うべきではありません。

構造を合理化することで、生活を簡素化できます。構造内のすべてを動的に割り当てる必要はありません。特に 64 ビット マシンでは、これは膨大なスペースの無駄遣いです。(OK: 些細なスペースの無駄ですが、労力の無駄でもあります。)

 /*Setting inital condictions*/
 table_p->worst = (int *)malloc(sizeof(int));
 table_p->total = (int *)malloc(sizeof(int));
 table_p->average = (float *)malloc(sizeof(float));
 table_p->number_buckets = (int *)malloc(sizeof(int));

構造内の要素のみを使用して、これらのポインターを使用せずにデータ構造を作成すると、よりコンパクトになります。これにより、割り当て解除コードも簡素化されます (また、ポインターが割り当てられているかどうかを気にする必要がないため、印刷コードも簡素化されます)。

typedef struct hash_table
{
  void    **order;
  int       number_next_calls;
  int       number_buckets;
  int      *buckets_size;        // Number of entries in each bucket
  int       worst;
  int       total;
  float     average;
  int     (*hash_func)(char *); 
  int     (*comp_func)(void*, void*);
  data_el **buckets_array;
} hash_table, *Phash_table;

平均はオンデマンドで計算できます。実際、構造内の場所を保証するものではありません。これらのポインターをすべて失うと、コードが大幅に簡素化されます。

たとえば、次のフラグメント:

if (*(table->number_next_calls) >= *(table->total))
{
    return NULL;
}
else
{
    *(table->number_next_calls) = *(table->number_next_calls) + 1;
    return table->order[*(table->number_next_calls)];
}

になります:

if (table->number_next_calls >= table->total)
{
    return NULL;
}
else
{
    table->number_next_calls = table->number_next_calls + 1;
    return table->order[table->number_next_calls];
}

あるいは:

if (table->number_next_calls >= table->total)
    return NULL;
else
    return table->order[++table->number_next_calls];

サンプルテキスト

これは私が SO コメントでよく使うものです:

スタックオーバーフローへようこそ。ここでの「感謝」の好ましい方法は、良い質問と役立つ回答に賛成票を投じること (そうするのに十分な評判が得られたら) と、質問に対する最も役立つ回答を受け入れることであることに注意してください (これにより、あなたの評判が少し上がります)。[FAQ](http://stackoverflow.com/faq)特にご覧ください[How do I ask questions here?](http://stackoverflow.com/faq#howtoask)

サンプル出力

表示されるデータのほとんどは、dump_hash_table()関数からのものです。何が機能し、何が機能していないかを確認する必要がありました。そのほとんどは実際に機能していました — アルゴリズムの多くを修正する必要はありませんでした (最悪のケースの計算は誤りであり、修正されました)。入力が解析されている間、トレース コードを省略しました。

Hash Table: 0x10E700900 At end of input
 Order = 0x00000000
 Buckets = 0x7FD9A3800000
 Hash = 0x10E607A40
 Comp = 0x10E607AA0
 Next calls: 0
 Buckets: 1000
 Worst: 4
 Total: 74
 Average: 0.074000
   Bucket   3: 2
   Bucket  67: 1
   Bucket  97: 1
   Bucket  99: 2
   Bucket 105: 1
   Bucket 211: 2
   Bucket 213: 1
   Bucket 219: 2
   Bucket 220: 1
   Bucket 226: 1
   Bucket 227: 4
   Bucket 229: 1
   Bucket 307: 3
   Bucket 312: 3
   Bucket 317: 1
   Bucket 319: 4
   Bucket 321: 3
   Bucket 328: 1
   Bucket 334: 1
   Bucket 337: 1
   Bucket 349: 3
   Bucket 418: 3
   Bucket 420: 3
   Bucket 421: 1
   Bucket 425: 1
   Bucket 431: 1
   Bucket 433: 1
   Bucket 438: 1
   Bucket 448: 2
   Bucket 451: 1
   Bucket 463: 1
   Bucket 531: 1
   Bucket 537: 1
   Bucket 542: 1
   Bucket 551: 1
   Bucket 634: 2
   Bucket 646: 1
   Bucket 649: 2
   Bucket 651: 1
   Bucket 656: 1
   Bucket 663: 1
   Bucket 748: 1
   Bucket 752: 2
   Bucket 771: 1
   Bucket 880: 1
   Bucket 888: 1
   Bucket 942: 1
   Bucket 959: 1
 Unique words: 74
 Used Buckets: 48
There were 74 words; 0 unique words.

ハッシュ.h

を宣言できるようにするには、 をhash.h含める必要があることに注意してください。含む必要はありません。<stdio.h>dump_hash_table()<stdlib.h>

/*hash.h*/

#ifndef HASH_H_INCLUDED
#define HASH_H_INCLUDED

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

typedef struct data
{
  char *key;
  void *data;
  struct data *next;
} data_el;

typedef struct hash_table
{
  void    **order;
  int       number_next_calls;
  int       number_buckets;
  int      *buckets_size;       // Array of sizes of each bucket
  int       worst;
  int       total;
  float     average;
  int     (*hash_func)(char *);
  int     (*comp_func)(void*, void*);
  data_el **buckets_array;
} hash_table, *Phash_table;

Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *, void *));
void free_hash(Phash_table table);
void insert_hash(Phash_table table, char *key, void *data);
void *find_hash(Phash_table table, char *key);
void stat_hash(Phash_table table, int *total, int *largest, float *average);
void *start_hash_walk(Phash_table table);
void *next_hash_walk(Phash_table table);

void dump_hash_table(FILE *fp, char const *tag, hash_table const *table);

#endif /* HASH_H_INCLUDED */

hash.c

/*hash.c*/
#include "hash.h"
#include <string.h>
#include <inttypes.h>

Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *, void *))
{
    int i;

    Phash_table table_p;
    hash_table hash_table;

    table_p = (Phash_table)malloc(sizeof(hash_table));

    /*Setting function pointers*/
    table_p->hash_func = hash_func;
    table_p->comp_func = cmp_func;

    /*Create buckets array*/
    table_p->buckets_array = (data_el **)malloc(sizeof(data_el *)*(size+1));
    table_p->buckets_size = (int *)malloc(sizeof(int)*(size+1));

    /*Setting order array*/
    table_p->order = NULL;

    /*Setting inital conditions*/
    table_p->worst = 0;
    table_p->total = 0;
    table_p->average = 0.0;
    table_p->number_buckets = size;

    for (i = 0; i < size; i++)
    {
        table_p->buckets_array[i] = NULL;
    }
    return table_p;
}

void free_hash(Phash_table table)
{
    int i;
    i = 0;
    data_el *cur;
    data_el *prev;

    /*Free order array*/
    if (table->order != NULL)
    {
        free(table->order);
    }

    /*Free Buckets array and buckets_size array*/
    if (table->buckets_array != NULL)
    {
        for (i = 0; i < table->number_buckets; i++)
        {
            if (table->buckets_array[i] != NULL)
            {

                /*Travers the linked list and free it*/
                cur = table->buckets_array[i];
                prev = cur;

                while ((cur = cur->next) != NULL)
                {
                    free(prev);
                    prev = cur;
                }
                /*Free the last node*/
                free(cur);
            }
        }
    }
    free(table);
}

void insert_hash(Phash_table table, char *key, void *data)
{
    int index;
    data_el *p, *cur;

    printf("Inserting: <<%s>> (data: %d)\n", key, *(int *)data);

    index = table->hash_func(key);

    /*Head insertion*/
    if (table->buckets_array[index] == NULL)
    {
        table->buckets_array[index] = (data_el *)malloc(sizeof(data_el));
        table->buckets_array[index]->data = data;
        table->buckets_array[index]->next =  NULL;
        table->buckets_array[index]->key = key;
    }
    else
    {
        cur = table->buckets_array[index];
        p = (data_el *)malloc(sizeof(data_el));
        p->key = key;
        p->data = data;
        p->next = cur;
        cur = p;
        table->buckets_array[index] = cur;
    }

    /*Update Total*/
    table->total += 1;

    /*Update Bucket Size*/
    table->buckets_size[index] +=1;

    /*Updates Worst Case*/
    if (table->buckets_size[index] > table->worst)
    {
        table->worst = table->buckets_size[index];
    }

    /*Update Average*/
    table->average = (float)table->total / (float)table->number_buckets;
}

void *find_hash(Phash_table table, char *key)
{
    int i = 0;

    while (1)
    {
        if (table->buckets_array[i] == '\0')
        {
            printf("End of Array\n");
            break;
        }
        if (table->buckets_array[i] != NULL)
        {
            printf("Checking:\n");
            if (table->buckets_array[i] != '\0')
            {
                if (table->buckets_array[i]->key != NULL)
                {
                    if (strcmp(table->buckets_array[i]->key, key) == 0 )
                    {
                        printf("Found it\n");
                        break;
                    }
                }
            }
        }
        i++;
    }

    if (table->buckets_array[i] != NULL)
    {
        printf("New entry %d\n", *((int *)table->buckets_array[i]->data));
        return table->buckets_array[i]->data;
    }
    else
    {
        return NULL;
    }
}

void stat_hash(Phash_table table, int *total, int *largest, float *average)
{
    *total   = table->total;
    *largest = table->worst;
    *average = table->average;
}

void *start_hash_walk(Phash_table table)
{
    int i, max_buckets, step, next_calls;
    step = 0;
    data_el *cur;
    next_calls = 0;

    max_buckets = table ->number_buckets;
    table->order = (void**)malloc(sizeof(void *) * table->total);
    table->number_next_calls = 0;

    /*Traverse the ADT and put all data into order array*/
    for (i = 0; i < max_buckets; i++)
    {
        if (table->buckets_array[i] != NULL)
        {
            cur = table->buckets_array[i];
            while (cur)
            {
                table->order[step] = cur->data;
                step ++;
                cur = cur->next;
            }
        }
    }

    /*Bubble Short*/
    int j, k;

    for (j = 0; j < (step - 1);j++)
    {
        for (k = 0;k < (step -(j+1));k ++)
        {
            if ((table->comp_func)(table->order[j], table->order[j+1]) < 5)
            {
                void *temp;

                temp = table->order[j];
                table->order[j] = table->order[j+1];
                table->order[j+1] =  temp;
                printf("Swapping %s with %s\n", (char *)table->order[j], (char *)table->order[j+1]);
            }
        }
    }
    return table->order;
}

void *next_hash_walk(Phash_table table)
{
    /*
       Check the amount of times next_has_walk has been
       if higher than total, it will return null
     */

    if (table->number_next_calls >= table->total)
        return NULL;
    else
        return table->order[++table->number_next_calls];
}

void dump_hash_table(FILE *fp, char const *tag, hash_table const *table)
{
    fprintf(fp, "Hash Table: 0x%.8" PRIXPTR " %s\n", (uintptr_t)table, tag);
    if (table == 0)
        return;
    fprintf(fp, " Order = 0x%.8" PRIXPTR "\n", (uintptr_t)table->order);
    fprintf(fp, " Buckets = 0x%.8" PRIXPTR "\n", (uintptr_t)table->buckets_array);
    fprintf(fp, " Hash = 0x%.8" PRIXPTR "\n", (uintptr_t)table->hash_func);
    fprintf(fp, " Comp = 0x%.8" PRIXPTR "\n", (uintptr_t)table->comp_func);
    fprintf(fp, " Next calls: %d\n", table->number_next_calls);
    fprintf(fp, " Buckets: %d\n",    table->number_buckets);
    fprintf(fp, " Worst: %d\n",      table->worst);
    fprintf(fp, " Total: %d\n",      table->total);
    fprintf(fp, " Average: %f\n",    table->average);
    if (table->buckets_size != 0)
    {
        int unique_words = 0;
        int used_buckets = 0;
        for (int i = 0; i < table->number_buckets; i++)
        {
            unique_words += table->buckets_size[i];
            if (table->buckets_size[i] != 0)
            {
                used_buckets++;
                fprintf(fp, "   Bucket %3d: %d\n", i, table->buckets_size[i]);
            }
        }
        fprintf(fp, " Unique words: %d\n", unique_words);
        fprintf(fp, " Used Buckets: %d\n", used_buckets);
    }
}

project4.c

/*project4.c*/

#include "hash.h"
#include <string.h>
#include <ctype.h>

#define WORD_SIZE 40
#define DICTIONARY_SIZE 1000
#define TRUE 1
#define FALSE 0

static void lower_case_word(char *w);

static int hash_function(char *word)
{
    int sum, i;
    i = 0;
    sum = 0;
    while (word[i] != '\0')
    {
        sum = sum + word[i];
        i++;
    }
    return sum%1000;
}

static int comp(void *v1, void *v2)
{
    char const *s1 = v1;
    char const *s2 = v2;
    return strcmp(s1, s2);
}

int main(void)
{
    /*Creating buckets array*/
    Phash_table dictionary = new_hash(DICTIONARY_SIZE, hash_function, comp);
    int frequency[DICTIONARY_SIZE] = { 0 };
    int char_index = 0, dictionary_size = 0, num_words = 0;
    char word[WORD_SIZE];
    int c;

    printf("Parsing input ...\n");

    while ((c = getchar()) != EOF) 
    {
        if (isalnum(c))
            word[char_index++] = c;
        else
        {
            /* End of a word */
            if (char_index)
            {
                /* Word is not empty */
                word[char_index] = '\0';
                lower_case_word(word);
                printf("Got: %s\n", word);
                if (!find_hash(dictionary, word))
                {
                    insert_hash(dictionary, word, &frequency[hash_function(word)]);
                }
                frequency[hash_function(word)]++;
                char_index = 0;
                num_words++;
            }
        }
    }

    dump_hash_table(stdout, "At end of input", dictionary);

    printf("There were %d words; %d unique words.\n", num_words, dictionary_size);
}

static void lower_case_word(char *w)
{
    int i = 0;

    while (w[i] != '\0')
    {
        w[i] = tolower(w[i]);
        i++;
    }
}
于 2012-05-06T03:24:24.677 に答える
1

これは非常に複雑です。コードにコメントします。

void *find_hash(Phash_table table, char *key){
  int i;
  i = 0;

  while(1){

for() ループに最適な場所です。

    if(table->buckets_array[i] == '\0'){

->buckets_array[] は data_el へのポインタの配列へのポインタです '\0' は int (文字定数は C では int です)

      printf("End of Array");
      break;
    }
    if(table->buckets_array[i] != NULL){

あなたはすでにそれをテストし、ループから抜け出しました。条件は常に true です。

      printf("%Checking");
      if(table->buckets_array[i] != '\0'){

3回目のテストは必要ありません。

    if(table->buckets_array[i]->key != NULL){

ああ、ノードのペイロードに到達しました

      if( strcmp(table->buckets_array[i]->key,key) == 0 ){
        printf("Found it\n");
        break;
      }
    }
      }
    }

ここで中括弧のクラッジ、私は怠惰すぎて読んだり、数えたり(4)したり、それらをマッハしたりできません.

    i++;
  }


  if(table->buckets_array[i] != NULL){

あなたはこの状態をとても気に入っているようです。

    printf("new asdasd %d", *((int *)table->buckets_array[i]->data));
    return table->buckets_array[i]->data;

ああ!ペイロードが配信されます。呼び出し元に印刷を保持できます。

  }else{
    return NULL;
  }
}

縮小版:

void *find_hash(Phash_table table, char *key){
      int i;
      unsigned i;

      for (i=0; i < *table_p->number_buckets; i++){
         data_el *cur;

         for (cur = table->buckets_array[i]; cur != NULL; cur = cur->next ) {
            if( strcmp(cur->key,key) ) continue;

            return cur->data; /* found it ! */
            }
         }
    return NULL;
}

また、int サイズのオブジェクト (table_p->number_buckets など) を malloc することは実際的ではありません。定義を次のように変更する方がはるかに実用的です。

typedef struct hash_table_ {
  void **order;  /* This might be intended as a permutation array ? */
  unsigned number_next_calls;
  unsigned int number_buckets;

  unsigned int *buckets_size; /* I think this was intended as a histogram */
  unsigned int worst;
  unsigned int total;
  float average;
  int (*hash_func)(char *);
  int (*comp_func)(void*, void*);
  data_el **buckets_array;
} hash_table, *Phash_table;

typedef (Phash_table など) の背後にポインターを隠すことは、一般的に悪い習慣と見なされます。

昨日コメントしたように、署名された int を返すため、ハッシュ関数は危険です。マイナス指数になる可能性があります。("ABC"、"ACB"、"CAB" はすべて同じ値にハッシュされるため、衝突に関しても非常に悪いです。K&R、FNV、または Jenkins を使用することをお勧めします。)

于 2012-05-06T14:19:11.620 に答える
0

たぶん、実際にテストしているものになるようにコードを修正することができます。おそらく、コンパイルできるように必要なすべてのビットを含めます(私は好きです)。

find_hashには戻り値がありませんが、それを呼び出す前にそれを呼び出すと問題が発生することに注意してくださいinsert_hash

編集(完全なコードが表示されます)

comp呼び出しの関数new_hash-したがって、コンパイルできません。

次のmallocで何をしていますか?

table_p->worst = (int *)malloc(sizeof(int));
table_p->total = (int *)malloc(sizeof(int));
table_p->average = (float *)malloc(sizeof(float));
table_p->number_buckets = (int *)malloc(sizeof(int));

とにかくmallocからのリターンはキャストされるべきではありませんが、ここではintにスペースを割り当ててから、コンパイラににスペースを割り当てたことを伝えていますint *。これらのフィールドは実際にはポインタである必要がありますか?

find_hashでは、ループは次のようになります。

for (i=0; table->buckets_array[i] == ...; ++i) {
    etc
}

しかし、サーノルドが言ったように、なぜ(0)と(0)table->buckets_array[i]の両方に対してテストを行うのですか。これは非常に奇妙なことです。NULL'\0'

私はそれをデバッグするのにあまり時間をかけません。代わりに、コードのレビューを行い(または同僚にレビューを依頼して)、問題のいくつかを整理することをお勧めします。それらの中には:

  • table->buckets_array[i]に含まれるべきものを理解する
  • アンキャストmallocリターン
  • 統合データのためのスペースを制限しない
  • フォーマット
  • const変更されていないパラメータに追加する
  • 可能な場合はネストされたループを抽出します
  • 正しいループを使用する
于 2012-05-06T02:59:14.310 に答える