[c] C 포인터를 NULL로 초기화 할 수 있습니까?

나는 다음과 같은 것을 쓰고 있었다

char *x=NULL;

가정에

 char *x=2;

char주소 2에 대한 포인터를 생성합니다 .

그러나 GNU C 프로그래밍 튜토리얼 에서는 할당 될 때 임의의 주소에 int *my_int_ptr = 2;정수 값 2을 저장 한다고 말합니다 my_int_ptr.

이것은 내 자신 char *x=NULLNULLa에 대한 캐스트 값이 char메모리의 임의의 주소에 할당 된다는 것을 의미하는 것 같습니다 .

동안

#include <stdlib.h>
#include <stdio.h>

int main()
{
    char *x=NULL;

    if (x==NULL)
        printf("is NULL\n");

    return EXIT_SUCCESS;
}

실제로 인쇄합니다.

NULL

컴파일하고 실행할 때 정의되지 않은 동작 또는 최소한 지정되지 않은 동작에 의존하고 있으며

char *x;
x=NULL;

대신.



답변

C 포인터를 NULL로 초기화 할 수 있습니까?

TL; DR 예, 대단히.


가이드 이루어 실제 특징은 같은 판독

반면에 단일 초기 할당 만 사용하는 경우 int *my_int_ptr = 2;프로그램은 가리키는 메모리 위치의 내용을 my_int_ptr값 2 로 채우려 고 시도 합니다. my_int_ptr가비지로 채워 지므로 모든 주소가 될 수 있습니다. […]

글쎄, 그들은 수 있습니다 당신이 옳다 잘못.

명령문의 경우 ( 지금은 정수 변환에 대한 포인터가 구현 정의 동작이라는 사실 무시 )

int * my_int_ptr = 2;

my_int_ptr변수는 (형 포인터의 것입니다 int(: 정수에 대한 포인터의 주소 형), 당신은의 값이 저장되어있다), 그것의 자신의 주소가 2 주소를.

이제 my_int_ptr포인터 유형이므로 다음을 가리킬 수 있습니다. 메모리 위치에서 “유형”의 값 에 의해 지적 되고있는 값 my_int_ptr. 따라서 기본적으로 포인터가 가리키는 메모리 위치의 값이 아니라 포인터 변수 의 값 할당합니다 .

그래서 결론을 위해

 char *x=NULL;

포인터 변수를 초기화합니다. x 가리키는 메모리 주소NULL값이 아닌 를로 .

이건 똑같아

 char *x;
 x = NULL;    

확장:

이제 엄격하게 준수하는 것은

 int * my_int_ptr = 2;

제약 위반을 포함하므로 불법입니다. 확실하게,

  • my_int_ptr 포인터 변수, 유형 int *
  • 정수 상수, 2유형 있음int 정의에 따라 .

“호환”유형이 아니므로이 초기화는 §6.5.16.1 / P1 장에 설명 된 단순 할당 규칙을 위반하므로 유효하지 않습니다. Lundin의 대답에 .

초기화가 간단한 할당 제약 조건에 어떻게 연결되는지 관심이있는 사람은 인용 C11, §6.7.9, P11 장

스칼라의 이니셜 라이저는 선택적으로 중괄호로 묶인 단일 표현식이어야합니다. 객체의 초기 값은 변환 후 표현식의 값입니다. 단순 할당과 동일한 유형 제약 및 변환이 적용되며 스칼라 유형을 선언 된 유형의 규정되지 않은 버전으로 취합니다.


답변

튜토리얼이 잘못되었습니다. ISO C에서는 int *my_int_ptr = 2;오류입니다. GNU C에서는 int *my_int_ptr = (int *)2;. 이것은 2컴파일러가 결정하는 방식으로 정수 를 메모리 주소 로 변환합니다 .

해당 주소 (있는 경우)로 주소가 지정된 위치에 아무것도 저장하지 않습니다. 계속해서을 쓰면 해당 주소로 주소가 지정된 위치에 *my_int_ptr = 5;번호를 저장하려고 5합니다.


답변

튜토리얼이 잘못된 이유를 명확히하기 위해 int *my_int_ptr = 2;“제약 조건 위반”인 것은 컴파일이 허용되지 않는 코드이며 컴파일러는이를 발견하면 진단을 제공해야합니다.

6.5.16.1에 따라 단순 할당 :

제약

다음 중 하나가 유지됩니다.

  • 왼쪽 피연산자는 원자, 규정 또는 규정되지 않은 산술 유형을 가지며 오른쪽 피연산자는 산술 유형을가집니다.
  • 왼쪽 피연산자는 오른쪽 유형과 호환되는 구조 또는 공용체 유형의 원자, 규정 또는 규정되지 않은 버전을 가지고 있습니다.
  • 왼쪽 피연산자는 원자, 정규화 또는 정규화되지 않은 포인터 유형을 가지며 (왼쪽 피연산자가 lvalue 변환 후 가질 유형을 고려할 때) 두 피연산자는 모두 호환되는 유형의 정규화되거나 정규화되지 않은 버전에 대한 포인터이며 왼쪽이 가리키는 유형은 모두 오른쪽으로 가리키는 유형의 한정자;
  • 왼쪽 피연산자는 원자, 정규화 또는 정규화되지 않은 포인터 유형을 가지며 (왼쪽 피연산자가 lvalue 변환 후 가질 유형을 고려할 때) 한 피연산자는 개체 유형에 대한 포인터이고 다른 피연산자는 정규화 된 또는 정규화되지 않은 버전에 대한 포인터입니다. void, 그리고 왼쪽이 가리키는 유형은 오른쪽이 가리키는 유형의 모든 한정자를가집니다.
  • 왼쪽 피연산자는 원 자성, 규정 된 또는 규정되지 않은 포인터이고 오른쪽은 널 포인터 상수입니다. 또는
  • 왼쪽 피연산자는 원자, 정규화 또는 정규화되지 않은 _Bool 유형을 가지며 오른쪽은 포인터입니다.

이 경우 왼쪽 피연산자는 규정되지 않은 포인터입니다. 오른쪽 피연산자가 정수 (산술 유형)가 될 수 있다는 내용은 어디에도 없습니다. 따라서 코드는 C 표준을 위반합니다.

GCC는 표준 C 컴파일러라고 명시 적으로 지정하지 않는 한 제대로 작동하지 않는 것으로 알려져 있습니다. 코드를으로 컴파일 -std=c11 -pedantic-errors하면 올바르게 진단을 제공합니다.


답변

int *my_int_ptr = 2

할당 될 때 my_int_ptr에있는 임의의 주소에 정수 값 2를 저장합니다.

이것은 완전히 잘못된 것입니다. 이것이 실제로 쓰여졌다면 더 나은 책이나 튜토리얼을 얻으십시오.

int *my_int_ptr = 2주소 2를 가리키는 정수 포인터를 정의합니다 2. 주소에 액세스하려고하면 충돌이 발생할 가능성이 큽니다 .

*my_int_ptr = 2int, 줄에가 없으면 임의의 주소 my_int_ptr가 가리키는 임의의 주소에 값 2를 저장합니다 . 이렇게 말하면 NULL포인터가 정의되면 할당 할 수 있습니다 . char *x=NULL;완벽하게 유효한 C입니다.

편집 : 이것을 작성하는 동안 정수에서 포인터로의 변환이 구현 정의 동작이라는 것을 몰랐습니다. 자세한 내용은 @MM 및 @SouravGhosh의 좋은 답변을 참조하십시오.


답변

C 포인터에 대한 많은 혼동은 원래 코딩 스타일과 관련하여 만들어진 매우 나쁜 선택에서 비롯되며 언어 구문에서 매우 나쁜 선택으로 입증되었습니다.

int *x = NULL;C는 맞지만, 그것은 매우 오해의 소지가 있고, 심지어 무의미하다고 말할 수도 있고, 많은 초심자에게 언어 이해를 방해했습니다. 그것은 *x = NULL;당연히 불가능한 일을 나중에 우리가 할 수 있다고 생각하게 만듭니다 . 당신은 변수의 유형이 아닌, 참조 int, 변수의 이름은하지 *x않으며, 수행 *선언에가와 공동으로 기능적 역할을한다 =. 순전히 선언적입니다. 따라서 훨씬 더 의미있는 것은 다음과 같습니다.

int* x = NULL;원래 K & R 코딩 스타일을 고수하지는 않지만 올바른 C입니다. 유형이 int*이고 포인터 변수 가라는 것을 완벽하게 명확하게 x하므로 값 NULL이에 x대한 포인터 인 에 저장되고 있음을 시작하지 않은 사람에게도 분명하게 알 수 int있습니다.

또한 규칙을 쉽게 유도 할 수 있습니다. 별이 변수 이름에서 멀어지면 선언이되고 이름에 붙은 별은 포인터 역 참조입니다.

그래서, 지금은 더 우리가 중 할 수있는 다운 것을 더 많이 이해하게 x = NULL;또는 *x = 2;그것을 쉽게 초보자 방법을 참조 할 수있게 즉 variable = expression에 리드를 pointer-type variable = pointer-expression하고 dereferenced-pointer-variable = expression. (시작된 경우 ‘표현식’은 ‘rvalue’를 의미합니다.)

언어 구문에서 불행한 선택은 지역 변수를 선언 할 때 int i, *p;정수와 정수에 대한 포인터를 선언하는 것을 말할 수 있으므로 *이름의 유용한 부분 이라고 믿을 수 있다는 것 입니다. 그러나 그렇지 않습니다.이 구문은 편의를 위해 추가 된 기발한 특수 사례 일뿐입니다. 제 생각에는 위에서 제안한 규칙을 무효화하기 때문에 존재하지 않았어야했습니다. 내가 아는 한, 언어의 다른 곳에서는이 구문이 의미가 없지만 그렇다고하더라도 C에서 포인터 유형이 정의되는 방식에 차이가 있음을 나타냅니다. 다른 모든 곳, 단일 변수 선언, 매개 변수 목록, 구조체 멤버 등에서 type* pointer-variable대신 포인터를 선언 할 수 있습니다 type *pointer-variable. 그것은 완벽하게 합법적이고 더 합리적입니다.


답변

많은 훌륭한 답변에 직교하는 것을 추가하고 싶습니다. 실제로로 초기화하는 NULL것은 나쁜 습관과는 거리가 멀고 포인터가 동적으로 할당 된 메모리 블록을 저장하는 데 사용되거나 사용되지 않는 경우 유용 할 수 있습니다.

int * p = NULL;
...
if (...) {
    p = (int*) malloc(...);
    ...
}
...
free(p);

받는 사람에 따라 이후 ISO-IEC 9899 표준 free 인수가 때 NOP입니다 NULL(같은 라인을 따라 더 의미 또는 무언가) 위의 코드는 합법적이다.


답변

이것은 널 포인터입니다

int * nullPtr = (void*) 0;