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

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

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

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

Q&A

解決済

2回答

519閲覧

構造体ポインタ配列について

emilio

総合スコア15

C

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

0グッド

0クリップ

投稿2020/01/11 07:54

前提・実現したいこと

ある配列への各要素を指すポインタを格納した配列
を並び替えること.

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

Alphabet=a Nomber=4 Alphabet=t Nomber=6 Alphabet=u Nomber=7 このように入力すると以下のエラーがでてしまいます。 Segmentation fault (core dumped)

該当のソースコード

ソースコード #include<stdio.h> typedef struct person{ char a[100]; int y; } SC; void rank(SC table[], SC* rank_array[]){ rank_array=&table; int i,j; SC temp; for(i=0;i<3;i++){ for(j=i+1;j<3;j++){ if(rank_array[i]->y<rank_array[j]->y){ temp=*rank_array[i]; rank_array[i]=rank_array[j]; rank_array[j]=&temp; } } } } int main(){ int i; SC table[3]; SC* rank_array[3]; for(i=0;i<3;i++){ printf("Alphabet="); scanf("%s",table[i].a); printf("Nomber="); scanf("%d",&table[i].y); } rank(table, rank_array); for(i=0;i<3;i++){ printf("%s %d\n",rank_array[i]->a,rank_array[i]->y); } return 0; }

試したこと

ここに問題に対して試したことを記載してください。

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

Windows10 ubuntu
ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答2

0

Segmentation Fault が起きたのは、rank() 関数の中で rank_array[1]もしくは rank_array[2] をアクセスしたことで、あらぬ番地のメモリをアクセスしてしまったから、です。

質問者のプログラムが何をしたのか、登場する変数 -- 特にポインタが何をポイントしてしまったのか、図に描いてみました。フリーハンドで申し訳ない。

イメージ説明

図は上下に分かれていて、上側は main() 関数の中の table[3] と rank_array[3] です。
下側は rank() 関数に渡された引数 table ポインタ変数と rank_array ポインタ変数です。
main()関数の中の rank_array[3] は table[3] のそれぞれをポイントすることを想定したと思いますが、実際はそうなりませんでした。

rank() 関数に2つの引数が渡されます。その2つは
void rank(SC table[], SC* rank_array[])
ですから、table ポインタ変数と rank_array ポインタ変数です。
table ポインタ変数は main() の table[3] の先頭をポイントしています。

しかし問題は rank_array ポインタ変数です。rank() 関数が呼ばれた時点では main() の rank_arrya[3] の先頭アドレスをポイントしていましたが、関数に入った途端に
rank_array = &table; の一行で、table ポインタ変数をポイントするように、値が書き換えられてしまいます。ここが大きな勘違いの元でしょう。その後、ソートする二重 for ループの中で rank_array[1] 等をアクセスしてしまいますが、図に描いたように、 rank_array[1] とは table ポインタ変数に隣接するメモリになってしまい、このメモリはSC型構造体をポイントする変数ではない ので、この辺りで Segmentation Faultが起こるのは無理からぬ事です。

この図を見せられて、質問者は「こんなつもりじゃなかった」と思われるのではないかと思いますが、これが質問者のコードから導き出される変数の姿です。

  • メモリ上の変数や配列、或いはポインタ変数を、具体的にイメージすること
  • 関数の引数として、何が渡るか、正確に理解すること
  • プログラムの各行が何をするのか、正確に理解すること

が肝要かと思います。

もうひとつ。ソートのなかで本来は rank_array[3] のなかのポインタを交換するはずだったので、一時変数 temp はポインタ変数であるべきでした。即ち、次のような格好にするべきでした。

SC *temp; // ポインタ変数を設ける if (rank_array[i]->y < rank_array[j]->y) { temp = rank_array[i]; rank_array[i] = rank_array[j]; rank_array[j] = temp; // & は不要 }

投稿2020/01/11 12:30

編集2020/01/11 12:33
rubato6809

総合スコア1380

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

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

emilio

2020/01/11 13:03 編集

ご丁寧な解説ありがとうございます。どうしてエラーが起きてしまったのか理解することができました。指摘いただいた点を改善することで想定した結果を得られました。
guest

0

ベストアンサー

rank_array=&table;

ここが間違い。これだと、rank関数の中のrank_arrayポインタ変数を変更したことになり、main関数に影響を及ぼせない。

rank_array[0] = &table[0];

のように要素1つ1つに代入してください。

投稿2020/01/11 09:28

majiponi

総合スコア1720

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

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

rubato6809

2020/01/11 10:43

もうひとつの間違いは temp 変数。 ソートするのはポインタの配列なので、ポインタを並べ替える。なので交換する時に使う一時変数もポインタ変数でなければならない。ところが SC temp; と、構造体変数をとっている。 そのため、コンパイルエラーを避けるためか rank_array[j] = &temp; としている。これで、ソートできても結果がおかしくなる。。。 メモリ上の変数の姿を的確にイメージできていないことが根源的な問題のようだ。それには・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問