c - 활용 - 포인터 배열 문자열 비교



C에서 가변 길이 배열에 대한 포인터의 유형은 무엇입니까? (1)

다음은 사용자에게 숫자를 물어보고, 그 크기의 int의 가변 길이 배열을 만든 다음 포인터 산술을 사용하여 할당 된 요소를 단계별로 처리하는 간단한 C 프로그램입니다.

#include <stdio.h>

int main() {
    /* Read a size from the user; inhibits compiler optimizations. */
    int n;
    scanf("%d", &n); // Yes, I should error-check. :-)

    /* We now have a VLA. */
    int arr[n];

    /* What is the type of &arr? */
    void* ptr = (&arr) + 1;

    /* Seems like this skipped over things properly... */
    printf("%p\n", arr);
    printf("%p\n", ptr);
}

원한다면 이상적으로 시도 할 수 있습니다. 출력 결과에 따르면

void* ptr = (&arr) + 1;

arr 의 주소를 취해 크기를 인식하는 방식으로 가변 길이 배열의 모든 n 요소를 단계별로 처리합니다.

이것이 가변 길이 배열이 아니라면, 나는 이것이 어떻게 작동하는지에 대해 매우 편안 할 것입니다. 컴파일러는 arr 의 타입을 알고있을 것입니다 int (*) [K] 어떤 상수 K 대해 int (*) [K] 가 될 것입니다). 그래서 우리는 &arr 에 하나를 추가 할 때 올바른 바이트 수를 건너 뛸 수 있습니다.

런타임에서 우리가 (&arr) + 1 평가할 수 있었던 것은 명백합니다. 컴파일러는 스택의 어딘가에있는 arr 의 크기를 숨 깁니다. (&arr) 에 하나를 더하면 건너 뛸 바이트 수를 계산하기 위해 그 크기를로드하는 것을 알고 있습니다.

그러나 내가 모르는 것은 언어가 표현식의 유형이 무엇인지 말하고있는 것입니다. 가변 길이 배열 ( int (*) [??] 같은 것)을 나타내는 정적 유형이 할당 되었습니까? 스펙은 "표현식의 타입은 int (*) [K] . 여기서 K 는 런타임에 배열에 지정된 크기입니다." 스펙은 가변 길이 배열의 주소를 허용하지 않으며, 컴파일러는 단지 그것을 허용합니까?


VLA에서는 sizeof 연산자가 컴파일 타임 상수가 아닙니다. 그것은 런타임에 평가됩니다. 귀하의 질문에, &arr 의 유형은 int (*)[n]; - int 형의 n 값의 배열에의 포인터. n 는 실행시의 값. 따라서 &arr + 1 (괄호가 필요하지 않음을 알리는 괄호 안의 주석을 제외하고 괄호는 필요하지 않음)은 arr 다음에 배열의 시작입니다. 주소는 sizeof(arr) 의 값을 초과하는 sizeof(arr) 바이트입니다.

arr 의 크기를 인쇄 할 수 있습니다. 적절한 크기 ( printf() 수정 자 z )를 줄 것이다. 당신은 &arr + 1arr 사이의 차이점을 출력 할 수 있고 크기는 ptrdiff_t ( printf() 수정 자 t )로 얻을 수 있습니다.

금후:

#include <stdio.h>

int main(void)
{
    int n;
    if (scanf("%d", &n) == 1)
    {
        int arr[n];

        void* ptr = (&arr) + 1;

        printf("%p\n", arr);
        printf("%p\n", ptr);
        printf("Size: %zu\n", sizeof(arr));
        printf("Diff: %td\n", ptr - (void *)arr);
    }
    return 0;
}

두 번의 샘플 실행 (프로그램 이름 vla59 ) :

$ vla59
23
0x7ffee8106410
0x7ffee810646c
Size: 92
Diff: 92
$ vla59
16
0x7ffeeace7420
0x7ffeeace7460
Size: 64
Diff: 64
$

재 컴파일은 필요 없지만 sizeof() 는 프로그램을 실행할 때마다 정확합니다. 그것은 런타임에 계산됩니다.

실제로 매번 다른 크기의 루프를 사용할 수도 있습니다.

#include <stdio.h>

int main(void)
{
    int n;
    while (printf("Size: ") > 0 && scanf("%d", &n) == 1  && n > 0)
    {
        int arr[n];

        void* ptr = (&arr) + 1;

        printf("Base: %p\n", arr);
        printf("Next: %p\n", ptr);
        printf("Size: %zu\n", sizeof(arr));
        printf("Diff: %td\n", ptr - (void *)arr);
    }
    return 0;
}

vla11 샘플 실행 :

$ vla11
Size: 23
Base: 0x7ffee3e55410
Next: 0x7ffee3e5546c
Size: 92
Diff: 92
Size: 16
Base: 0x7ffee3e55420
Next: 0x7ffee3e55460
Size: 64
Diff: 64
Size: 2234
Base: 0x7ffee3e53180
Next: 0x7ffee3e55468
Size: 8936
Diff: 8936
Size: -1
$




variable-length-array