"int *nums = {5, 2, 1, 4}"이(가) 분할 장애를 일으킵니다.
int *nums = {5, 2, 1, 4};
printf("%d\n", nums[0]);
seg fault를 발생시키는 반면,
int nums[] = {5, 2, 1, 4};
printf("%d\n", nums[0]);
Doesn't.지금:
int *nums = {5, 2, 1, 4};
printf("%d\n", nums);
인쇄 5
이를 바탕으로 어레이 초기화 표기법 {}이(가) 이 데이터를 왼쪽 변수에 맹목적으로 로드하는 것으로 추측했습니다.int [ ] 의 경우 어레이는 원하는 대로 채워집니다.int*일 경우 포인터는 5로 채워지고 포인터가 저장되는 메모리 위치는 2, 1, 4로 채워집니다.따라서 nums [ 0 ]는 5를 참조 해제하려고 시도하여 seg fault를 발생시킵니다.
제가 틀렸다면 정정해 주세요.제 말이 맞다면 자세히 설명해 주세요.왜 어레이 이니셜라이저가 정상적으로 동작하는지 이해할 수 없기 때문입니다.
C에는 (stupid) 규칙이 있습니다.즉, 플레인 변수는 배열과 마찬가지로 괄호로 둘러싸인 이니셜라이저 리스트로 초기화할 수 있습니다.
를 들어, 이렇게 쓸 수 있어요.int x = {0};
int x = 0;
.
쓸 때int *nums = {5, 2, 1, 4};
실제로 단일 포인터 변수에 이니셜라이저 목록을 제공하고 있습니다. 1개의 첫 값 할당되고 컴파일러를 . 필요도 없습니다).메모리에 전혀 기입되지 않습니다.코드는 다음과 같습니다.int *nums = 5;
은 즉그말,, . . . .,nums
주소를 가리켜야 합니다. 5
.
이 시점에서 컴파일러 경고/오류가 2개 표시됩니다.
- 캐스트 없이 포인터에 정수를 할당하는 중입니다.
- 이니셜라이저 목록에 초과 요소가 있습니다.
이 버립니다.이때부터, 「는 크래시 되어 버립니다.5
는, 대부분의 가 아닌 것 같습니다.이 주소는, 「」를 사용해 해제할 수 .nums[0]
.
, ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.printf
및 """를 합니다.%p
정의되지 않은 동작을 호출하고 있습니다.
여기서 무엇을 하려고 하는지 잘 모르겠지만 어레이를 가리키도록 포인터를 설정하려면 다음 작업을 수행해야 합니다.
int nums[] = {5, 2, 1, 4};
int* ptr = nums;
// or equivalent:
int* ptr = (int[]){5, 2, 1, 4};
포인터의 배열을 작성하는 경우는, 다음과 같이 합니다.
int* ptr[] = { /* whatever makes sense here */ };
편집
몇 가지 조사를 통해 "초과 요소 이니셜라이저 목록"은 실제로 유효하지 않다고 말할 수 있습니다.그것은 GCC 확장입니다.
표준 6.7.9 초기화에는 다음과 같이 기재되어 있습니다(강조).
2 초기화자는 초기화 대상 기업 내에 포함되지 않은 객체에 대한 가치를 제공하려고 해서는 안 된다.
/--/
11 스칼라 이니셜라이저는 단일 표현식이어야 하며 선택적으로 괄호로 묶어야 한다.객체의 초기값은 식(변환 후)의 값입니다.단순한 할당과 같은 유형의 제약 및 변환이 적용되며 스칼라 유형이 선언된 유형의 미적용 버전이 됩니다.
"스칼라 유형"은 배열, 구조 또는 결합 유형이 아닌 단일 변수(이러한 변수를 "집약 유형"이라고 함)를 가리키는 표준 용어입니다.
따라서 표준 영어로는 "변수를 초기화할 때 이니셜라이저 식 주위에 추가 괄호를 자유롭게 삽입할 수 있습니다."라고 되어 있습니다.
시나리오 1
int *nums = {5, 2, 1, 4}; // <-- assign multiple values to a pointer variable printf("%d\n", nums[0]); // segfault
이 세그먼트(seg)가 고장나는 이유는 무엇입니까?
이 선언했어요.nums
int에 로서, int에 대한 nums
메모리내의 1개의 정수의 주소를 보관 유지하도록 되어 있습니다.
''를 했습니다.nums
여러 값의 배열로 이동합니다.따라서 세부사항을 자세히 조사하지 않으면 개념적으로 잘못된 것입니다. 하나의 값을 보유해야 하는 변수에 여러 값을 할당하는 것은 의미가 없습니다.이와 관련하여 다음과 같은 작업을 수행해도 동일한 효과를 얻을 수 있습니다.
int nums = {5, 2, 1, 4}; // <-- assign multiple values to an int variable
printf("%d\n", nums); // also print 5
변수에 ), 첫인 int int int >를 됩니다.5
아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아.될 때마다 됩니다.
warning: excess elements in scalar initializer
.
변수에 시합니다.nums[0]
즉, 주소 5에 저장되어 있는 것은 말 그대로 배변하는 것입니다.포인터에 유효한 메모리를 할당하지 않았습니다.nums
★★★★★★★★★★★★★★★★★★,
int 변수에 여러 값을 할당하는 경우(여기에서는 유효하지 않은 포인터를 참조하지 않음)에는 segfault가 없습니다.
시나리오 2
int nums[] = {5, 2, 1, 4};
스택에 4개의 int 배열을 합법적으로 할당하고 있기 때문에 세그먼트 폴트는 발생하지 않습니다.
시나리오 3
int *nums = {5, 2, 1, 4};
printf("%d\n", nums); // print 5
포인터 자체의 값을 인쇄하고 있기 때문에 예상대로 세그먼트 폴트는 발생하지 않습니다(비활성 메모리 액세스).
다른이들
이와 같은 포인터의 값을 하드코드 할 때마다 세그먼트 폴트가 발생합니다(어떤 프로세스가 어떤 메모리 위치에 액세스할 수 있는지를 결정하는 것은 운영체제 태스크이기 때문입니다).
int *nums = 5; // <-- segfault
따라서 다음과 같이 할당된 변수의 주소에 대한 포인터를 항상 초기화해야 합니다.
int a;
int *nums = &a;
또는,
int a[] = {5, 2, 1, 4};
int *nums = a;
int *nums = {5, 2, 1, 4};
형식이 올바르지 않은 코드입니다.이 코드를 다음과 같이 취급하는 GCC 확장이 있습니다.
int *nums = (int *)5;
메모리 주소 5에 대한 포인터를 형성하려고 합니다.(이 확장자는 유용하지 않지만 개발자 기반에서 원하는 것 같습니다.)
이 동작을 방지하려면(또는 최소한 경고를 수신하려면) 표준 모드로 컴파일할 수 있습니다.-std=c11 -pedantic
.
유효한 코드의 대체 형식은 다음과 같습니다.
int *nums = (int[]){5, 2, 1, 4};
같은 저장 기간의 가변 리터럴을 가리키고 있습니다.nums
.하지만, 그int nums[]
일반적으로 스토리지 사용량이 적기 때문에 더 나은 버전입니다.sizeof
어레이의 길이를 검출합니다.
int *nums = {5, 2, 1, 4};
nums
유형의 포인터입니다.int
따라서 이 포인트는 유효한 메모리 위치를 지정해야 합니다. num[0]
일부 랜덤 메모리 위치를 참조 해제하려고 하면 분할 결함이 발생합니다.
네, 포인터가 값 5를 유지하고 있으며 시스템에서 정의되지 않은 동작인 포인터를 참조 해제하려고 합니다.(외관상으로는5
시스템상의 유효한 메모리 위치가 아닙니다.)
반면에.
int nums[] = {1,2,3,4};
유효한 선언입니다.nums
는 타입의 배열입니다.int
메모리는 초기화 중에 전달된 요소의 수에 따라 할당됩니다.
할당에 의해{5, 2, 1, 4}
int *nums = {5, 2, 1, 4};
5를 할당하다nums
(암묵적인 타입캐스트 뒤에 int에서 포인터로 int로).참조 해제 시 메모리 위치에 대한 액세스콜이 발신됩니다.0x5
. 프로그램이 액세스할 수 없는 경우가 있습니다.
해라
printf("%p", (void *)nums);
언급URL : https://stackoverflow.com/questions/35266987/int-nums-5-2-1-4-causes-a-segmentation-fault
'programing' 카테고리의 다른 글
C/C++: 강제 비트 필드 순서 및 정렬 (0) | 2022.08.16 |
---|---|
스토어가 정의되어 있지 않습니다.vue.syslog (0) | 2022.08.16 |
v-show 및 v-if가 어레이가 아닌 개체의 부울 변경에 즉시 응답하는 이유는 무엇입니까? (0) | 2022.08.16 |
구조 내에서 구성원을 초기화할 수 없는 이유는 무엇입니까? (0) | 2022.08.16 |
null 끝 문자열의 근거는 무엇입니까? (0) | 2022.08.16 |