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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

1166閲覧

c言語 線形リストと動的領域確保(malloc関数)について

_ta_ryo

総合スコア11

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

2クリップ

投稿2019/06/03 08:25

編集2019/06/03 08:59

前提・実現したいこと

C言語で線形リストを用いて講義の科目名、単位数、成績をリストに保存できるプログラムを作成しています。
コンパイルは問題なく通るのですが実行すると上手く動かないため質問させていただきます。

発生している問題・エラーメッセージ

実行後、1を入力してデータを追加すると途中で終了してしまいます(以下が実行結果)

C:\Users\tar\program>a
1:科目の追加 2:科目の挿入 3:要素の削除
4:要素の表示 5:GPAの表示 0:終了
操作を入力してください:1
科目名を入力してください:w
単位数を入力してください:1
GPを入力してください2

aa

ただしスイッチ文のcase1の中のprintf内の文章を長めの文字(ここでは0000000)に変更すると以下のように実行できます。

C:\Users\tar\program>a
1:科目の追加 2:科目の挿入 3:要素の削除
4:要素の表示 5:GPAの表示 0:終了
操作を入力してください:1
科目名を入力してください:w
単位数を入力してください:1
GPを入力してください2
0000000
aaii1:科目の追加 2:科目の挿入 3:要素の削除
4:要素の表示 5:GPAの表示 0:終了
操作を入力してください:4
length = 1
w 1 2.00
1:科目の追加 2:科目の挿入 3:要素の削除
4:要素の表示 5:GPAの表示 0:終了
操作を入力してください:0

aaまで表示できることからmallocの使い方が悪いと思うのですが、どのように改善したらよいか分かりません。
今回の質問に関係のないremovedata関数やinsertdata関数は省略させていただきました。
ご教示よろしくお願いいたします。

該当のソースコード

#include <stdio.h> #include <stdlib.h> /* 要素データの構造定義 */ struct Data { char *name; int num; double gp; struct Data *pNext; }; typedef struct Data data; /* リストの構造定義 */ typedef struct { data *pHead; int length; } List; /* 関数プロトタイプ */ void initialize(List*); void disp(List); void adddata(List*, char*, int, double); void removedata(List*, int); void insertdata(List*, int, char*, int, double); int main() { char str[30]; int num, n, mode; double gp; /* リスト型の宣言 */ List v; /* 初期化 */ initialize(&v); do{ printf("1:科目の追加\t2:科目の挿入\t3:要素の削除\n"); printf("4:要素の表\示\t5:GPAの表\示\t0:終了\n"); printf("操作を入力してください:"); scanf("%d", &mode); switch(mode){ case 1 : printf("科目名を入力してください:"); scanf("%s",str); printf("単位数を入力してください:"); scanf("%d",&num); printf("GPを入力してください"); scanf("%lf", &gp); printf("\n"); adddata(&v, str, num, gp); break; case 2 : printf("科目名を入力してください:"); scanf("%s",str); printf("単位数を入力してください:"); scanf("%d",&num); printf("GPを入力してください"); scanf("%lf", &gp); printf("何番目の前に挿入しますか:"); scanf("%d",&n); printf("\n"); insertdata(&v, n-1, str, num, gp); break; case 3 : printf("何番目を削除しますか:"); scanf("%d", &n); removedata(&v, n); break; case 4 : printf("length = %d\n", v.length); disp(v); break; case 0 : break; default: printf("正しい値を入力してください\n"); break; } }while(mode != 0); /* 全要素の削除 */ while(v.pHead == NULL){ removedata(&v, 1); } return 0; } /* 線形リストの初期化 */ void initialize(List *pV) { pV->pHead = NULL; pV->length = 0; } /* 要素の表示 */ void disp(List v) { data *pd; pd = v.pHead; if(pd == NULL) printf("リストには何もありません。\n"); else { while(pd != NULL) { printf("%s\t%d\t%1.2f\n", pd->name,pd->num,pd->gp); pd = pd->pNext; } } } /* 要素の追加 */ void adddata(List *pV, char *name, int num, double gp) { /* 最後尾要素のポインタ */ data *pLast; /* 新規に追加する要素の生成 */ data *pNew; printf("aa"); pNew->name = (char*)malloc(sizeof(name)); printf("aaaa"); pNew = (data*)malloc(sizeof(data));/* 領域確保 */ pNew->name = name; pNew->num = num; pNew->gp = gp; pNew->pNext = NULL; if( pV->pHead == NULL ) { /* リストが空の場合 */ pV->pHead = pNew; /* 新規要素を先頭にリンク */ } else { /* リストが空でない場合 */ pLast = pV->pHead; while( pLast->pNext != NULL ) /* 最後尾を探索 */ pLast = pLast->pNext; pLast->pNext = pNew; /* 新規要素を最後尾にリンク */ } pV->length++; }

