←検索窓の楽しみ方
  ショッピングモール  掲示板ランキング


【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※返信付き投稿の削除は禁止!
 ※マルチポスト(多重投稿)は慎んで!

 詳しくはこちら


 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.4400

mallocが問題?fgetsが問題?
投稿者---G(2005/08/11 04:16:46)


Q126の問題を改良して作りました。
OS:WindowsXPproSP2
コンパイラ:Borland C++ Compiler 5.5 Information(パッチ当てています)

テキストファイルを読み込みたいのですが、完全には読み取ることができません。
data1.txt

abc def ghi jkl mno pqr stu vwx yz
012 345 678 9
ABC DEF GHI JKL MNO PQR STU VWX YZ

というテキストファイルを読み込んだところ3行目を読み込めずにMicrosoft社に送信するエラーが表示されてしまいます。

    if((p = (HEAD *)malloc(sizeof(HEAD))) == NULL){
        printf("malloc error\n");
        free_list(head);
        exit(1);
    }

が原因のような気がするのですが、どこが悪いのかわかりません。
    for(; fgets(name, 256, fp) != NULL;){
        head = add_list(name, head);
    }

が原因なのかもしれないと思っています。

また、表示するときに先頭から表示したいので、rewind()もしくはfseek()を使いたいのですが、エラーがでてしまいます。
空白を含む文字列を読み込みたいので、fscanfは使えないことがわかりました。
freadも格納されている文字列がばらばらなので、使えないです。

どうして、エラーになるのかわかりません。
お願いします。

リストを使わなければならないのは必須です。
贅沢を言えば、双方向のリストが望ましいです。


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

#define EMAIL "data1.txt"

typedef struct list{
    int key;
    char name[20];
    struct list *next;
}HEAD;

struct list *add_list(char *name, HEAD *head);
void show_list(struct list *p);
void free_list(struct list *p);

int main(void)
{
    static FILE *fp;    /* ファイルポインタ */
    static HEAD *head;
    static char name[256];

    fp = fopen(EMAIL, "r");
    if(NULL == fp){
        printf("ファイルをオープンできませんでした。\n");
        return 0;
    }

    head = NULL;

    for(; fgets(name, 256, fp) != NULL;){
printf("%s", name); // バグ取りのための一時
        head = add_list(name, head);
    }
    show_list(head);
    free_list(head);

    fclose(fp);

    return 0;
}

struct list *add_list(char *name, HEAD *head)
{
    static HEAD *p;
    if((p = (HEAD *)malloc(sizeof(HEAD))) == NULL){
        printf("malloc error\n");
        free_list(head);
        exit(1);
    }
printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");  // バグ取りのための一時

    strcpy(p -> name, name);

    p -> next = head;
    head = p;

    return head;
}

void show_list(struct list *p)
{
    while(p != NULL){
        printf("%s", p -> name);
        p = p -> next;
    }
}

