• 締切済み

【C言語】構造体内の領域解放(free)の仕方

C言語について教えてください。 大学の課題でCを書いています。 freeの仕方について教えてください。 構造体 struct word { struct word *next; char *st; int *line_no; int line_cnt; }; を用意し、char* stにstrdupにて文字列を格納します。 そして、簡単なリストを作り、表示をさせfreeをするプログラムです。 freeをする際にfreeしてはいけないメモリをfreeしているようです。 しかし、正しい場所をfreeしていると思うので、なぜエラーなのか分かりません。 理由と解決方法を御教授願えませんでんしょうか。 よろしくお願いします。 /************以下ソース****************/ #include<stdio.h> #include<stdlib.h> #include<string.h> struct word { struct word *next; char *st; int *line_no; int line_cnt; }; struct word *head; void Add_List(char *buf,int no){ struct word* node = malloc(sizeof(struct word*)); struct word* crnt; /*nodeの準備*/ node->next = NULL; node->st = strdup(buf); node->line_no = malloc(sizeof(int*)); node->line_no[0] = 1; node->line_cnt= 1; if(head == NULL) { head = node; } else { crnt = head; while( crnt->next != NULL) { crnt = crnt->next; } crnt->next = node; } } void printlist(){ struct word *crnt = head; while( crnt != NULL ) { printf("%s\n",crnt->st); crnt = crnt->next; } } int main(){ head = NULL; char buf1[] = {'A','B','C','D','E','\0'}; char buf2[] = {'F','G','H','I','J','\0'}; char buf3[] = {'K','L','M','N','O','\0'}; Add_List(buf1,1); Add_List(buf2,1); Add_List(buf3,1); printlist(); /*この部分がうまくいかない*/ free(head->st); /*********************/ } (以下実行結果です。OS:CentOS) [yuichiro-ito@localhost test]$ ./a.out ABCDE FGHIJ KLMNO *** glibc detected *** ./a.out: free(): invalid pointer: 0x0000000001a01030 *** ======= Backtrace: ========= /lib64/libc.so.6[0x365a4760e6] ./a.out[0x40072f] /lib64/libc.so.6(__libc_start_main+0xfd)[0x365a41ecdd] ./a.out[0x4004d9]  ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:02 390975 /home/yuichiro-ito/test/a.out 00600000-00601000 rw-p 00000000 08:02 390975 /home/yuichiro-ito/test/a.out 01a01000-01a22000 rw-p 00000000 00:00 0 [heap] 3659c00000-3659c20000 r-xp 00000000 08:02 785966 /lib64/ld-2.12.so 3659e1f000-3659e20000 r--p 0001f000 08:02 785966 /lib64/ld-2.12.so 3659e20000-3659e21000 rw-p 00020000 08:02 785966 /lib64/ld-2.12.so 3659e21000-3659e22000 rw-p 00000000 00:00 0 365a400000-365a58a000 r-xp 00000000 08:02 785967 /lib64/libc-2.12.so 365a58a000-365a789000 ---p 0018a000 08:02 785967 /lib64/libc-2.12.so 365a789000-365a78d000 r--p 00189000 08:02 785967 /lib64/libc-2.12.so 365a78d000-365a78e000 rw-p 0018d000 08:02 785967 /lib64/libc-2.12.so 365a78e000-365a793000 rw-p 00000000 00:00 0 3666c00000-3666c16000 r-xp 00000000 08:02 785985 /lib64/libgcc_s-4.4.7-20120601.so.1 3666c16000-3666e15000 ---p 00016000 08:02 785985 /lib64/libgcc_s-4.4.7-20120601.so.1 3666e15000-3666e16000 rw-p 00015000 08:02 785985 /lib64/libgcc_s-4.4.7-20120601.so.1 7fc7b9e92000-7fc7b9e95000 rw-p 00000000 00:00 0 7fc7b9ea0000-7fc7b9ea3000 rw-p 00000000 00:00 0 7fffbce3c000-7fffbce51000 rw-p 00000000 00:00 0 [stack] 7fffbce9d000-7fffbce9e000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

みんなの回答

  • onegai5
  • ベストアンサー率0% (0/0)
回答No.1

