ページ 11

分割した文字列を自己参照構造体に入れて要素数をカウント

Posted: 2016年10月23日(日) 23:48
by 素人マン

コード:

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

#define CLASS1 "2.1"
#define STU_NUMBER ((sizeof deta1)/(sizeof(struct student)))


typedef struct student{
	char name1[100];
	char name2[100];
	char club[100];
	char height1[100];
	char height2[100];
	char weight1[100];
	char weight2[100];
	char seibetu[100];
	char number[100];
	struct student *next;
}student;

sturuct student *add_student(char *name1, name2, club, height1, height2, weight1, weight2, seibetu, number struct student *head);
void show_student(struct student *p);
void free_student(struct student *p);

int main(void)
{
	static char deta1[100] = {"Tanaka Taro: 2.1 baseball 170.3 cm 65 Kg man 21"};
	static char c1[] = {" :"CLASS1""};, 
	char *cut;
	int i;
	cat = strtok(deta1, c1);
	head = NULL;
	while(cut != NULL)
		{
			head = *add_student(char *name1, name2, club, height1, height2, weight1, weight2, seibetu, number struct student *head);
			printf("%s\n", cut);
			cut = strtok(NULL, c1);
		}
	show_student(head);
	show_student(head);
	printf("word is %d\n", 	STU_NUMBER);	

	return 0;
}


struct student *add_student(char *name1, name2, club, height1, height2, weight1, weight2, seibetu, number struct student *head);
{
	struct student *p;
	
	if ((p = (struct student *) malloc(sizeof(struct list))) == NULL) {
		printf("malloc error\n");
		exit(EXIT_FAILURE);
	}

	p->next = head;		
	head = p;
	
	return head;
}

void show_student(struct student *p)
{
	while (p != NULL) {	
		printf("%s\n", p->name1);
		p = p->next;
	}
}

void free_student(struct student *p)
{
	struct student *p2;

	while (p != NULL) {  
		p2 = p->next;
		free(p);
		p = p2;
	}
}
自己参照構造体を文字列を分割して配列へ入れて、要素数をカウントするプログラムを作成したいのですが、どのようにすればいいのか分かりません。
コードは上記のように入力したのですかエラーが出てしまいます。
私は構造体、配列、ポインタは最近勉強始めたばかりです。
コンパイル実行は今現在、できない環境にあるため、返答は一日後あたりになると思います。

Re: 分割した文字列を自己参照構造体に入れて要素数をカウント

Posted: 2016年10月24日(月) 00:35
by みけCAT
素人マン さんが書きました: 自己参照構造体を文字列を分割して配列へ入れて、要素数をカウントするプログラムを作成したいのですが、
やりたいことがよくわかりません。
分割対象の「文字列」は「自己参照構造体」から取得するのですか?それとも提示されたプログラムのように外部からですか?
「配列へ入れて」の配列はどこに作りますか?提示されたプログラムのように「自己参照構造体」の中ですか?それとも外部ですか?
また、何の配列ですか?「文字列」ですか?「自己参照構造体」ですか?
提示されたプログラムでは構造体のもととなりそうな文字列は構造体1個分で固定のようですが、「要素数をカウント」の対象は何ですか?
素人マン さんが書きました:どのようにすればいいのか分かりません。
コードは上記のように入力したのですかエラーが出てしまいます。
とりあえず、コンパイルエラーを修正してコンパイルが通るコードにすることから始めるといいと思います。
素人マン さんが書きました:私は構造体、配列、ポインタは最近勉強始めたばかりです。
変数や関数の勉強はどの程度しましたか?

今あるコンパイルエラーの原因は
  • 22行目:
    • 最初にtypoがある:stuructではなくstructが正しい
    • 引数name2~numberに型が書かれていない
    • numberとstructの間にコンマが抜けている
  • 29行目:最後に余計なコンマがある
  • 32行目:宣言されていない変数catが使用されている (typoでcutが正しい?)
  • 33行目:宣言されていない変数headが使用されている
  • 36行目:
    • 引数name1とheadに余計な型名が付いている
    • 宣言されていない変数name1, name2, club, height1, height2, weight1, weight2, seibetu, number, headが使用されている
    • 関数の戻り値を無駄にデリファレンスしている (NULL(スカラ型の値)と構造体を両方格納できる型はC言語には無さそうだし、headが構造体型だとするとshow_studentに渡しているのに矛盾する)
  • 48行目:
    • 引数name2~numberに型が書かれていない
    • numberとstructの間にコンマが抜けている
    • 最後に余計なセミコロンがある
  • 52行目:サイズを得ようとしているstruct listが定義されていない (struct studentが正しい?)
