널 포인터 예외 발생


14

당신의 작업은 널 포인터 예외를 생성하는 것입니다. 즉, 프로그램은 널이 아닌 것으로 예상되는 값을 승인하고 값이 널이므로 예외 / 오류 또는 충돌을 발생시켜야합니다.

또한 값이 null이라는 코드를 읽는 것이 분명하지 않습니다. 목표는 실제로는 있지만 값이 null이 아니라는 것을 독자에게 명확하게 보이게하는 것입니다.

  • null 대신 nil, none, none 또는 해당 언어의 언어를 사용할 수 있습니다. undefined, uninitialized 등을 사용할 수도 있습니다.
  • 코드의 문제는 프로그램이 null이 아닌 변수를 기대하는 경우 변수가 (놀랍게도) null이라는 것입니다.
  • 프로그램은 예외를 던지거나, 오류를 던지거나, 충돌하거나 예기치 않은 널이 발생할 때 일반적으로 수행하는 모든 조치를 통해 널에 응답 할 수 있습니다.

이것은 인기 콘테스트이므로 영리하십시오!


@Ourous 당신은 무슨 뜻인지 보여줄 수 있습니까?
Ypnypn

그것을 살펴본 후, 그것은 당신이 찾고있는 것보다 더 많은 캐스트 오류입니다.
OUurous

컴파일러 버그를 사용할 수 있습니까?
Mark

1
@Mark 인기 콘테스트입니다. 커뮤니티가 결정하게하십시오. 나는 분명히 컴파일러 버그에 투표 할 것입니다.
11684

언더 핸드 컨테스트는 커뮤니티 컨센서스마다 주제가 다르기 때문에이 질문을 마무리합니다 .
Dennis

답변:


33

자바

숫자의 절대 값을 계산해 봅시다. 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는 정수를 취하지 않고 int (다른 숫자 유형에 대해 오버로드 된 메소드가 있음)를 가져오고 int를 반환합니다. Java에서 int는 기본 유형이며 null 일 수 없으며 Integer는 해당 클래스입니다 (null 일 수 있음). Java 버전 5부터는 int와 Integer 간의 변환이 필요할 때 자동으로 수행됩니다. 따라서 Math.abs는 x를 가져 와서 자동으로 int로 변환하여 int를 반환 할 수 있습니다.

이제 이상한 부분 : 삼항 연산자 (? :)가 두 가지 표현식을 처리해야 할 때 하나는 기본 유형을 가지고 다른 하나는 해당 클래스 (예 : int 및 Integer)를 가지며 Java는 기본을 변환 할 것으로 예상합니다 클래스 (일명 "박싱")로, 특히 필요한 유형 (여기서는 메소드에서 리턴하는 경우)이 참조 (클래스) 유형이고 첫 번째 표현식도 참조 유형 인 경우. 그러나 java는 정반대입니다. 참조 유형을 기본 유형 (일명 "unboxing")으로 변환합니다. 따라서 우리의 경우 x를 int로 변환하려고 시도하지만 int는 null 일 수 없으므로 NPE가 발생합니다.

Eclipse를 사용하여이 코드를 컴파일하면 실제로 "널 포인터 액세스 : Integer 유형의이 표현식은 널이지만 자동 언 박싱이 필요합니다"라는 경고가 표시됩니다.


/programming/7811608/java-npe-in-ternary-operator-with-autoboxing
/programming/12763983/nullpointerexception-through-auto-boxing-behavior-of-java 삼항 연산자



스포일러 x! = null 일 때 어떻게됩니까? (나는 이미 알아 냈습니다.)
11684 년

x가 null의 경우, 그것을 잘 작동하지 않는 경우 11684 @
SE 악이기 때문에 aditsu 종료

그런 다음 어떻게 작동하는지 모르겠습니다. x가 null이 아닌 경우 작동하고 왜 이것이 발생하는지에 대해 옳다면 콜론은 두 가지 의미로 구문 분석해야합니다 (언어 사양에 넣지 않을 것입니다).
11684

@ 11684 당신이 "두 감각"에 대해 무슨 뜻인지 모르겠지만 어쨌든 지금 설명을 추가했습니다
SE가 EVIL이기 때문에 아디 츠 종료

23

모든 C 프로그래머는 적어도 한 번은이 오류를 일으켰습니다.

#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실제로 널 포인터 리터럴이지만 변수에 저장하지 않고 직접 사용 된 리터럴 자체에만 적용됩니다. n널 포인터를 포함하지 않았습니다.
Konrad Borowski