free()の使い方ではなくてmalloc()の使い方が間違ってます. > struct word* node = malloc(sizeof(struct word*)); これだと sizeof(struct word*) バイト、つまりポインタのバイト数 (普通、4バイトとか8バイト)のメモリ しか 確保されていません。 そこに無理矢理構造体のデータを書き込んでしまっているのでメモリ管理が破綻してます。 構造体本体を確保する場合はこうします。 struct word* node = malloc(sizeof(struct word)); > node->line_no = malloc(sizeof(int*)); こちらも同様。 ポインタ line_no で示される位置に格納されるのは int* ではなくて int ですから node->line_no = malloc(sizeof(int)); とします。 余談ですが、malloc()やstrdup()などで動的にメモリを確保した際には、必ずNULLかどうかチェックしてメモリ不足を捕まえておかないと後で苦労する事になります。 (本格的なプログラムを書き始めると、それこそどこが原因でエラーが起きてるのか判らなくなります) 今からCを習得されるのでしたら、C++から入った方が楽です。 malloc()しません.し、 ( struct word* node = new struct word; とします) もし間違って struct word* node = new struct word*; と書いてしまった場合ばコンパイラがエラー吐いて教えてくれますから.

関連するQ&A

  • 【C言語】構造体内の領域解放(free)の仕方

    教えてGoo運営側に内容チェックされているため再度内容を変更し質問させていただきます。 http://okwave.jp/qa/q8080757.html (ダンプを書いたのがまずかったかもしれないので、ここでは削除します。) <プログラムで実行したいこと> ・簡単なリストを作成 ・リストを構成する構造体のメンバはchar*などのメンバがあり、  特に、char*にstrdupにて文字列をコピーする。(正確には文字列のポインタをコピーする。) ・作ったリストをプリントする。 ・領域を確保する。 下記のソースで動くと思ったのですが、領域のfreeでうまくいきません。 どうもない領域をfreeしているようなのです。それがなぜかわかりません。 *** glibc detected *** ./a.out: free(): invalid pointer: 0x00000000020eb030 *** どうしたら、解決するのか、どこが悪いのかご指摘いただけないでしょうか。 以下、私が書いたソースになります。 #include<stdio.h> #include<stdlib.h> #include<string.h> struct word { struct word *next; char *st; int *line_no; int line_cnt; }; struct word *head; void Add_List(char *buf,int no){ struct word* node = malloc(sizeof(struct word*)); struct word* crnt; /*nodeの準備*/ node->next = NULL; //node->st = strdup(buf); node->st = malloc(sizeof(char)*10); strcpy(node->st,buf); node->line_no = malloc(sizeof(int*)); node->line_no[0] = 1; node->line_cnt= 1; if(head == NULL) { head = node; } else { crnt = head; while( crnt->next != NULL) { crnt = crnt->next; } crnt->next = node; } } void printlist(){ struct word *crnt = head; while( crnt != NULL ) { printf("%s\n",crnt->st); crnt = crnt->next; } } int main(){ head = NULL; char buf1[] = {'A','B','C','D','E','\0'}; char buf2[] = {'F','G','H','I','J','\0'}; char buf3[] = {'K','L','M','N','O','\0'}; Add_List(buf1,1); Add_List(buf2,1); Add_List(buf3,1); printlist(); /*この部分がうまくいかない*/ printf("%s\n",head->st); printf("%x \n",head->st); free(head->st); /*********************/ }

  • C言語解読

    #include <stdio.h> #include <stdlib.h> #include <string.h> #define dBufferSize (32768) #define dPrintFmt "#d: %s\n" typedef struct _NODE NODE; struct _NODE { char *line; NODE *next; }; int RemoveReturnCode(char *string); NODE *MakeNode(char *string); int FreeNodeList(NODE *node); void FreeNode(NODE *node); int PrintNoceList(NODE *node); NODE *ReverseNodeList(NODE **head); int main(void){ char buffer[dBufferSize]; NODE *head = NULL; while (fgets(buffer, dBufferSize, stdin) != NULL){ NODE *pivot; RemoveReturnCode(buffer); pivot = MakeNode(buffer); if (pivot == NULL) return FreeNodeList(head); pivot->next = head; head =pivot; } PrintNodeList(head); ReverseNodelist(&head); PrintNodeList(head); FreeNodeList(head); return 0; } int RemoveReturnCode(char *str){ char *p; if (str == NULL) return -1; for (p = str; *p != '\n' && *p != '\r' && *p != '\0'; p++) ; *p = '\0'; return p - str; } NODE *MakeNode(char *str){ NODE *node; if(str == NULL)return NULL; node = (NODE *)calloc(1,sizeof(NODE)); if(node != NULL){ char *p = (char *)calloc(strlen(str)+1, sizeof(char)); if (p != NULL){ node->line = strcpy(p, str); node->next = NULL; } else{ free(node); node = NULL; } } return node; } int FreeNodeList(NODE *node){ int ct = 0; while (node != NULL){ NODE *next = node->next; FreeNode(node); ct++; node = next; } return ct; } void FreeNode(NODE *node){ free(node->line); free(node); } int PrintNodeList(NODE *node){ int ct; for (ct = 0; node != NULL; node = node->next, ct++) printf(dPrintFmt, ct+1, node->line); return ct; } NODE *ReverseNodeList(NODE **head){ NODE *reverse = NULL; NODE *node = *head; while (node != NULL){ NODE *next = node->next; node->next = reverse; reverse = node; node = next; } return *head = reverse; } このプログラムは単方向リストを利用して複数行のデータを格納していくものであるという ものらしいのですが、そのようなヒントがあっても、まったく解読できません、 手も足も出ない状態です。 できれば、初心者に近い私にもわかるように、関数ごとの解説をおねがいします!! エラーがでるかもしれないのですが・・・大体の意味にはかわりないと思いますので、宜しくお願いします!!

  • C言語 リスト

    (1) /* list.c */ #include <stdio.h> #include <stdlib.h> struct node { int num; struct node *next; }; main() { struct node *head, *p; int x; head = NULL; while(scanf("%d",&x) != EOF) { p = (struct node *)malloc(sizeof(struct node)); p->num = x; p->next = head; head = p; } // リストの要素のnumの値を先頭から順に表示する p=head; while(p!=NULL) { printf("%d\n" ,p->num); p = p->next; } } (2) struct node *q; q = head; while(q->next != NULL) q = q->next; (1)を(2)を使い新しいノードをリストの最後に追加するようにしたいのですが どう書いたら良いのか教えていただきたいです

  • C言語に関する質問

    初めて質問させて頂きます。C言語初心者です。 実は講義で「ファイル中の英文を単語に分けてその出現頻度をカウントするコードを木構造を用いて出力せよ」という課題が出ました。 そこで、参考にするコードを検索しましたところ、以下のURLにあるベストアンサーのコードが近いと感じました。 http://okwave.jp/qa/q4155655.html コードの内容は以下の通りになります。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> typedef struct node Node; struct node{ char *word; int count; Node *left,*right; }; Node *root=NULL; void compose(FILE *fp); void inorder(Node *p); void strlower(char *s); int main(int argc, char *argv[]) { FILE *fp; Node *new; fp=fopen(argv[1],"r"); if(fp==NULL){puts("ファイルを開けません");return(-1);} compose(fp); inorder(root); return (0); } void strlower(char *s){ while(*s!=NULL){*s=tolower(*s);s++;} } void compose(FILE*fp){ Node **p,*new; char buf[256]; while(1){ fscanf(fp,"%[^a-zA-Z0-9]",buf); if(fscanf(fp,"%[a-zA-Z0-9]",buf)==EOF)break; strlower(buf); if(root==NULL){ new=(Node *)malloc(sizeof(Node)); new->left=NULL; new->right=NULL; new->word=strdup(buf); new->count=1; root=new; }else{ *p=root; while(1){ if(strcmp(buf,(*p)->word)==0){ (*p)->count++;break; }else if(strcmp(buf,(*p)->word)<0){ if((*p)->left==NULL){ new=(Node *)malloc(sizeof(Node)); new->left=NULL;new->right=NULL;new->word=strdup(buf);new->count=1; (*p)->left=new; break; }else{ *p=(*p)->left; } }else{ if((*p)->right==NULL){ new=(Node *)malloc(sizeof(Node)); new->left=NULL; new->right=NULL; new->word=strdup(buf); new->count=1; (*p)->right=new; break; }else{ *p=(*p)->right; } } } } } } void inorder(Node*p){ if (p==NULL) return; inorder(p->left); printf("%s %d\n",p->word, p->count); inorder(p->right); } しかし、これをそのままコンパイル・実行すると、コンパイル時に以下の注意が出ます。 warning comparison between pointer and integer ('int' and 'char *') while(*s!=NULL){*s=tolower(*s);s++;} 上記の注意を無視してそのまま実行すると、segmatation faultが出てしまいますorz おそらく、sの型が*s=s[]なので、注意の中の「s++」の部分で誤作動を起こしている(s++を実行するにはsはint型でなければならない)と思うのですが、どうコード文を変えれば良いのかがよくわかりません。 どなたかお教え頂けると幸いです。どうぞよろしくお願いしますm(_ _)m

  • C言語のプログラム

    以下のプログラムはハッシュテーブルを用いて文字列を探すプログラムなのですが、コンパイル時にセグメントエラーとなってしまいます。プログラム中に誤った箇所があれば教えて頂きたいです。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASHSIZE 10 #define MAX_LEN 64 #define N_WORDS 4 struct list { char word [MAX_LEN]; struct list *next; }; struct list *hash_table[HASHSIZE]; char colors[N_WORDS][MAX_LEN] = {"red", "blue", "green", "yellow"}; void my_strcpy(char* a, const char* b) { int i = 0; while(*b != '\0'){ *(a+i) = *(b+i); i++; } *(a+i) = '\0'; } int hash(char *key) { int hashval = 0; while (*key != '\0') { hashval += *key; key++; } return (hashval % HASHSIZE); } int find_word (char *key) { struct list *p; for (p = hash_table[hash(key)]; p != NULL; p++) if (strcmp(key, p->word) == 0) return 1; return 0; } void init_hash_table() { int i, hashvalue; struct list *p, *q; for (i = 0; i < HASHSIZE; i++) { hash_table[i] = NULL; } for (i = 0; i < N_WORDS; i++) { if ((find_word(colors[i])) == 0){ p = (struct list *)malloc(sizeof(struct list)); my_strcpy(p->word, colors[i]); hashvalue = hash(colors[i]); if (hash_table[hashvalue] = NULL) { hash_table[hashvalue] = p; p->next=NULL; } else { q = hash_table[hashvalue]; while (q->next != NULL) q = q->next; q->next = p; p->next=NULL; } } } } void main(void) { init_hash_table(); printf("result = %d\n", find_word("red")); }

  • このプログラムのポインタを配列に変換したいんですけど

    C言語初心者です。助けてください。 途中までがんばったのですがどうしてもできません。問題はこの構造体の*name→name[25],*email→email[30]に変換させたいのですが、そのまま変換すると左辺値が必要や移植性のないポインタ変換などのエラーが出てしまいます。どうすればいいですか?教えてください。あと関数getlineと構造体は変えないでください。(指定した部分は除く) このプログラムは名前、メールアドレス、年齢を保存していき-1を入力した時出力されるというものです。 よろしくお願いします。 入力例 10 hakata abc@・・・ 12 yokohama dfg@・・・ -1 -1 -1 出力例 -1 -1 -1 12 yokohama dfg@・・・ 10 hakata abc@・・・ #include <stdio.h> #include<stdlib.h> struct node { char *name; char *email; int age; struct node *next; } heap[100], *hp = heap; void getline(char *s,int n) { int c; while(--n>0&&((c=getchar())!=EOF && c!='\n')) *s++=c; *s='\0'; } char* dupstr(char* strg) { char* newstr; newstr=(char*)malloc(sizeof(char)*strlen(strg)); strcpy(newstr,strg); return newstr; } struct node *new(int n ,char* a, char* b) { hp->age=n; hp->email=a; hp->name=b; hp->next=NULL; return hp++; } struct node *add(struct node *p, struct node *q) { q->next=p; p=q; return p ; } void print_list(struct node *p) { while (p != NULL) { printf("%d ", p->age); printf("%s ", p->name); printf("%s ", p->email); p=p->next; } printf("\n"); } main() { int age,p; char buf[80],a[80],b[80],*email,*name; struct node *root=NULL; while(getline!=NULL) { getline(buf,sizeof(buf)); age=atoi(buf); getline(b,sizeof(b)); getline(a,sizeof(a)); email=dupstr(b); name=dupstr(a); root=add(root,new(age,email,name)); if(age==-1) break; } print_list(root); }

  • reallocでエラー

    reallocを使うとエラーがでます。 簡単なreallocのプログラムでもエラーがでて、realloc自体が使えないような感じです。 どうしたらよいでしょうか? 試したプログラムは #include<stdlib.h> #include<stdio.h> #include<string.h> int main(void){ char *p; p=malloc(17); if(!p){ printf("error\n"); exit(1); } strcpy(p,"これは16文字です"); p=realloc(p,18); if(!p){ printf("error\n"); exit(1); } strcat(p,"."); printf(p); free(p); return 0; } というもので、 *** glibc detected *** ./test: realloc(): invalid next size: 0x09b61008 *** ======= Backtrace: ========= /lib/libc.so.6[0x43ca2f] /lib/libc.so.6(realloc+0xfe)[0x43e68e] /lib/libc.so.6[0x43ea61] /lib/libc.so.6(realloc+0x3c)[0x43e5cc] ./test[0x8048512] /lib/libc.so.6(__libc_start_main+0xe0)[0x3e8f70] ./test[0x80483e1] ======= Memory map: ======== 00235000-0023f000 r-xp 00000000 fd:00 360450 /lib/libgcc_s-4.1.2-20070626.so.1 0023f000-00240000 rwxp 00009000 fd:00 360450 /lib/libgcc_s-4.1.2-20070626.so.1 003d3000-00521000 r-xp 00000000 fd:00 360473 /lib/libc-2.6.so 00521000-00522000 r-xp 0014e000 fd:00 360473 /lib/libc-2.6.so 00522000-00524000 rwxp 0014f000 fd:00 360473 /lib/libc-2.6.so 00524000-00527000 rwxp 00524000 00:00 0 00616000-00631000 r-xp 00000000 fd:00 360466 /lib/ld-2.6.so 00631000-00632000 r-xp 0001a000 fd:00 360466 /lib/ld-2.6.so 00632000-00633000 rwxp 0001b000 fd:00 360466 /lib/ld-2.6.so 006c0000-006c1000 r-xp 006c0000 00:00 0 [vdso] 08048000-08049000 r-xp 00000000 fd:00 3473718 /home/gucchi/test/test 08049000-0804a000 rw-p 00000000 fd:00 3473718 /home/gucchi/test/test 09b61000-09b82000 rw-p 09b61000 00:00 0 b7e00000-b7e21000 rw-p b7e00000 00:00 0 b7e21000-b7f00000 ---p b7e21000 00:00 0 b7fd6000-b7fd8000 rw-p b7fd6000 00:00 0 bfb07000-bfb1c000 rw-p bfb07000 00:00 0 [stack] アボートしました というエラーがでます。 試しに他の環境でコンパイルしたら実行できちゃいました。 glibcに問題があったりするんでしょうか? ご教授ください。

  • C言語の自己参照型プログラムについて

    #include <stdio.h> #include <string.h> #include <stdlib.h> struct list { int key; /* キー */ char name[20]; /* 名前 */ struct list *next; /* 次のデータへのポインタ */ }; struct list *add_list(int key, char *name, struct list *head); void show_list(struct list *p); void free_list(struct list *p); int main(void) { struct list *head; /* 先頭ポインタ */ char name[20]; int key = 0; head = NULL; /* 先頭ポインタにNULLを設定 */ printf("キーと名前(MAX:19文字)を入力(終了:CTRL+Z)\n"); while (scanf("%d %s", &key, name) != EOF) { /* リストにデータを登録 */ head = add_list(key, name, head); } /* リストの表示 */ show_list(head); /* リストの開放 */ free_list(head); return 0; } /*** リストにデータを登録 ***/ struct list *add_list(int key, char *name, struct list *head) { struct list *p; /* 記憶領域の確保 */ if ((p = (struct list *) malloc(sizeof(struct list))) == NULL) { printf("malloc error\n"); exit(EXIT_FAILURE); } /* リストにデータを登録 */ p->key = key; strcpy(p->name, name); /* ポインタのつなぎ換え */ p->next = head; /* 今までの先頭ポインタを次ポインタに */ head = p; /* 新たな領域を先頭ポインタに */ return head; } /*** リストの表示 ***/ void show_list(struct list *p) { while (p != NULL) { /* 次ポインタがNULLまで処理 */ printf("%3d %s\n", p->key, p->name); p = p->next; } } /*** リストの開放 ***/ void free_list(struct list *p) { struct list *p2; while (p != NULL) { /* 次ポインタがNULLまで処理 */ p2 = p->next; free(p); p = p2; } } これを実行すると、 新しく入力された順にリストが表示されます。 そうではなく、キーの昇順に表示したいです。 どなたかそのように実行できるようにプログラムを書き換えてくれませんか? 図々しいですがよろしくお願いいたします。m(_ _)m

  • C言語 構造体(2)

    ご質問です。 構造体で、あらかじめメンバ数を固定したものではなく、 テキストファイルを読み込んだときにメンバ数を変えて読み込みたいのです。 (カンマできりたい) aaa.txt ------------------------ あああ,いいい ------------------------ となっているときは、 tmp.nm[0]=あああ tmp.nm[1]=いいい となり、 kamoku.nm[0] kamoku.nm[1] をprintf。 aaa.txt --------------------------- あああ,いいい,ううう,えええ --------------------------- の場合は tmp.nm[0]=あああ tmp.nm[1]=いいい tmp.nm[2]=ううう tmp.nm[3]=えええ kamoku.nm[0] kamoku.nm[1] kamoku.nm[2] kamoku.nm[3] をprintf。 下記は動きません。。 よろしくお願いいたします。 #include <stdio.h> struct kamokumei { char nm[10]; }kamoku; int main(void) { int i,P,t; FILE *fp; struct kamokumei kamoku[20]; char buf[1024]; fp = fopen("aaa.txt", "r"); P=3; t=0; while( fgets(buf, sizeof(buf), fp) ){ struct kamokumei tmp; sscanf(buf, "%s", tmp.nm[t]); nm[t++] = tmp; } for(i = 0; i < P; i++) { printf("%s\n", kamoku.nm[i]); } return 0; }

  • C言語でセグメンテーションエラー

    環境はUbuntu Feisty Fawn gcc 4.1.2 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 32 #define DEBUG struct node{ char *moji; struct node *left,*right; }; typedef struct node NODE; void error(char *msg){ fflush(stdout); fprintf(stderr, "%s\n", msg); exit(1); } NODE *createNode(char *x){ NODE *new; new = malloc(sizeof(NODE)); if(new == NULL){ error("メモリがありません。\n"); } new->moji = x; new->left = NULL; new->right = NULL; return new; } NODE *insertNode(NODE *p, char *x){ if(p == NULL){ p = createNode(x); }else if(strcmp(p->moji, x) == 0){ return NULL; }else if(strcmp(p->moji, x) > 0){ p->left = insertNode(p->left, x); }else{ p->right = insertNode(p->right, x); } return p; } void printTree(NODE *p){ if(p == NULL) return; printTree(p->left); printf("%s\n",p->moji); printTree(p->right); } int main(int argc, char *argv[]){ FILE *fp; char *buf = malloc(sizeof(char) * MAX); char *ans = malloc(sizeof(char) * MAX); NODE *p = malloc(sizeof(NODE)); if( argc > 2 ){ printf("ファイルの指定は一つだけです。\n"); return -1; }else if(argc == 1){ printf("ファイルを指定してください。\n"); return -1; } fp = fopen( argv[1] , "r" ); if( fp == NULL ){ printf("ファイル読み込みに失敗しました。\n"); return -1; } while(fscanf(fp,"%s",buf) == 1){ ans = strtok(buf," -,."); p = insertNode(p, ans); while(ans != NULL){ ans = strtok(NULL," -,."); if(ans != NULL){ p = insertNode(p, ans); } } } printTree(p); fclose(fp); return 0; } このファイルを読み込んで記憶させたいんです。 file.txt ここから下がファイルの中身 The Java programming language is a general-purpose, concurrent, class-based, object-oriented language. It is designed to be simple enough that many programmers can achieve fluency in the language. どこがいけないとおもいますか?

専門家に質問してみよう