void free_list(struct list *p)
{
    static HEAD *p2;

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


国語力がないので、かみ砕くようにお願いします。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:mallocが問題?fgetsが問題? 4401 iijima 2005/08/11 07:14:14


No.4401

Re:mallocが問題?fgetsが問題?
投稿者---iijima(2005/08/11 07:14:14)


HEAD構造体のメンバnameは20文字分しかないのに、それを上回る文字数の文字列をコピーしようとしているのが問題です。


この投稿にコメントする

削除パスワード

No.4403

解決
投稿者---G(2005/08/11 10:27:34)


>HEAD構造体のメンバnameは20文字分しかないのに、それを上回る文字数の文字列をコピーしようとしているのが問題です。


ありがとうございました。
全然上の方はみていませんでした。

解決することができました。


この投稿にコメントする

削除パスワード

No.4404

Re:解決
投稿者---Blue(2005/08/11 10:55:52)


> 解決することができました。
結局どうやったのでしょうか?

  1. HEAD構造体のメンバnameのサイズを増やした。
  2. HEAD構造体のメンバnameに格納時にサイズに合わせたコピーをするようにした。
  3. HEAD構造体のメンバnameをchar*型にし、文字列長によって領域をmallocして、コピーした。
のどれでしょうか?



この投稿にコメントする

削除パスワード

No.4409

文字列検索
投稿者---G(2005/08/11 13:03:39)


  1. HEAD構造体のメンバnameのサイズを増やした。
  2. HEAD構造体のメンバnameに格納時にサイズに合わせたコピーをするようにした。
  3. HEAD構造体のメンバnameをchar*型にし、文字列長によって領域をmallocして、コピーした。


のどれでしょうか?</pre>

1番を選びました。
<pre>typedef struct list{
int key;
char name[256];
struct list *next;
}HEAD;
</pre>
name[256]にしました。

また新しい問題に直面しました。
文字列を検索しようと思いましたが、検索に引っかかりません。
<pre>int main(void)
{
static FILE *fp; /* ファイルポインタ */
static HEAD *head, *p;
static char name[256], *dat;
static char pattern[] = &quot;012 345 678 9&quot;;
static int tlen, plen;

fp = fopen(EMAIL, &quot;r&quot;);
if(NULL == fp){
printf(&quot;ファイルをオープンできませんでした。\n&quot;);
return 0;
}

head = NULL;

for(; fgets(name, 256, fp) != NULL;){
head = add_list(name, head);
}
for(; head != NULL;){
tlen = strlen(head -&gt; name);
plen = strlen(pattern);
dat = head -&gt; name;
dat = strstr(dat, pattern);
p = head -&gt; next;
head = p;
}
printf(&quot;-------%s-----&quot;, dat);
// show_list(head);
free_list(head);

fclose(fp);

return 0;
}
</pre>
(main関数以外は最初に投稿したプログラムと同じです)
本に書いてあったとおりに、strstrを使う場合は、strlenを
使わなければ、検索することができないと書いていました。

なぜ、検索に引っかからないのでしょうか。

よろしくお願いします。

解決方法を聞いてきたということは、1〜3のどれかを選ぶのはよくないという意味でしょうか。


この投稿にコメントする

削除パスワード

No.4411

Re:文字列検索
投稿者---Blue(2005/08/11 13:26:07)


とりあえずHTML変換がミスっているので直しておきました。

typedef struct list{ int key; char name[256]; struct list *next; }HEAD; int main(void) { static FILE *fp; /* ファイルポインタ */ static HEAD *head, *p; static char name[256], *dat; static char pattern[] = "012 345 678 9"; static int tlen, plen; fp = fopen(EMAIL, "r"); if(NULL == fp){ printf("ファイルをオープンできませんでした。\n"); return 0; } head = NULL; for(; fgets(name, 256, fp) != NULL;){ head = add_list(name, head); } for(; head != NULL;){ tlen = strlen(head -> name); plen = strlen(pattern); dat = head -> name; dat = strstr(dat, pattern); p = head -> next; head = p; } printf("-------%s-----", dat); // show_list(head); free_list(head); fclose(fp); return 0; }



この投稿にコメントする

削除パスワード

No.4412

Re:文字列検索
投稿者---おでん(2005/08/11 13:52:24)


>なぜ、検索に引っかからないのでしょうか。
>
fgets()が読み込む文字列は?
・・・仕様を確認しましょう。


この投稿にコメントする

削除パスワード

No.4418

Re:文字列検索
投稿者---G(2005/08/11 16:57:42)


>>なぜ、検索に引っかからないのでしょうか。
>>
>fgets()が読み込む文字列は?
>・・・仕様を確認しましょう。

「fgetsは次の最大 n-1 文字を配列 s に読み込む。改行がくるとストップである。この改行は配列に含められ、その後に '\0' が付く。fgets は s を返すが、ファイルの終わりあるいはエラー発生時には NULL が返される。」
と聖書(K&R)には書いていました。

abc def ghi jkl mno pqr stu vwx yz
012 345 678 9
ABC DEF GHI JKL MNO PQR STU VWX YZ

を読み込んだ後に、

012 345 678 9

を検索しようとしましたが、だめな理由は・・・。
改行の文字が含まれていないからということでしょうか。
しかし、
static char pattern[] = "012 345 678 9\r\n";
static char pattern[] = "012 345 678 9\r\n";
static char pattern[] = "012 345 678 9\n";
static char pattern[] = "012 345 678 9\r";
static char pattern[] = "012 345 678 9\0";
すべてのパターンをしてもだめでした。
が、strcmp() の関数を使えば、
static char pattern[] = "012 345 678 9\n";
の書式設定でうまくできました。


この投稿にコメントする

削除パスワード

No.4413

Re:文字列検索
投稿者---まきじ(2005/08/11 14:10:23)


>本に書いてあったとおりに、strstrを使う場合は、strlenを
>使わなければ、検索することができないと書いていました。
>なぜ、検索に引っかからないのでしょうか。

name を検索するのでした、リストですから next を辿り
順番に strcmp() で比較していけば良い。

strstr() も strlen() も不要。

>解決方法を聞いてきたということは、1〜3のどれかを選ぶのはよくないという意味でしょうか。

解決時には、どの様に解決したのか報告してください。


この投稿にコメントする

削除パスワード

No.4419

文字列検索 解決
投稿者---G(2005/08/11 17:01:34)


>name を検索するのでした、リストですから next を辿り
>順番に strcmp() で比較していけば良い。

    dat = 10000000;

    for(; fgets(name, 256, fp) != NULL;){
        head = add_list(name, head);
    }
    for(; head != NULL && dat != 0;){
        dat = strcmp(head -> name, pattern);
        if(dat == 0){
            break;
        }
        p = head -> next;
        head = p;
    }
    if(dat == 0){
        printf("-------%s-----", head -> name);
    }


ごちゃごちゃしていますが、以上のソースコードで解決することができました。
ありがとうございました。

>解決時には、どの様に解決したのか報告してください。

教えられたのですから、当たり前のことでした。
礼に欠けていました。失礼しました。


まきじさん、おでんさん、Blueさん(変換ありがとうございます)、iijimaさんありがとうございました。


この投稿にコメントする

削除パスワード

No.4423

キャスト
投稿者---G(2005/08/12 03:17:01)


すみません、何度も何度も、お粗末な私の頭をののしってください。

char buf[256];
if(dat == 0){
    printf("-------%s-----", head -> name);
    p3 = head -> next;
    head = p3;
    strcpy(buf, head -> name);
}


途中の処理で、strcpy(buf, head -&gt; name);をしようと思いましたが、
「'char [256]' と 'struct _iobuf *' の間で型に互換性がありません。」
というエラーがでてしまいます。
調べてみるとキャストをすれば解決すると書いていたので、キャストをしたのですが、それでもエラーがでてしまいます。
strcpy(buf, head -> (char)name);
strcpy(buf, head -> (char *)name);
strcpy(buf, (char)head -> name);
strcpy(buf, (char *)head -> name);
strcpy((char *)buf, head -> name);
以上すべてだめでした。
buf にあわせるために char を使うものとばかり思っていましたが、そうではない感じです。
どのようにしたら、エラーがでないようになるのでしょうか。
何度も質問して申し訳ありません。
よろしくお願いします。


この投稿にコメントする

削除パスワード

No.4424

Re:キャスト
投稿者---YuO(2005/08/12 03:27:35)


>途中の処理で、strcpy(buf, head -&gt; name);をしようと思いましたが、
>「'char [256]' と 'struct _iobuf *' の間で型に互換性がありません。」
>というエラーがでてしまいます。

エラーがでたのが,strcpyのある行なのですか?
# struct _iobuf *はおそらくFILE *のこと。
エラーが起きているのは,別の行だと思うのですが……。


>調べてみるとキャストをすれば解決すると書いていたので、キャストをしたのですが、それでもエラーがでてしまいます。

キャストをしても,おそらく解決していません。
臭い物に蓋をしただけです。



この投稿にコメントする

削除パスワード

No.4425

Re:キャスト
投稿者---とおり(2005/08/12 03:43:32)


>エラーがでたのが,strcpyのある行なのですか?
># struct _iobuf *はおそらくFILE *のこと。
>エラーが起きているのは,別の行だと思うのですが……。

大方、変数名でも間違えて(pなんたらをfpとでも)、chat buf[256]とFILE*の間で
代入や比較演算でもしちゃってるってあたりでしょうかね…


この投稿にコメントする

削除パスワード

No.4439

Re:キャスト
投稿者---G(2005/08/12 16:28:23)


すみません、別の行でした。

strcpy()をキャストしたらいいという記事を見かけたので、固定観念でこの行が問題なのだと決めつけてしまいました。
ですので、ソースコードも省いて載せてしまいました。
その省いたソースコードにエラーが指していました。

fread(buf, 1, 11, buf);
fgets(dat1, 32, buf);

の2行です。

if文の中で
p3 = head -> next;
head = p3;
とした行がありますが、これは次の行に移動してもらいたいための処理をしていましたが、これも勘違いでした。
1つ前の行に戻らなければならない処理をしなければならなかったのです。
前の行に戻って、fread()を実行したかったのです。

前の行に戻るためには、双方向のリストでなければ戻れないのでしょうか。
head の頭に戻りたいために、for文で何回 繰り返したか数えて、headから繰り返した数を引いてheadに代入しようとしましたが、失敗しました。

head = head - i;

のような感じです。



この投稿にコメントする

削除パスワード

No.4440

Re:キャスト
投稿者---とおり(2005/08/12 16:41:43)


> fread(buf, 1, 11, buf);
> fgets(dat1, 32, buf);

ちゃんと関数の仕様を確認して使いましょう。
# 引数を適当に設定しているとしか思えません。

>前の行に戻るためには、双方向のリストでなければ戻れないのでしょうか。

そんなことはありません。(双方向リストの方が楽ですが)
もう一度、headからリストを手繰りながら、"構造体のnextメンバ変数が目標のnodeを指す"
ようなnodeを見つければ、それが一つ前のnodeです。


この投稿にコメントする

削除パスワード

No.4441

Re:キャスト
投稿者---Blue(2005/08/12 16:42:35)


> fread(buf, 1, 11, buf);
> fgets(dat1, 32, buf);
>
> の2行です。
解決方法は既にとおりさんが示されていますよ。
わからないようならば、再度 fread, fgets の関数を調べてください。

> 前の行に戻るためには、双方向のリストでなければ戻れないのでしょうか。
双方向にするか、先頭から一行一行、現在行の前の行を探すかでしょうね。



この投稿にコメントする

削除パスワード

No.4442

Re:キャスト
投稿者---まきじ(2005/08/12 16:49:40)


>fread(buf, 1, 11, buf);
>fgets(dat1, 32, buf);

buf は、FILE* 型ですか?
FILE* 型だとしたら、fread() の第一引数が間違ってます。
char[] 型とかなら、第四引数が間違ってます。

>前の行に戻るためには、双方向のリストでなければ戻れないのでしょうか。

双方向リストが適切かと。

>前の行に戻って、fread()を実行したかったのです。

1 行ごとにノードに格納してるのでは?
fread() は不要かと

>head の頭に戻りたいために、for文で何回 繰り返したか数えて、headから繰り返した数を引いてheadに代入しようとしましたが、失敗しました。
>head = head - i;

head は struct list 型 への ポインタですので、
引いても意味がありません。


この投稿にコメントする

削除パスワード

No.4448

Re:キャスト
投稿者---G(2005/08/12 17:53:29)


>buf は、FILE* 型ですか?
>FILE* 型だとしたら、fread() の第一引数が間違ってます。
>char[] 型とかなら、第四引数が間違ってます。

size_t fread(void *ptr, size_t size, size_t nobj, FILE *stream)
となっているので、FILEとしないといけないってことですね。

違う本に
「指定したサイズのデータを一度にファイルから読み込んで、配列に代入することができます」

とあるので、第4引数は何でもいいのかと思いましたが、ファイルというのはファイルポインタでなければならないのですね。
さらに違う本では、丁寧に第四引数にファイルポインタを指定すると書いていました。
見忘れというか、ミスというか、すみません。

>双方向リストが適切かと。

わかりました。

>1 行ごとにノードに格納してるのでは?
>fread() は不要かと

違う関数を見つけました。(strtok()関数ですが、試したわけではないのでわかりません。双方向リストを実現してから試したいと思います。)

>head は struct list 型 への ポインタですので、
>引いても意味がありません。

単純にできていないということですね。
双方向リストを勉強します。


この投稿にコメントする

削除パスワード

No.4451

解決
投稿者---G(2005/08/13 01:17:42)


>違う関数を見つけました。(strtok()関数ですが、試したわけではないのでわかりません。双方向リストを実現してから試したいと思います。)

できました。
テキストファイルを読み込み

0123 456


のファイルを読み込むとき

temp1 = strtok(buf, " ");
temp2 = strtok(NULL, " ");

とすると、きちんと区切られて読み込むことができました。
改行まで読み込むとは思いませんでしたが、for 文で配列をブン回して文字の最後に '\0' を入れました。
それで、改行を回避することができました。

一段落落ち着きましたので、違うプログラムに取りかかります。
何かありましたら、また質問をするかもしれません、そのときはご教授お願いいたします。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity