🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

Q&A

3回答

5131閲覧

nullとSegmentation fault

cihnatr8

総合スコア14

C

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

0グッド

0クリップ

投稿2018/03/20 09:34

編集2018/03/20 09:44

現在『詳説Cポインタ』を読んでおり、その途中で1つ疑問が出てきたので質問をします。
p.168にてEmployee構造体

C

1typedef struct _employee{ 2 char name[32]; 3 unsigned char age 4}Employee;

へのポインタemployeeを宣言し、リンクリストで作ったスタックから

C

1employee = (Employee*)pop(stack);

として、データを取り出しています。
popはstackが空の場合NULLを返します。
3つのEmployee型のデータをpushし、for文で4回上記の式を実行して

C

1printf(″Popped %s¥n″, employee->name);

とすると、
Popped 名前1
Popped 名前2
Popped 名前3
Popped (null)
となるのですが、下のようなプログラムを書くと(null)とはならずSegmentation fault(コアダンプ)になります。
何が違うんでしょう?

C

1int main(void) 2{ 3 Employee *employee = NULL; 4 printf(″employee : %s¥n″, employee->name); 5 return 0; 6}

また、下のプログラムは(nil)となります。
(nil)と(null)の違いも教えていただけるとありがたいです。

C

1int main(void) 2{ 3 int *p = NULL; 4 printf(%p¥n″, p); 5 6 return 0; 7}

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

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

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

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

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

guest

回答3

0

まず前提として、 NULL はポインタとして無効であるものとして定義されています。
ポインタが NULL であるとき、それが指す先へアクセスしてはいけません。
それは未定義の挙動だからです。
つまりこの場合は employeeNULL であるときに employee->name としたらそれだけで何が起こるかわからなくなります。

C で言う__未定義__というのは何が起こるか規定されていないということであり、何か出鱈目な値が返ってきても Segmentation fault になっても仕様通りということです。
前後の状況で何か条件が変わっているのだろうとしか言えません。

NULL が指している先へアクセスしようとするのが間違ったプログラムですので、言語仕様で規定してない状況について説明できないのです。

表示について、書式指定子 %p はポインタを表示するものですが、その表現は処理系定義です。
ポインタをどのような表現で表示するのか言語仕様では規定しておらず、処理系の裁量で決められます。
内部表現そのままの数値で表現してもかまいませんし、特別な文字列かもしれません。
NULL ポインタを表示するために nil という言葉を使うのも、あなたが使っている処理系ではそうなるというだけで、言語仕様で決まっているものではないので、それがどういう意図をもってそうなっているのかは言語仕様からはわかりません。
ひょっとすると処理系のドキュメントに書いていることがあるかもしれませんが、そうでなければ処理系の作者にしかわからないでしょう。

nil というのは C の仕様には無い用語です。
LISP などでは使われている用語ですが、意味としては NULL と同じようなものです。
言語仕様にないことなので、どうして使い分けをしているのかを強いて想像するのであれば、あくまでも私ひとりの想像ですけども、 %s のときは__ポインタが指している先にあるもの__を表示しようとするもので、 %p のときは__ポインタの値__を表示しようとしているというところで区別しているのではないかといったことが考えられます。

投稿2018/03/20 11:36

SaitoAtsushi

総合スコア5684

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

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

0

2番めだけ。
printf でNULLが来たら nil と出力している、というだけのはなしですねー

ぢつはNULLという名前もC言語的には決まった名前じゃないんですよねーw

投稿2018/03/20 09:51

y_waiwai

総合スコア88038

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

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

y_waiwai

2018/03/20 10:02

1番目の回答は前の質問を見てくださいねー
退会済みユーザー

退会済みユーザー

2018/03/20 13:52

NULLという名前はC言語の規格書に出てくるし、マクロは標準のヘッダにも含まれていますけれど、それでも言語として決まった名前じゃないんですか? (確かにマクロ定義の中身はただの0だったり(void*)0だったりで決まってないみたいですけれど)
y_waiwai

2018/03/20 13:56

string.h(だっけ?)をインクルードしてなければNULLは未定義となりますし、NULL以外の名前をつけてコードを構成することも可能です。そういうコードをC言語ではない、と言ってのけるのは簡単ですが、はてさて。。 まあ、こういうところのえーかげんさというのがC言語の魅力だと思っとります。
退会済みユーザー

退会済みユーザー

2018/03/20 14:04

NULLはstddef.h(あるいはその他)にあるそうですが。 なるほど、よく言う「Cは入出力(scanfだのprintfだの)を言語本体から切り離している」みたいなものですね。
y_waiwai

2018/03/20 14:20

マイコン上の実装となると、標準入出力はシリアルポートに出すのかUSBに出すのか液晶表示器にだすのか、となって、あえて実装しないことになってたりしますね。 このえーかげんな言語仕様と相まったメモリ効率の良さもあって、組み込み用途ではまだまだ現役ですねー
guest

0

当該書籍は読んでいないのですが。
ナルポインタにアクセスした場合、C言語では何が起こるかわかりません。
たまたま、質問者様のコンパイラでは、printf の %s に対応する文字列(文字へのポインタ)がナルポインタの場合 (null) と表示し、%p では (nil) と表示する親切設計だったのでしょう。これは別にC言語仕様で(あるいはprintf関数仕様で)そう決められてるわけではないです。
emploee->name はemploee と同じアドレスになるので、(null) が出たが、書き換えたら何らかの理由で親切機構が働かずに「ヌルポインタにアクセスした」という形になってセグメントフォールトになったのでしょうが、私にはその違いは分かりません。
ヌルポインタにアクセスしたら何が起こるか分からないので、何が起こっても文句は言えないということです。
ちなみに printf("%s",str) で、strが長さ0の文字列""の場合(strはナルポインタではないことに注意)は動作が決まってます。

投稿2018/12/25 08:55

編集2018/12/25 10:24
myoon

総合スコア100

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問