NULLポインター例外をスロー[クローズ]


14

あなたの仕事は、null-pointer例外を生成することです。つまり、プログラムはnull以外の値を受け取る必要があり、値がnullであるため例外/エラーまたはクラッシュをスローする必要があります。

さらに、コードを読んでも値がnullであることは明らかではありません。あなたの目標は、実際には値がnullでないことを読者に明らかにすることです。

  • nullの代わりに、nil、none、nothing、またはあなたの言語で同等のものを使用できます。未定義、未初期化などを使用することもできます。
  • コードの問題は、プログラムがnull以外の変数を予期している場合、変数が(驚くほど)nullである必要があります。
  • プログラムは、例外をスローしたり、エラーをスローしたり、クラッシュしたり、予期しないnullに遭遇したときに通常行うことによって、nullに応答できます。

これは人気コンテストですので、気をつけてください!


@Ourousあなたの言いたいことを示すために例を挙げていただけますか?
Ypnypn

それを見た後、それはあなたが探しているものよりもキャストエラーです。
14年

コンパイラのバグを使用できますか?
マーク

1
@Markこれは人気コンテストです。コミュニティに決定させてください。私は間違いなくコンパイラのバグに投票します。
11684

回答:


33

Java

数値の絶対値を計算しましょう。Javaにはこの目的のためのMath.absがありますが、使用している数値はnullになる場合があります。そのため、この場合に対処するヘルパーメソッドが必要です。

public class NPE {
    public static Integer abs(final Integer x) {
        return x == null ? x : Math.abs(x);
    }

    public static void main(final String... args) {
        System.out.println(abs(null));
    }
}

xがnullの場合はnullを返し、そうでない場合はMath.abs()を使用します。
コードは非常にシンプルで明確であり、正常に動作するはずです...

ところで、代わりに次の行を使用します。

return x == null ? null : Math.abs(x);

正常に動作します。私はこれをネタバレにすることを考えたが、..私はそれがちょうど不可解だと思う:)

わかりました、説明:

まず、Math.absはIntegerではなくint(他の数値型のオーバーロードメソッドもあります)を受け取り、intを返します。Javaでは、intはプリミティブ型であり(nullにはできません)、Integerは対応するクラスです(nullにできます)。Javaバージョン5以降、intとIntegerの間の変換は必要なときに自動的に実行されます。そのため、Math.absはxを取り、自動的にintに変換し、intを返すことができます。

奇妙な部分:三項演算子(?:)が2つの式を処理し、一方がプリミティブ型でもう一方が対応するクラス(intやIntegerなど)である場合、javaがプリミティブを変換すると予想されるクラス(別名「ボクシング」)、特に必要な型(ここではメソッドから戻るため)が参照(クラス)型であり、最初の式も参照型である場合。しかし、javaはまったく逆のことを行います。つまり、参照型をプリミティブ型に変換します(別名「ボックス化解除」)。したがって、この場合、xをintに変換しようとしますが、intをnullにすることはできないため、NPEがスローされます。

Eclipseを使用してこのコードをコンパイルすると、実際には次の警告が表示されます。「ヌルポインターアクセス:整数型のこの式はnullですが、自動ボックス化解除が必要です」


/programming/7811608/java-npe-in​​-ternary-operator-with-autoboxing
/programming/12763983/nullpointerexception-through-auto-boxing-behavior-of-java -三項演算子



スポイラーx!= nullの場合はどうなりますか?(私はすでにそれを理解しました。)
11684

11684 @ xがnullでないとき、それは正常に動作します
aditsu

それから私はこれがどのように機能するかわからないと思います。xがnullでないときに機能し、これがスローされる理由が正しい場合、コロンは2つの意味で解析する必要があります(言語仕様には入れません)。
11684

@ 11684「2感覚」についてあなたが何を意味するのかわかりませんが、とにかく私は今説明を追加しました
aditsu

23

C

すべてのCプログラマーがこのエラーを少なくとも1回行いました。

#include <stdio.h>

int main(void) {
    int n=0;
    printf("Type a number : ");
    scanf("%d",n);
    printf("Next number is : %d",n+1);
    return 0;
}

理由:

scanfint *引数にポインター()を取ります。ここ0に渡されます(NULLポインター)

修正:

scanf("%d",&n);

