質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.99%

vi での日本語の取り扱いについて

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 246

masuter0413

score 39

以下のプログラムを実行したとき,name.txtがすべて英数字だとうまく実行されます.
しかし,名前の部分を日本語に帰るとcore dumputedとなり1行も表示されません.
実行環境はubuntsuの上でviエディタを使ってます.
どうすれば改善されるでしょうか.

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

/* ハッシュテーブルの要素数 */
#define SIZE 50

/*キー型,データ型 定義*/
typedef char KEY;
typedef char DATA;

/*連結リスト構造体*/
struct cell {
    KEY *key;
    DATA *data;
    struct cell *next;
};
typedef struct cell CELL;

/*ハッシュテーブル*/
CELL *table[SIZE];

/*ハッシュテーブル初期化*/
void init(CELL **table)
{
    int i = 0;
    for (i = 0; i < SIZE; i++) {
        table[i] = NULL;
    }
    return;
}

/*!
* 連結リストからセルを解放する*/
static void cell_free(CELL *cell)
{
    if (cell->key != NULL) free(cell->key);
    if (cell->data != NULL) free(cell->data);
    free(cell);
    return;
}

/* ハッシュテーブルの要素を解放する*/
void hash_free(CELL **table)
{
    int i = 0;
    CELL *temp = NULL;
    CELL *swap = NULL;

    for (i = 0; i < SIZE; i++) {
        temp = table[i];
        /* リストの解放 */
        while (temp != NULL) {
            swap = temp->next;
            cell_free(temp);
            temp = swap;
        }
    }
    init(table);
    return;
}


/* ハッシュ値を取得する*/
static int hash(KEY *key)
{
    int hashvalue = 0;
    while (*key) {
        hashvalue += *key++;
    }
    return(hashvalue % SIZE);
}

/*
* ハッシュ表を探索して、キーに対応するデータを取得する
* @table  ハッシュテーブル
* @key    ハッシュキー
* @return データへのポインタ。存在しない場合にはNULLを返す。
*/
DATA *search_cell(CELL **table, KEY*key)
{
    int hashval = hash(key);
    CELL *hp = table[hashval];

    for (; hp != NULL; hp = hp->next) {
        if (strcmp(key, hp->key) == 0) return(hp->data);
    }

    return(NULL);
}

/*!
* 文字列を領域確保してコピーする
* @dest  文字列のコピー先
* @src   文字列
* @return  0     success
* @return  -1    failure
*/
static int strcpy_alloc(char **dest, char *src)
{
    int length = 0;

    length = strlen(src);
    if (length <= 0) {
        fprintf(stderr, "ERROR: Invalid parameter(%d line)\n", __LINE__);
        return(-1);
    }

    *dest = (char *)malloc(length);
    if (*dest == NULL) {
        fprintf(stderr, "ERROR: %s(%d line)\n", strerror(errno), __LINE__);
        return(-1);
    }

    if (strncpy(*dest, src, length) == NULL) {
        fprintf(stderr, "ERROR: %s(%d line)\n", strerror(errno), __LINE__);
        return(-1);
    }

    return(0);
}

/*!
* ハッシュテーブルに登録する
* @table  ハッシュテーブル
* @key    ハッシュキー
* @data   登録するデータ
* @return      0      success
* @return      -1     failure
*/
int insert_cell(CELL **table, KEY *key, DATA *data)
{
    CELL *p = NULL;
    int hashval = 0;

    /* 同一キーがすでに登録されているか確認する */
    if (search_cell(table, key) != NULL) {
        fprintf(stderr, "key[%s] is already exist in hash table.\n", key);
        return(-1);
    }

    /* セル領域を確保する */
    p = (CELL *)malloc(sizeof(CELL));
    if (p == NULL) {
        fprintf(stderr, "ERROR: %s(%d line)\n", strerror(errno), __LINE__);
        return(-1);
    }

    /* キーとデータをセルに保存する */
    if (strcpy_alloc(&(p->key), key) != 0) return(-1);
    if (strcpy_alloc(&(p->data), data) != 0) return(-1);

    /* セルをハッシュテーブルに登録する */
    hashval = hash(key);
    p->next = table[hashval];
    table[hashval] = p;

    return(0);
}

/*!
* @brief      ハッシュテーブルから削除する
* @param[in]  table  ハッシュテーブル
* @param[in]  key    ハッシュキー
* @return     0      success
* @return     -1     failure
*/
int delete_cell(CELL **table, KEY *key)
{
    CELL *target = NULL;
    CELL *chain = NULL;
    int hashval = hash(key);

    /* ハッシュキーがハッシュテーブルに存在しているか確認する */
    target = table[hashval];
    if (target == NULL) {
        fprintf(stderr, "target[%s] is not exist in hash table.\n", key);
        return(-1);
    }
    chain = target->next;

    /* リストの先頭要素を削除する場合 */
    if (strcmp(key, target->key) == 0) {
        table[hashval] = chain;
        CELL(target);
        return(0);
    }

    /* 先頭以外の要素を削除する場合 */
    while (target != NULL) {
        if (strcmp(key, target->key) == 0) {
            chain->next = target->next;
            cell_free(target);
            return(0);
        }
        chain = target;
        target = target->next;
    }

    return(-1);
}

