文字列を記録するリストの問題

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
imaichi

文字列を記録するリストの問題

#1

投稿記事 by imaichi » 8年前

次の問題がわかりません。
(1)p->word=str_clone(word);
(2)if(head==tail){
head=tail=p;
}else{
tail->next=p;
tail=p;
}
(3)for(p=head;p!=NULL;p=p->next){
printf("%s\n",p-> word);
}

としたところcapacityしか表示されませんでした。

どなたか教えていただけると幸いです。


問題は読み込んだデータをアルファベット順にリストを使用して並び替えるというものです。


/* (1) */ から /* (3) */ の部分に適当なコードを書き込んで,プログラムを完成させよ.

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define L 256

/* リストを構成する自己参照構造体 */
typedef struct node {
char *word; /* 文字列を指すポインタ */
struct node *next;
} Node;

/* リストに記録されたデータを整列する関数 */
void mysort(Node *a)
{
char *x;
Node *p, *done = NULL;

while(done != a->next) {
for(p = a; p->next != done; p = p->next){
if(strcmp(p->word, p->next->word)>0) {
x = p->word;
p->word = p->next->word;
p->next->word = x;
}
}
done = p;
}
}

char *str_clone(char *s)
{
char *clone, *p;
int len;

len = strlen(s);
clone = p = (char*)malloc(sizeof(char)*(len+1));
strcpy(clone, s);

return clone;
}

int main(int argc, char *argv[])
{
FILE *ifp; /* 入力ファイル用ファイルポインタ */
char word[L]; /* ファイル読み込み用 char 配列 */
Node *head = NULL, *tail = NULL; /* リストの先頭と末尾を指すポインタ */
Node *p;
int i;

/* コマンドライン引数の数のチェック */
if(argc != 2) {
printf("使い方: %s 入力ファイル名\n", argv[0]);
exit(1);
}

/* 入力ファイルを開く */
if((ifp=fopen(argv[1],"r"))==NULL) {
printf("オープン失敗: \"%s\".\n", argv[1]);
exit(1);
}

/* 単語の読み込み */
for(i = 0; fscanf(ifp, "%s\n", word) > 0; i++) {
p = malloc(sizeof(Node)); /* Node の動的割り当て */

/* p->word が(str_cloneで作った) word の複製を指すようにする */
/* (1) */

/* リストの末尾に p の指す Node を追加 */
/* (2) */
}
tail->next = NULL; /* 末尾の Node の next を NULL に */

/* 入力ファイルを閉じる */
fclose(ifp);

/* 読み込んだ単語のソート */
mysort(head);

/* 単語を表示 */
/* (3) */

while(head != NULL) {
p = head->next;
free(head->word);
free(head);
head = p;
}

return 0;
}
読み込むデータ内容
definition
agriculture
background
account
creation
career
characteristic
anxiety
circumstance
ancestor
climate
alternative
crisis
decade
address
capacity

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 文字列を記録するリストの問題

#2

投稿記事 by みけCAT » 8年前

(2)のif文でhead==tailという条件にしてしまうと、
最初はhead = NULL, tail = NULLなので真、
2回目以降もhead=tail=pなので真になってしまい、
常に最後に入力された文字列しか保存されません。
たとえば、この条件をhead==NULLとするといいでしょう。
オフトピック
なんでこのコード…インデントが全く無いのん…?

str_clone()関数で謎の変数pがある、malloc()の戻り値をチェックしていないなど、他にもツッコミどころはありそうだが…。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Math

Re: 文字列を記録するリストの問題

#3

投稿記事 by Math » 8年前

http://dixq.net/forum/viewtopic.php?f=3&t=18689を参考に考えると
data.txt

コード:

definition
agriculture
background
account
creation
career
characteristic
anxiety
circumstance
ancestor
climate
alternative
crisis
decade
address
capacity
としてコマンドライン・コンパイルが終わると自動実行させるバッチを作って

コード:

rem コンパイル後リンク
cl /TC c1.txt
rem 実行結果
c1.exe data.txt
c1.txt [cプログラム]  (/TC オプションでC言語コードとみなされる)

コード:

/* [問題]
問題は読み込んだデータをアルファベット順にリストを使用して並び替えるというものです。
(1) から (3)  の部分に適当なコードを書き込んで,プログラムを完成させよ.*/
///----------------------------------------------------------------------------
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define L 256
 
/* リストを構成する自己参照構造体 */
typedef struct node { //-構造体タグ名--node--
    char *word; /* 文字列を指すポインタ */
    struct node *next; //-構造体のポインター:チェーン-
} Node; //-typedef struct node Node; と同義-
 
/* リストに記録されたデータを整列する関数 */
void mysort(Node *a)
{
    char *x;
    Node *p, *done = NULL;
 
    while(done != a->next) {
      for(p = a; p->next != done; p = p->next){
      if(strcmp(p->word, p->next->word)>0) {
        x = p->word;
        p->word = p->next->word;
        p->next->word = x;
        }
      }
      done = p;
    }
}
 
