- PR -

C言語入門者:自作ライブラリの呼び出しでSegmentation fault

投稿者投稿内容
うーたん
常連さん
会議室デビュー日: 2008/09/16
投稿数: 34
投稿日時: 2009-02-19 17:01
いつも参考にさせていただいてます。

C言語入門者のうーたんと申します。
今回、会社からの指示により簡単なC言語プログラムを作ることになりました。
そこで、まずは簡単な自作ライブラリとその中の関数を呼び出すプログラムを
作り実行したところ、どうしてもSegmentation faultが発生してしまいます。
入門者ゆえの馬鹿なコーディングをしていると思いますが、
何が原因か分かりません。
どなたかご教授お願いいたします。
ちなみに、subpg.cの引数の受渡方法は決まりにより変更できません。
あと、環境はUbuntu Linux 8.04です。

◆ソースは以下の通りです。
[ subpg.c ]---------------------------------------
#include <stdio.h>

void subpg(ret)
int *ret;
{
*ret = -1; /* とりあえず必ず-1を返す */
return;
}
-------------------------------------------------

[mainpg.c]---------------------------------------
#include <stdio.h>

void main(void) {
int *ret;
subpg(ret); /* subpgを実行 */
printf("ret:%d\n", *ret); /* subpgからのリターンコードを表示 */
}
-------------------------------------------------

◆コンパイル手順は以下の通りです。
$ gcc -shared -fPIC -o libtest.so subpg.c
$ gcc ./libtest.so -o mainpg mainpg.c

◆実行方法は以下の通りです。
$ ./mainpg
Segmentation fault

どうか、宜しくお願いいたします。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2009-02-19 17:30
main()でretを初期化していないからです。retが不定なところ指しているので、*retをアクセスすると高い確率で segmentation fault になります。

うーたん
常連さん
会議室デビュー日: 2008/09/16
投稿数: 34
投稿日時: 2009-02-19 17:58
スフレさん
回答ありがとうございます。
早速試してみました。

main()のretを初期化ということで
int *ret = 0;
としてみましたが結果が同じであったため、
ポインタの初期化について調べてみました・・・。

int n = 0;
int *ret = &n;
としたところ、うまくいきました。
有難うございました!!!
(この方法で正しいですか?)

また何かありましたら宜しくお願いいたします。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2009-02-19 19:07
引用:

int n = 0;
int *ret = &n;
としたところ、うまくいきました。
有難うございました!!!
(この方法で正しいですか?)



はい、それで大丈夫です。
ポインタを0で初期化すると「無効なポインタ」を表すので、やはり *ret にアクセスするとダメですね。

コンパイルするときに「gcc -Wall -O2 …」とオプションを付けることをおすすめします。retが未初期化の件もこれで警告が出るはずです。
加納正和
ぬし
会議室デビュー日: 2004/01/28
投稿数: 332
お住まい・勤務地: 首都圏
投稿日時: 2009-02-19 23:51
引用:

うーたんさんの書き込み (2009-02-19 17:01) より:

何が原因か分かりません。

◆ソースは以下の通りです。
[ subpg.c ]---------------------------------------
#include <stdio.h>

void subpg(ret)
int *ret;
{
*ret = -1; /* とりあえず必ず-1を返す */
return;
}



いわゆる「ポインタ問題」というやつですね。
ポインタという概念は理解できたでしょうか。

初期化も必要です。が、この場合はsubpg()関数の引数が
ポインタ変数です。

「ポインタ変数」とは「ポインタ」が入る変数です。

ポインタ変数の中身(ポインタ先ともいう)をアクセスする場合、
絶対に実体をあらわすメモリが必要です。
上記だとポインタ変数である「ret」の
中身の「*ret」にアクセスしようとして実体が存在しないので
segmentaion faultしました。

引用:

int n = 0;
int *ret = &n;



とやると実体はint 「n」 の32bit分が実体です。
「ポインタ変数 ret」は、「n」を「指している」変数。
「ポインタ変数の実体 *ret」は「n」と同じ。
*retを変えると「n」も変わる。

ここらへんはたくさんの入門書が出ているので
どれかの入門書をとりあえず信じて、その入門書の考え方で
理解するのをお勧めします。

一回理解してしまえばどれでも言ってることは同じなのがわかりますので。
うーたん
常連さん
会議室デビュー日: 2008/09/16
投稿数: 34
投稿日時: 2009-02-20 09:33
スフレさん

ご助言、有難うございます。
コンパイルオプション -Wall(警告オプション)と、-O2(最適化オプション)を付けて
$ gcc -Wall -O2 ./libtest.so -o mainpg mainpg.c
で訂正前のmainpg.cをコンパイルしたところ、
以下の警告が出ました。

警告: ‘ret’ is used uninitialized in this function (‘ret’は、初期化されずに使われています )

今後、このオプションを付けてコンパイルするようにいたします。
今回は本当に有難うございました。
うーたん
常連さん
会議室デビュー日: 2008/09/16
投稿数: 34
投稿日時: 2009-02-20 09:43
加納正和さん

入門者にとってありがたいご助言有難うございます。
ポインタは何とかクリアできた気がします。
今後いろいろな問題にぶつかると思いますが、
なんとか頑張ります。

また何かありましたら宜しくお願いいたします。
あんとれ
ぬし
会議室デビュー日: 2004/01/14
投稿数: 556
投稿日時: 2009-02-20 12:42
普通に書くとこんな感じでしょうか。

コード:
#include <stdio.h>

int
main ()
{
 int n;
 subpg (&n); /* subpgを実行 */
 printf ("ret:%d\n", n); /* subpgからのリターンコードを表示 */
  return 0;
}



もしくは、

コード:
#include <stdio.h>

int
main ()
{
 int *ret = (int *)malloc (sizeof (int));
 subpg (ret); /* subpgを実行 */
 printf ("ret:%d\n", *ret); /* subpgからのリターンコードを表示 */
  free (ret);
  return 0;
} 


スキルアップ/キャリアアップ(JOB@IT)