ですね。

また、
  • 42行目でint型のデータを渡すべき%dにsize_t型のデータが渡されている
  • 66行目ででmallocにより確保され、初期化されていないデータp->name1が使用されている
ため、実行されれば未定義動作になります。

Re: 分割した文字列を自己参照構造体に入れて要素数をカウント

Posted: 2016年10月24日(月) 00:36
by box
素人マン さんが書きました: コードは上記のように入力したのですかエラーが出てしまいます。
何だかツッコミどころ満載のコードですね。
さておき、「何をしたときに」「何という」エラーが出るかを具体的に書いてください。話はそこから始まります。
単に「エラーが出る」と書かれても、何も説明したことになりません。

Re: 分割した文字列を自己参照構造体に入れて要素数をカウント

Posted: 2016年10月24日(月) 23:44
by 素人マン
みけCAT様
box様

お忙しい中、返信とアドバイスありがとうございます。
返信が遅れた上に説明足らずに質問をしてしまい、すみません。
今後は、このようなことがないように気をつけます。

図々しいようで申し訳ありませんが、もう一度質問に答えていただけると助かります。
修正したソースコートは以下になります。

コード:

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

#define CLASS1 "2.1"
#define STU_NUMBER ((sizeof deta2)/(sizeof(struct student)))


typedef struct student{
	char name1[100];
	char name2[100];
	char club[100];
	char height1[100];
	char height2[100];
	char weight1[100];
	char weight2[100];
	char seibetu[100];
	char number[100];
	struct student *next;
}student;

struct student *add_student(char *name1, char *name2, char *club, char *height1, char *height2, char *weight1, char *weight2, char *seibetu, char *number struct student *head);
void show_student(struct student *p);
void free_student(struct student *p);

int main(void)
{
	static char deta1[100] = {"Three Student Deta : 2.1 Club Height Weight Class"};
	static char deta2[100] = {"Tanaka Taro: 2.1 baseball 170.3 cm 65 Kg man 21"};
	static char deta3[100] = {"Sato Ichiro: 2.1 succer 168.4 cm 59 Kg man 19"};
	static char deta4[100] = {"Suzukiyosio: 2.1 tennis 173.9 cm 61 Kg man 20"};
	static char c1[] = {" :"CLASS1""};
	struct student *head;
	char name1[100];
	char name2[100];
	char club[100];
	char height1[100];
	char height2[100];
	char weight1[100];
	char weight2[100];
	char seibetu[100];
	char number[100];
	head = NULL;
	char *cut;
	int i;
	cut = strtok(deta2, c1);
	
	while(cut != NULL)
		{
			strcpy(num[i].name1, num[i].name2, num[i].club, num[i].height1, num[i].height2, num[i].weight1, num[i].weight2, num[i].seibetu, num[i].number, cut);

		head = *add_student(num[i].name1, num[i].name2, num[i].club, num[i].height1, num[i].height2, num[i].weight1, num[i].weight2, num[i].seibetu, num[i].number head);

			cut = strtok(NULL, c1);
		}
	show_student(head);
	show_student(head);
	printf("word is %d\n", 	STU_NUMBER);	

	return 0;
}


struct student *add_student(char *name1, char *name2, char *club, char *height1, char *height2, char *weight1, char *weight2, char *seibetu, char *number struct student *head);
{
	struct student *p;
	
	if ((p = (struct student *) malloc(sizeof(struct student))) == NULL) {
		printf("malloc error\n");
		exit(EXIT_FAILURE);
	}

	p->next = head;		
	head = p;
	
	return head;
}

void show_student(struct student *p)
{
	while (p != NULL) {	
		printf("%s\n", p->name1, p->name2, p->club, p->height1, p->height2, p->weight1, p->weight2, p->seibetu, p->number);
		p = p->next;
	}
}

void free_student(struct student *p)
{
	struct student *p2;

	while (p != NULL) {  
		p2 = p->next;
		free(p);
		p = p2;
	}
}
[1]やりたいこと
学校の課題の一部で以下のことができるようなプログラムを作成したいです。
①char deta1~4から取得した文字列を分割して構造体内の配列に格納
②それを文字列がNULLになるまで格納
③構造体内の要素数をカウントし、要素数が8~9以外は処理を終了させて①へ戻る
④それをdeta4まで繰り返す
配列に格納する理由は、文字列のソートなどの作業も考えているためです。
また、理想となる実行結果は以下のようなものです。