http://ideone.com/MbQhMM


1
それは正確にはそうではありません。scanfは可変個の関数でありint、予期しint *たときに不正な型の引数()が指定されました。C(私は知っている、コンパイラはの場合にこれを検出scanfできる)は可変個の関数の型をチェックできないため、これは喜んでコンパイルします。0確かにNULLポインターリテラルですが、これは変数に格納せずに、直接使用されるリテラル自体にのみ適用されます。nnullポインターが含まれることはありません。
コンラッドボロウスキ

この関数を修正するには、scanfの戻り値も確認する必要があります。
デビッドグレイソン

1
nが0のままになります(標準入力として空のファイルをリダイレクトしてみてください、これが起こるを参照するには。) -それは、戻り値をチェックせずに正しくないのですが、それはUBをクラッシュしたり呼び出しません@デビッド
Riking

14

PHP

これは私に数回噛みつきました。

<?php

class Foo {
  private $bar;

  function init() {
    $this->bar = new Bar();
  }

  function foo() {
    $this->bar->display_greeting(); // Line 11
  }
}

class Bar {
  function display_greeting() {
    echo "Hello, World!";
  }
}

$foo_instance = new Foo();
$foo_instance->init();
$foo_instance->foo();

期待される結果:

Hello, World!

実結果:

Fatal error: Call to a member function display_greeting() on a non-object on line 11

別名NullPointerException

理由:

デフォルトでは、コンストラクター構文はPHP 4.xと下位互換性fooがあるため、関数はクラスの有効なコンストラクターであるためFoo、デフォルトの空のコンストラクターをオーバーライドします。この種のエラーは、プロジェクトに名前空間を追加することで回避できます。


9

CoffeeScript(Node.js上)

CoffeeScriptでは、?存在演算子です。変数が存在する場合はそれが使用され、そうでない場合は右側が使用されます。私たちは皆、移植可能なプログラムを書くのが難しいことを知っています。適切な場合、JavaScriptでの印刷は指定されていません。ブラウザはalert(またはdocument.write)を使用し、SpiderMonkeyシェルはを使用しprint、Node.jsはを使用しconsole.logます。これはクレイジーですが、CoffeeScriptはこの問題を解決します。

# Portable printer of "Hello, world!" for CoffeeScript

printingFunction = alert ? print ? console.log
printingFunction "Hello, world!"

Node.jsでこれを実行しましょう。結局、スクリプトが機能することを確認したいのです。

ReferenceError: print is not defined
  at Object.<anonymous> (printer.coffee:3:1)
  at Object.<anonymous> (printer.coffee:3:1)
  at Module._compile (module.js:456:26)

うーん、なぜそれも文句を言われないのに文句を言うのalert

なんらかの理由で、CoffeeScriptでは、?左側が未定義の変数のみを無視することを意味する連想性が残っています。明らかに、一部の開発者が依存している可能性があるため、修正されていません。連想的になります。


8

ルビー

UnixクローンのPATHでawkを見つけます。

p = ENV['PATH'].split ':'

# Find an executable in PATH.
def find_exec(name)
  p.find {|d| File.executable? File.join(d, name)}
end

printf "%s is %s\n", 'awk', find_exec('awk')

おっとっと!