/*!
* ハッシュテーブルのデータ一覧を表示する
* @table      ハッシュテーブル
*/
static void hash_print_table(CELL **table)
{
    int i = 0;
    CELL *chain = NULL;

    for (i = 0; i < SIZE; i++) {
        if (table[i] != NULL) {
            printf("table[%d]:{", i);
            chain = table[i];
            /* リスト内部を調査して出力する */
            for (; chain != NULL; chain = chain->next) {
                printf("{%s:", (chain->key));
                printf("%s", (chain->data));
                printf(" %d}",hash(chain->key));
            }
            printf("}\n");
        }
    }
}

int main(void)
{

    FILE*fp;
    /* ハッシュの初期化 */
    init(table);
    char key[256];
    char data[256];
    char name[256];
    char del[256];
    int i, ren;

    fp = fopen("name.txt", "r");
    for (i = 0;; i++) {
        ren = fscanf(fp, "%s %s \n", key, data);
        if (ren == EOF)break;
        insert_cell(table, key, data);
    }

    hash_print_table(table);

    /* データを検索する */
    printf("Search stu-num\nname please:");
    scanf("%s", name);
    printf("number:%s\n", search_cell(table, name));

    /* データを削除する */
    printf("DELET-WORD:\nname please:");
    scanf("%s", del);
    delete_cell(table, del);
    hash_print_table(table);

    /* ハッシュテーブルを解放する */
    hash_free(table);

    return(0);
}
田中 J1877
梅島 D4563
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • cateye

    2019/06/09 09:54

    2行目"梅島 D4563"に全角空白文字が入っているようですが?

    キャンセル

  • 1T2R3M4

    2019/06/09 09:58

    viは関係ないんじゃないの。

    キャンセル

  • masuter0413

    2019/06/09 09:59

    半角に修正してもダメでした.

    キャンセル

回答 3

checkベストアンサー

0

ren = fscanf(fp, "%s %s \n", key, data);

renが2以外だと、入力データがおかしいと言うことなので、エラー表示して終了しましょう。
これで、全角空白を発見できます。

また、ハッシュ値関係の型を全部intからuintにしましょう。負数になるとテーブル範囲外になる。

あと、Cのプログラムの話であり、エディタは何を使おうが関係ないので、タイトルとタグからviを消しましょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/09 17:46

    田中 J1877
    梅島□D4563
    佐藤□K2718

    name.txt がこのようになっていた場合(□は全角スペース)、
    key="梅島□D4563"、data="佐藤□K2718" のように読み込んで
    ren が 2 になるので、全角スペースを検出できません。
    fgets + sscanf で読み込んだほうがよいと思います。

    キャンセル

  • 2019/06/09 20:47

    なるほど。\n があるから大丈夫と思っていましたが、やっぱり駄目ですね。

    キャンセル

0

usr ~/tmp % od -x aa.txt 
0000000 94e7 e4b0 adb8 4a20 3831 3737 e60a 85a2
0000020 b3e5 e3b6 8080 3444 3635 0a33
0000034
usr ~/tmp % cat aa.txt
田中 J1877
梅島 D4563
usr ~/tmp % 

全角空白(8080)が入っています。

 ren = fscanf(fp, "%s %s \n", key, data);

で、keyの値しか読めてないと思います。

 if (ren == EOF)break;

は、やめて項目数(ここでは2)にしましょう。
ちゃんと読めなくても通ってしまいます。

if (ren == EOF)break;

if (ren != 2)break;

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/09 10:09

    ダメでした

    キャンセル

  • 2019/06/09 10:14

    insert_cell(table, key, data);呼び出し前にprintf()とかやってみましょう。

    キャンセル

  • 2019/06/09 10:47 編集

    search_cell()が怪しいけど時間がないので後は自分で調べて下さい。
    usr ~/tmp % ./a.out
    init in
    init out
    田中:J1877
    田中:J1877
    search_cell in
    Segmentation fault (core dumped)
    usr ~/tmp %
    と、vimのタグは外して・・・
    あと、23個もワーニングが出ます。“プロトタイプがない”なんてのも有るけど、自分で説明が付けられないワーニングは消しましょう。

    キャンセル

0

strcpy_alloc ですが、文字列終端の '\0' もコピーしましょう。

    int length = strlen(src);
    *dest = (char *)malloc(length + 1);   // '\0' の分も確保
    strcpy(*dest, src);   // '\0' までコピー

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る