コード:

Tanaka Taro baseball 170.3 cm 65 Kg man 21
word is 9
Sato Ichiro succer 168.4 cm 59 Kg man 19
word is 9
Suzukiyosio tennis 173.9 cm 61 Kg man 20
word is 8
[2]とりあえずdeta2だけでも表示させようとすると以下のエラーが表示されます
test1.c: In function 'main' :
test1.c:51 error : too many arguments to function 'strcpy'
test1.c:55 error : incompatible types in assignment

非常に長くなってしまった上に拙い説明になってしまい申し訳ありませんが、答えていただけると幸いです。

Re: 分割した文字列を自己参照構造体に入れて要素数をカウント

Posted: 2016年10月25日(火) 00:14
by みけCAT
素人マン さんが書きました:[2]とりあえずdeta2だけでも表示させようとすると以下のエラーが表示されます
test1.c: In function 'main' :
test1.c:51 error : too many arguments to function 'strcpy'
test1.c:55 error : incompatible types in assignment
申し訳ないですが、信じられません。
提示されたコードの55行目は}だけであり、代入はありません。
また、提示されたコードをWandboxでコンパイルしたところ、以下のエラーと警告が出力されました。

コード:

prog.c:22:155: error: expected ';', ',' or ')' before 'struct'
 struct student *add_student(char *name1, char *name2, char *club, char *height1, char *height2, char *weight1, char *weight2, char *seibetu, char *number struct student *head);
                                                                                                                                                           ^
prog.c: In function 'main':
prog.c:50:11: error: 'num' undeclared (first use in this function)
    strcpy(num[i].name1, num[i].name2, num[i].club, num[i].height1, num[i].height2, num[i].weight1, num[i].weight2, num[i].seibetu, num[i].number, cut);
           ^
prog.c:50:11: note: each undeclared identifier is reported only once for each function it appears in
prog.c:50:4: error: too many arguments to function 'strcpy'
    strcpy(num[i].name1, num[i].name2, num[i].club, num[i].height1, num[i].height2, num[i].weight1, num[i].weight2, num[i].seibetu, num[i].number, cut);
    ^
prog.c:52:3: warning: implicit declaration of function 'add_student' [-Wimplicit-function-declaration]
   head = *add_student(num[i].name1, num[i].name2, num[i].club, num[i].height1, num[i].height2, num[i].weight1, num[i].weight2, num[i].seibetu, num[i].number head);
   ^
prog.c:52:158: error: expected ')' before 'head'
   head = *add_student(num[i].name1, num[i].name2, num[i].club, num[i].height1, num[i].height2, num[i].weight1, num[i].weight2, num[i].seibetu, num[i].number head);
                                                                                                                                                              ^
prog.c:6:51: warning: format '%d' expects argument of type 'int', but argument 2 has type 'long unsigned int' [-Wformat=]
 #define STU_NUMBER ((sizeof deta2)/(sizeof(struct student)))
                                                   ^
prog.c:58:26: note: in expansion of macro 'STU_NUMBER'
  printf("word is %d\n",  STU_NUMBER); 
                          ^
prog.c:45:6: warning: variable 'i' set but not used [-Wunused-but-set-variable]
  int i;
      ^
prog.c: At top level:
prog.c:64:155: error: expected ';', ',' or ')' before 'struct'
 struct student *add_student(char *name1, char *name2, char *club, char *height1, char *height2, char *weight1, char *weight2, char *seibetu, char *number struct student *head);
                                                                                                                                                           ^