$ ruby21 find-awk.rb
find-awk.rb:5:in `find_exec': undefined method `find' for nil:NilClass (NoMethodError)
        from find-awk.rb:8:in `<main>'

エラーから、がp.find呼び出されたことがわかっているnil.findため、であるp必要がありますnil。どうしてそうなった?

Rubyでは、defローカル変数に独自のスコープがあり、外部スコープからローカル変数を取得することはありません。したがって、割り当てp = ENV['PATH'].split ':'はスコープ内にありません。

未定義の変数は、通常は発生しNameErrorますが、p特殊なケースです。Rubyにはという名前のグローバルメソッドがありpます。のp.find { ... }ように、メソッド呼び出しになりp().find { ... }ます。ときにp引数がない、それが返されますnil。(コードゴルファーはp、のショートカットとして使用しnilます。)その後、nil.find { ... }レイズしNoMethodErrorます。

Pythonでプログラムを書き換えて修正します。

import os
import os.path

p = os.environ['PATH'].split(':')

def find_exec(name):
    """Find an executable in PATH."""
    for d in p:
        if os.access(os.path.join(d, name), os.X_OK,
                     effective_ids=True):
            return d
    return None

print("%s is %s" % ('awk', find_exec('awk')))

できます!

$ python3.3 find-awk.py 
awk is /usr/bin

おそらく印刷したいのですawk is /usr/bin/awkが、それは別のバグです。


7

C#

With()は、stringオブジェクトの拡張メソッドですstring.Format()。これは本質的にの単なるエイリアスです。

using System;

namespace CodeGolf
{
    internal static class Program
    {
        private static void Main()
        {
            Console.WriteLine( "Hello, {0}!".With( "World" ) );
        }

        private static string With( this string format, params object[] args )
        {
            Type str = Type.GetType( "System.string" );
            MethodInfo fmt = str.GetMethod( "Format", new[] { typeof( string ), typeof( object[] ) } );

            return fmt.Invoke( null, new object[] { format, args } ) as string;
        }
    }
}

よさそうですね?違う。

Type.GetType()完全修飾の大文字と小文字を区別するタイプ名が必要です。問題はSystem.string存在しないことです。stringは、実際の型の単なるエイリアスですSystem.String。動作するはずですがstr.GetMethod()、のために例外をスローしますstr == null

言語の内部仕様について少し知っているほとんどの人は、おそらく問題をかなり迅速に見つけることができますが、それでも一目で簡単に見落とされるものです。


D:それは素晴らしいものです
Knerd

これは少し明白すぎる。そこに同じことを行うには、2つの方法があるので、読者はすぐに手掛かりを取得.GetType()してtypeof()、結果が同じでない場合ので、故障につながります。ポスターには防弾のようなコードが必要でしたが、そうではありません。
ja72

この拡張メソッドで反射が使用されるのはなぜですか?明らかなコードはreturn string.Format(format, args);です。(別のユースケースで)リフレクションが必要な場合typeof(string)は、静的GetTypeメソッドではなく(コンパイル時に大文字小文字の間違いをキャッチし、マジックストリングを使用しない)使用します。したがって、例は「非現実的」に見えます。
ジェッペスティグニールセン14年

4

Unity3D

public GameObject asset;

次に、そこにアセットをドラッグアンドドロップするのを忘れると、BOOM、Unityが爆発します。常に起こります。


3
unity3dの開発にはマウスが必要ですか?
アイナシオ

1
@Einacio物事をもっと簡単にしたい場合は、アセットを変数にドラッグアンドドロップするだけです。とても便利な。ただし、必要な場合は、それなしでコーディングできます。
ファブリシオ

4

ルビー

配列の積を取るための簡単なコード。

number_array = [2,3,9,17,8,11,14]
product = 1
for i in 0..number_array.length do
  product *= number_array[i]
end
puts product

ここに二つのこと。1つは、..範囲演算子が包括的であることです。だから、0..x持っているのx + 1つの要素を、そしてxが含まれています。これは、配列の境界を超えることを意味します。もう1つのことは、Rubyでこれを行うと、それは単にあなたにnil恩返しをすることです。たとえば、プログラムがバグの後にexcept 10行をスローした場合、これは非常に楽しいです。


これはあまりにも明白です。for (int i = 0; i <= arr.length; i++)Javaで行うようなものです。
コールジョンソン

3

アンドロイド

これは頻繁に起こります。人はメッセージを次のアクティビティ(ステータスコード、マップデータなど)に渡し、最終的にからnullを取得しますIntent

一見、それはかなり合理的なようです。ただ:

  • メッセージがnullでないことを確認してください
  • インテントに詰める
  • 新しい活動を始める
  • 新しいアクティビティに興味を持ちます
  • タグでメッセージを抽出する

MenuActivity.java

private void startNextActivity(String message){
    // don't pass a null!
    if(message == null)                        
        message = "not null";        

    // put message in bundle with tag "message"
    Bundle msgBundle = new Bundle();
    msgBundle.putString("message", message);   

    // pack it into a new intent
    Intent intent = new Intent(this, NextActivity.class);
    intent.putExtras(msgBundle);               
    startActivity(intent);
}

NextActivity.java

private void handleMessage(){
    // get Intent
    Intent received = getIntent();
    if(received == null){
        Log.d("myAppTag","no intent? how does this even happen?");
        finish();
    }
    // get String with tag "message" we added in other activity
    String message = received.getStringExtra("message");
    if(message.length() > 10){
        Log.d("myAppTag", "my message is too long! abort!");
        finish();
    }
    // handle message here, etc
    // ...
    // too bad we never GET here!
}

FWIW、JavaDoc それIntent.getStringExtra(String)がを返すかもしれないと言ってますがnull、タグが見つからなかった場合のみです。明らかに私は同じタグを使用しているので、それは何か他のものでなければなりません...


2
この答えの問題は、Androidの開発に慣れていない人(私のような)がAndroidの開発に感謝できないことです。
ジョンドヴォルザーク

@JanDvorak同意しましたが、大したことはありません。このサイトには、私が十分に評価していない他の回答もあります。:)
ジオビット

3

C

潜在的な危険性を文書化するのに十分なほど親切なプログラマーさえいるバッファからの簡単な読み取りです!

char* buffer;
int main( void )
{
    ///!!WARNING: User name MUST NOT exceed 1024 characters!!\\\
    buffer = (char*) malloc( 1024 );
    printf("Please Input Your Name:");
    scanf("%s", buffer);
}

悪意のあるコードを予期している場合、非常にシンプルで明らかなトリック。'\'で終わるコメントは改行をエスケープするため、バッファにメモリが割り当てられることはありません。バッファがNULLになるため、scanfは失敗します(Cでファイルスコープ変数がゼロに初期化されるため)。


0

ニムロッド

type TProc = proc (a, b: int): int

proc func1(a, b: int): int=a+b
proc func2(a, b: int): int=a-b

proc make_func(arg: int, target: var TProc)=
  if arg == 1:
    target = func1
  elif arg == 2:
    target = func2
  else:
    raise newException(EIO, "abc")

var f, f2: TProc

try:
  make_func(2, f)
  make_func(3, f2)
except EIO:
  discard

echo f(1, 2)
echo f2(3, 4)

ここで何が起こっているかは少し複雑です。Nimrodでは、プロシージャはデフォルトでに初期化されnilます。最初のmake_func呼び出しで成功します。ただし、2番目は例外をスローし、f2初期化されないままにします。次に呼び出され、エラーが発生します。


0

C#

これは古典的です。非常に有用な方法はFindStringRepresentationOf、その後、指定された型パラメータの新しいインスタンスを作成し、そのインスタンスの文字列表現を見つけるでしょう。

確かにnull、新しいインスタンスを作成した直後に確認するのはもったいないので、私はそれをしていません...

static void Main()
{
  FindStringRepresentationOf<DateTime>();  // OK, "01/01/0001 00:00:00" or similar
  FindStringRepresentationOf<DateTime?>(); // Bang!
}

static string FindStringRepresentationOf<TNewable>() where TNewable : new()
{
  object goodInstance = new TNewable();
  return goodInstance.ToString();
}

変更objectにローカル変数の宣言でTNewable またはにvar(C#3以降)問題が離れて行くことができます。ヒント:(Nullable<T>別名T?)の ボクシングは.NET Frameworkで異常です。

上記の非表示のテキストで説明されているように問題を修正した後、試してくださいgoodInstance.GetType()GetType()違いはToString()、とは異なり、仮想ではないoverrideため、type Nullable<>ではできませんでした)。


0

C ++:

#include <iostream>
#include <cstring>
#include <vector>
#include <conio.h>
#include <string>

using namespace std;

class A
{
public:
    string string1;
    A()
    {
        string1 = "Hello World!";
    }
};
A *a_ptr;

void init()
{
    A a1;
    a_ptr = &a1;
}

int main()
{
    init();
    cout<<a_ptr->string1;
    _getch();
    return 0;
}

あなたが期待するのは「Hello World!」です。印刷されます。ただし、画面にはゴミのみが表示されます。

ここでは、スコープinit()が終了するとa1が破棄されます。したがって、a_ptrは、a1を指しているため、ゴミを生成します。


0

C

#define ONE 0 + 1

int main(void) {
    printf("1 / 1 = %d\n", 1 / ONE);
    return 0;
}

説明

プリプロセッサは実際に計算しない0 + 1のでONE、文字通りとして定義され0 + 1、結果として、1 / 0 + 1ゼロによる除算であり、浮動小数点例外が発生します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.