補足情報(FW/ツールのバージョンなど)

OS:windows10
コンパイラ:gcc

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/06/03 08:35

このままではコードが見づらいので、質門を編集し、<code>ボタンで、出てくる’’’の枠の中にコードを貼り付けてください
_ta_ryo

2019/06/03 09:00

ご指摘ありがとうございます。修正させていただきました。
guest

回答3

0

C

1 /* 新規に追加する要素の生成 */ 2 data *pNew; 3 pNew = (data*)malloc(sizeof(data));/* 領域確保 */ 4 pNew->name = (char*)malloc(strlen(name)+1); /* 文字列格納するのに十分な領域を確保し*/ 5 strcpy(pNew->name, name); /* しかるのちそこにコピー */ 6 pNew->num = num; 7 pNew->gp = gp; 8 pNew->pNext = NULL;

...ぢゃろね。

投稿2019/06/04 02:48

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

pNew->name = (char*)malloc(sizeof(name));

printf("aaaa");
pNew = (data*)malloc(sizeof(data));/* 領域確保 */
pNew->name = name;

ちと分かりづらいので修正
nameはなんでしょう。
そして、pNew->name には何が入るんでしょう

投稿2019/06/03 08:40

編集2019/06/03 08:47
y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_ta_ryo

2019/06/03 09:04 編集

回答ありがとうございます。 pNew->nameにはadddata関数の引数であるnameが入ります。 構造体pNewの中のnameの領域確保→構造体のnameに引数であるnameを入れるという流れを行いたいと考えました。 変数名を同じにしてしまったためややこしくなってしましました…
y_waiwai

2019/06/03 09:07

まず、この最初の行はアクセス違反となります pNew は初期化されてないので、でたらめな値が入ってます。 運が良ければ暴走しますが、運が悪けれ動き続けます。 そして、ここのnameという値は、なんでしょうか。どこからくる値?
_ta_ryo

2019/06/03 09:30

pNewのメンバであるnameはポインタ変数なので、領域確保をした後でないと初期化も別の変数を保存することもできないと考えたのですが、そもそもpNewという構造体そのものを初期化した後でないとpNewのメンバにアクセスして領域確保も行えないということでしょうか? その場合、構造体の初期化とはどのようにして行うのでしょうか? callocを利用することも考えたのですが、pNewのメンバであるnameのサイズが未決定であるため構造体のサイズも定まらないと考えたのですが、そのような事はないのでしょうか? nameはメイン関数内でscanf関数によって入力されたstrをadddata関数の引数として持ってきたもので、adddata関数内での変数名をnameとしています。
y_waiwai

2019/06/03 09:48

pNewってのは、dataのポインタとして定義されてます 本来、どこかにあるdataのアドレスが入るべきものです ところが、その何処かにあるdataのアドレスを入れる前にそのメンバに何かを入れてます。 そしてべつのはなし nameという変数はどこから来ているかというと、main関数内で定義されたstrのアドレスですね。 main関数内でいくらループしていようが、このstrという配列のアドレスは変わるもんじゃありません。 つまりは、生成されたdataのnameはすべて同じ値が入ります char*  といいうのはあくまでアドレスが入ります。文字列というのは、そのアドレスの指した先に格納されてます。
guest

0

y_waiwaiさん、epistemeさんの回答の要約ですが…

お二人の指摘するように、このプログラムには問題が3つあります。

  1. (未初期化のポインタ)pNewの内容にアクセスしてメンバ変数nameを初期化しようとしていること。得体の知れない領域を書き換えているので何がおきてもおかしくありません。

  2. nameメンバの初期化。文字列のコピーには文字列の文字数+1(ヌル文字)個以上の要素からなるchar型の配列が必要です。sizeof演算子で引数の文字列の大きさを求めようとしていますが、この方法では上手くいきません。なぜなら、引数で渡されるのはあくまで配列の先頭要素へのポインタで、sizeofはそのポインタのバイト数を取得する仕様になっているからです。文字列の文字数を取得する場合、strlen関数を使う必要があります。

  3. nameメンバの内容の初期化。今の方法ではnameメンバ(ポインタ)を引数のname(ポインタ)で初期化しています。ポインタの先の内容をコピーする場合、strcpy関数を使う必要があります。

以上、要約です。問題点を簡潔にまとめただけなので、厳密には誤っている部分もあります。不明な点は一度自分で要約中からキーワードを拾って検索し、それで分からない場合はコメントを送ってください。

投稿2019/06/05 04:53

majiponi

総合スコア1720

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問