C言語 構造体とポインタでセグメンテーション違反
解決済
回答 2
投稿
- 評価
- クリップ 0
- VIEW 4,843

退会済みユーザー
c言語でプログラムを作っているのですが、構造体の中のポインタを参照するとセグメンテーション違反と出ました。
調べてみたらこんな記事があって解決方法も載ってました。
http://oshiete.goo.ne.jp/qa/3144134.html
この中の4の回答者様と同じようにたぶん実態がないんだと思います。
そこでいろいろ試してみてこういうものを作ったのですが、こうするとprintfで変な値を指しています。たぶん環境によって変わると思いますが、自分の場合は./a.outを指していました。
この挙動はなぜ起こるのですか?また、このように別の関数で構造体を宣言して、その後、別の関数からポインタで参照する方法を教えてください。
お願いします。
#define DEBUG
#include<stdio.h>
#include<stdlib.h>
struct Sort{
int no;
char *name;
char *avg;
//char *maximax;
char *saiaku_saidai;
char *alias;
};
void sortinit(struct Sort *);
int main(void){
struct Sort *arr;
void *fes;
sortinit(arr);
//struct Sort *aa=(struct Sort *)fes;
printf("%s",arr->name);
return 0;
}
void sortinit(struct Sort *in){
struct Sort sortArr[]={
{
1,"バブルソート","nasi","n^2","基本交換法"
},{
2,"選択ソート","n^2","n^2","基本三法"
},{
3,"挿入ソート","n+d","n^2","基本三法"
},{
4,"シェルソート","nasi","nlog^2n",""
},{
5,"マージソート","nlogn","nlogn",""
},{
6,"ヒープソート","nlogn","nlogn",""
},{
7,"クイックソート","nlogn","n^2",""
},{
8,"ただの(偏った)二分木","n+1/2","n","線形探索法"
},{
9,"完全二分木","","",""
},{
10,"2分探索法","","",""
}
};
in=sortArr;
//struct Sort *in2=(struct Sort *)in;
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
いくつか問題点があります。
- まず、関数を抜けた後も参照したい配列は、
static
にするか関数の外側で定義してください。普通に関数内で宣言した変数(自動変数)は、関数を抜けた瞬間に無効となります(無理やりポインタで参照した場合、結果は未定義です)。 - C言語では引数はすべて値渡しなので、
sortinit(arr);
としてもmain
側のarr
は書き換わりません(未定義な値を使って関数を呼びだした段階で、動作は未定義です)。とりあえず動かしたいのであれば、上のと合わせてsortArr
をmain
より前に定義してしまうのが手っ取り早いです。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
printf("%s",arr->name); の arr は未初期化なので何処を指しているか不明で動作未定義です。
sortinit の中では引数で受け取っている in に代入していますが
この影響範囲は sortinit の中だけであり呼び出し元の main の arr には何の影響もありません。
arrの初期化という事が意図なら
sortinit(&arr);
もしくは
arr = sortinit();
のような構成にすべきですね。
もう1つの問題点は(今回の直接原因ではありませんが) sortinit の中で宣言された sortArr[]
を sortinit の外で参照しようとしている点です。(参照できてはいませんでしたが)
もしこのようにするのなら sortArr に static をつけるなど何かしらの対策が必要です。
「関数の中で宣言されたローカルなauto変数は原則的にスタック上に確保されその関数終了と共に消失する」ので関数終了後に仮に元々あったハズの場所が判明してそこにアクセスできたとしてもそこにその時点で何が入っているかは不明でありそんなアクセスはしてはいけません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.36%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/06/01 17:15 編集
確かにローカル変数だから消滅しますね。気づきませんでした。
sortArrをどうしても関数内部で初期化させたいのですが方法はないでしょうか。
2016/06/01 17:22 編集
~~void sortinit(struct Sort *in){でポインタ渡しをしているため書き換わる思ったのですが違うのでしょうか?~~
申し訳ないです。自分の認識ミスでした。
2016/06/01 17:34
配列だけ外で宣言しておいて、中身を入れる…ということを希望しているのでないのでしたら、mallocなどで動的に確保することとなります。
>ポインタ渡し
ポインタの「値」だけが渡っているので、ポインタが指す先は書き換えられてもポインタ自体は書き換えできません。引数経由でポインタ自体を書き換えるには「ポインタのポインタ」を渡して、ダブルポインタ経由で元のポインタを書き換える必要があります。
2016/06/01 18:30
お二人ともとても詳しく説明してくださってありがたいのですが先に回答してくださったのでこっちをBAとさせていただきます。