prog.c:65:1: error: expected identifier or '(' before '{' token
 {
 ^
prog.c: In function 'show_student':
prog.c:82:3: warning: too many arguments for format [-Wformat-extra-args]
   printf("%s\n", p->name1, p->name2, p->club, p->height1, p->height2, p->weight1, p->weight2, p->seibetu, p->number);
   ^
素人マン さんが書きました:どのようにすればいいのか分かりません。
  • 慌てないでください。落ち着いてください。
  • デタラメを書かず、使用する関数の説明をきちんと読んでから使ってください。
    素人マン さんが書きました:

    コード:

    strcpy(num[i].name1, num[i].name2, num[i].club, num[i].height1, num[i].height2, num[i].weight1, num[i].weight2, num[i].seibetu, num[i].number, cut);
    C言語標準のstrcpyは引数を2個しか取りません。
    こんなデタラメなstrcpyの使い方、どこで学んだのですか?

    また、
    素人マン さんが書きました:

    コード:

    printf("%s\n", p->name1, p->name2, p->club, p->height1, p->height2, p->weight1, p->weight2, p->seibetu, p->number);
    という行も、(きちんと使う引数が初期化されていれば)余計な引数は評価後無視されるだけなので無害で規格に沿っているとはいえ、不自然に引数が多いです。
  • 投稿に矛盾がないようにしてください。
    コードとエラーメッセージを貼る場合は、対応したものにしてください。

Re: 分割した文字列を自己参照構造体に入れて要素数をカウント

Posted: 2016年10月25日(火) 00:44
by みけCAT
素人マン さんが書きました:[1]やりたいこと
学校の課題の一部で以下のことができるようなプログラムを作成したいです。
①char deta1~4から取得した文字列を分割して構造体内の配列に格納
②それを文字列がNULLになるまで格納
③構造体内の要素数をカウントし、要素数が8~9以外は処理を終了させて①へ戻る
④それをdeta4まで繰り返す
配列に格納する理由は、文字列のソートなどの作業も考えているためです。
また、理想となる実行結果は以下のようなものです。

コード:

Tanaka Taro baseball 170.3 cm 65 Kg man 21
word is 9
Sato Ichiro succer 168.4 cm 59 Kg man 19
word is 9
Suzukiyosio tennis 173.9 cm 61 Kg man 20
word is 8
とりあえずこのコードで出力は合いました。

コード:

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

/* 捨てる文字列 */
#define CLASS1 "2.1"

/* 構造体の定義 */
typedef struct student{
	char name1[100];
	char name2[100];
	char club[100];
	char height1[100];
	char height2[100];
	char weight1[100];
	char weight2[100];
	char seibetu[100];
	char number[100];
	struct student *next;
}student;

int main(void)
{
	/* 入力データ */
	static char deta1[100] = "Three Student Deta : 2.1 Club Height Weight Class";
	static char deta2[100] = "Tanaka Taro: 2.1 baseball 170.3 cm 65 Kg man 21";
	static char deta3[100] = "Sato Ichiro: 2.1 succer 168.4 cm 59 Kg man 19";
	static char deta4[100] = "Suzukiyosio: 2.1 tennis 173.9 cm 61 Kg man 20";
	/* 区切り文字 */
	static char c1[] = " :";

	/* 入力データ(へのポインタ)をまとめて処理できるように配列に入れる */
	char *inputs[4] = {deta1, deta2, deta3, deta4};

	/* 各入力データを処理する */
	int i;
	for (i = 0; i < 4; i++)
	{
		/* データを格納する構造体 */
		student head;
		/* 格納したデータの数 */
		int count = 0;
		/* 構造体の各要素をまとめて処理できるように配列に入れる */
		char *targets[] = {
			head.name1, head.name2, head.club, head.height1, head.height2,
			head.weight1, head.weight2, head.seibetu, head.number
		};
		/* 取得したトークン */
		char *cut;
		/* 最初のトークンを取得する */
		cut = strtok(inputs[i], c1);

		/* トークンが取れなくなるまで処理する */
		while(cut != NULL)
		{
			/* トークンが捨てる対象でなく、格納先の要素が残っているなら */
			if (strcmp(cut, CLASS1) != 0 && (size_t)count < sizeof(targets) / sizeof(*targets))
			{
				/* 格納してカウントする */
				strcpy(targets[count], cut);
				count++;
			}
			/* はみ出して捨てる分をカウントしてしまうと、「構造体内の要素数」にならないので、こっちでカウントはしない */
			/* 次のトークンを取得する */
			cut = strtok(NULL, c1);
		}
		/* 格納した数が条件を満たすなら */
		if (8 <= count && count <= 9)
		{
			int j;
			/* 「理想となる実行結果」に沿った出力をする */
			printf("%s", targets[0]);
			for (j = 1; j < count; j++)
			{
				printf(" %s", targets[j]);
			}
			printf("\nword is %d\n", count);
		}
	}

	/* 処理系に正常終了したことを伝える */
	return 0;
}

Re: 分割した文字列を自己参照構造体に入れて要素数をカウント

Posted: 2016年10月26日(水) 19:03
by 素人マン
みけCAT様
返信と回答ありがとうございました。
string.hのライブラリ関数について深く学習しようと思います。