char *str_clone(char *s)
{
  char *clone, *p;
  int len;
 
  len = strlen(s);
  clone = p = (char*)malloc(sizeof(char)*(len+1));
  strcpy(clone, s);
 
  return clone;
}
///----------------------------------------------------------------------------
    // リスト構造の先頭に新しいデータを追加する関数
    Node *add_list(char *word, Node *head)//新データ:新次のデータへのポインタ
    {
        Node *new_head;           //次のデータへのポインタ
        new_head = (Node *)malloc(sizeof(Node));//メモリー確保
        //ポインタのつなぎ換え
        new_head->word = word; //リストにデータを登録
        new_head->next = head;// 今までの先頭ポインタを次ポインタに
     
        return new_head;    //新しい先頭ポインタ
    }
///----------------------------------------------------------------------------
    // リスト構造を表示する関数
    void show_list(Node *head)
    {
        if (head == NULL) // NULLポインタだったら改行のみ表示
        {
            printf("\n\n");
        }
        else {
            printf("%s\n", head->word);//データ表示
            show_list(head->next);  //再帰呼び出し
        }
    }
///[まず①コマンドラインの入力処理。(この問題はVisualStudioでは手法が確立している)]
///[今回はコマンドライン・コンパイル後引き続き自動実行するバッチを使用する]
int main(int argc, char *argv[])
{
  FILE *ifp; /* 入力ファイル用ファイルポインタ */
  char word[L]; /* ファイル読み込み用 char 配列 */
  Node *head = NULL, *tail = NULL; /* リストの先頭と末尾を指すポインタ */
  Node *p; //-構造体宣言-
  int i;
 
/* コマンドライン引数の数のチェック */
if(argc != 2) {
    printf("使い方: %s 入力ファイル名\n", argv[0]);
    exit(1);
}
 
printf("..000..入力ファイル名=%s\n", argv[1]);/* 入力ファイルを開く */
if((ifp=fopen(argv[1],"r"))==NULL) {
    printf("オープン失敗: \"%s\".\n", argv[1]);
    exit(1);
}
 
/* 単語の読み込み */ //void*' から非 'void' 型への変換には明示的なキャストが必要です。
for(i = 0; fscanf(ifp, "%s\n", word) > 0; i++) {printf("..111..入力Data=%s\n",word);
    head = add_list(word,head);//p = (Node *)malloc(sizeof(Node)); /* Node の動的割り当て */
}
show_list(head); // リスト構造を表示する関数
exit(0);//----------------------------------------ここまで:終わり------------
//-----------------------------------------------------------------------------
/* p->word が(str_cloneで作った) word の複製を指すようにする */
/* (1) */
//(1)
p->word=str_clone(word);
/* リストの末尾に p の指す Node を追加 */
/* (2) */
//(2)
  if(head==tail){
    head=tail=p;
  }else{
    tail->next=p;
    tail=p;
}
//-----------------------------------------------------------------------------
tail->next = NULL; /* 末尾の Node の next を NULL に */
 
/* 入力ファイルを閉じる */
fclose(ifp);
 
/* 読み込んだ単語のソート */
mysort(head);
//----------------------------------------------------------------------------- 
/* 単語を表示 */
/* (3) */
//(3)
//  for(p=head;p!=NULL;p=p->next){
//    printf("%s\n",p-> word);
//  }
while(head != NULL) {
    p = head->next;
    free(head->word);
    free(head);
    head = p;
}
return 0;
}
[実行結果]

コード:

D:\h\z10\01\13\c\1>c

D:\h\z10\01\13\c\1>rem コンパイル後リンク

D:\h\z10\01\13\c\1>cl /TC c1.txt
Microsoft(R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

c1.txt
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:c1.exe
c1.obj

D:\h\z10\01\13\c\1>rem 実行結果

D:\h\z10\01\13\c\1>c1.exe data.txt
..000..入力ファイル名=data.txt
..111..入力Data=definition
..111..入力Data=agriculture
..111..入力Data=background
..111..入力Data=account
..111..入力Data=creation
..111..入力Data=career
..111..入力Data=characteristic
..111..入力Data=anxiety
..111..入力Data=circumstance
..111..入力Data=ancestor
..111..入力Data=climate
..111..入力Data=alternative
..111..入力Data=crisis
..111..入力Data=decade
..111..入力Data=address
..111..入力Data=capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity
capacity



D:\h\z10\01\13\c\1>
あ、どこかおかしい。

Math

Re: 文字列を記録するリストの問題

#4

投稿記事 by Math » 8年前

この問題はⅲつ主要な部分に分けて考えます。
まず①コマンドラインの入力処理。これは既に解決しました。
ファイルの読み込みも出来ています。(①はOK)
②はリスト構造の作成です。
③ソートです。この時新しくリスト構造をつくります。
---------------------------
/* p->word が(str_cloneで作った) word の複製を指すようにする */
/* (1) */
//(1)---
p->word=str_clone(word);
/* リストの末尾に p の指す Node を追加 */
/* (2) */
//(2)---


/* 単語を表示 */
/* (3) */
------------------この(1)(2)(3)以外は正しく与えられたもの
と考えて良いのでしょうか。またこの位置に記述しサブルーチン
化しない方がいいのですか(与えられた課題を正確に記述して
下さい。もっと簡単な方法も考えれます。------------------

閉鎖

“C言語何でも質問掲示板” へ戻る