또한이 기능을 수정하려면 scanf의 반환 값을 확인해야합니다.
David Grayson

1
@David 반환 값을 확인하지 않고 정확하지는 않지만 충돌하지 않거나 UB를 호출하지 않습니다. n은 0으로 유지됩니다. (이런 현상을 보려면 빈 파일을 stdin으로 리디렉션하십시오.)
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

루비

유닉스 클론의 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특별한 경우입니다. 루비에는라는 전역 메소드가 p있습니다. 따라서 p.find { ... }와 같은 메소드 호출이됩니다 p().find { ... }. 때 p인수가 없습니다, 그것은 반환합니다 nil. (코드 골퍼 pnil .) 그런 다음을 nil.find { ... }올립니다 NoMethodError.

파이썬으로 프로그램을 다시 작성하여 문제를 해결했습니다.

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

씨#

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.Stringstr.GetMethod() 때문에 예외가 발생 str == null합니다.

언어의 내부 특성에 대해 조금 알고있는 대부분의 사람들은 아마도 문제를 상당히 빨리 발견 할 수 있지만 여전히 한 눈에 쉽게 놓칠 수 있습니다.


대단한 것입니다 : D
Knerd

이것은 너무 분명하다. 이 같은 일을 두 가지 방법이기 때문에 독자는 즉시 단서를 얻을 수 .GetType()typeof()결과가 동일하지 않은 경우에 따라서 오류로 이어지는. 포스터가 방탄 코드를 원한다고 생각합니다.
ja72

왜이 확장 법에서 리플렉션이 사용됩니까? 명백한 코드는 return string.Format(format, args);입니다. 리플렉션이 필요한 경우 (다른 사용 사례에서) typeof(string)정적 GetType메서드가 아닌 (컴파일 타임에 케이싱 실수를 포착하고, 마법 문자열이 없음) 사용합니다. 따라서이 예는 "비현실적"인 것 같습니다.
Jeppe Stig Nielsen

4

Unity3D

public GameObject asset;

그런 다음 애셋을 끌어다 놓는 것을 잊어 버리고 Unity가 폭발합니다. 항상 일어난다.


3
잠깐, unity3d의 개발에는 마우스가 필요합니까?
Einacio

1
@Einacio 당신이 일을 더 쉽게 원한다면 그냥 자산을 변수로 드래그 앤 드롭 할 수 있습니다. 매우 편리합니다. 그러나 원하는 경우 코드없이 코딩 할 수 있습니다.
Fabricio

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

여기 두 가지가 있습니다. 하나는 ..범위 연산자를 포함 한다는 것 입니다. 그래서 0..x갖는 X + 1 개 요소 및 X를 포함한다. 이것은 배열의 범위를 초과한다는 것을 의미합니다. 다른 것은 루비에서이 작업을 수행 할 때 nil되돌릴 수 있다는 것입니다. 예를 들어 프로그램 이 버그 다음에except 10 줄 던질 때 이것은 매우 재미있다 .


이것은 너무 명백하다. for (int i = 0; i <= arr.length; i++)Java 에서하는 것과 같습니다 .
Cole Johnson

3

기계적 인조 인간

나는 이것이 너무 자주 일어나는 것을 본다. 사람은 다음 활동 (메시지 코드,지도 데이터 등)에 메시지를 전달하고Intent .

언뜻보기에는 꽤 합리적입니다. 다만:

  • 메시지가 널이 아닌지 확인하십시오
  • 의도에 넣다
  • 새로운 활동을 시작하다
  • 새로운 활동에 집중하다
  • 태그별로 메시지 추출

에서 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 개발에 익숙하지 않은 사람들 (예 : 나와 같은)이 그것을 이해할 수 없다는 것입니다.
John Dvorak

@JanDvorak 동의하지만 큰 문제는 없습니다. 이 사이트에는 내가 완전히 이해하지 못하는 다른 답변이 있습니다. :)
Geobits

3

프로그래머가 잠재적 인 위험을 문서화하기에 충분히 친절했던 버퍼에서 빠르게 읽습니다!

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으로 초기화 됨).


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전화에서는 성공합니다. 그러나 두 번째는 예외를 발생시키고 f2초기화되지 않은 상태로 둡니다 . 그런 다음 호출되어 오류가 발생합니다.


0

씨#

이것은 고전입니다. 매우 유용한 방법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형태에서 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

#define ONE 0 + 1

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

설명

전처리 실제로 계산하지 않기 0 + 1때문에, ONE문자로 정의되는 0 + 1결과 1 / 0 + 10으로 분할되는, 부동 소수점 예외 초래한다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.