2016-10-16 2 views
1

저는 C 프로그래밍을 처음 접했고 튜토리얼을 일부 진행할 것입니다. 나를 곤란하게 한 가지는 배열에 대한 포인터를 반환하는 것입니다. 나는 요점을 설명하기 위해 https://www.tutorialspoint.com/cprogramming/c_return_arrays_from_function.htm에서 예제를 잘라 냈다.함수에서 배열 반환하기 (C)

#include <stdio.h> 

int * getRandom() { 

    static int r[10]; 
    int i; 

    for (i = 0; i < 10; ++i) { 
     r[i] = i; 
     printf("r[%d] = %d\n", i, r[i]); 
    } 
    return r; 
} 

int main() { 
    int *p; 
    int i; 
    p = getRandom(); 
    for (i = 0; i < 10; i++) { 
     printf("*(p + %d) : %d\n", i, *(p + i)); 
    } 
    return 0; 
} 

사람이 기대하는 것처럼,이

r[0] = 0 
r[1] = 1 
r[2] = 2 
r[3] = 3 
r[4] = 4 
r[5] = 5 
r[6] = 6 
r[7] = 7 
r[8] = 8 
r[9] = 9 
*(p + 0) : 0 
*(p + 1) : 1 
*(p + 2) : 2 
*(p + 3) : 3 
*(p + 4) : 4 
*(p + 5) : 5 
*(p + 6) : 6 
*(p + 7) : 7 
*(p + 8) : 8 
*(p + 9) : 9 

를 인쇄하지만이 변경 될 때

static int r[10]; 

에는
int r[10]; 

대신

를 인쇄
r[0] = 0 
r[1] = 1 
r[2] = 2 
r[3] = 3 
r[4] = 4 
r[5] = 5 
r[6] = 6 
r[7] = 7 
r[8] = 8 
r[9] = 9 
*(p + 0) : 0 
*(p + 1) : 1980517315 
*(p + 2) : -1164399724 
*(p + 3) : 4199040 
*(p + 4) : 4199040 
*(p + 5) : 2285568 
*(p + 6) : 19 
*(p + 7) : 6356668 
*(p + 8) : 8 
*(p + 9) : 6356940 

나는 이유를 모르겠다. 필자가 생각할 수있는 유일한 이유는 컴파일러가 배열 셀을 다른 데이터 유형으로 읽는 것이지만 그게 옳은 것인지 의심 스럽습니다.

+1

컴파일러 경고를 읽으십시오 :'임시 참조 반환 '이 좋지 않습니다. 즉, 값은 언제든지 덮어 쓰게됩니다 (따라서 정적 키워드). 이 중복을 찾을 수 없습니다. –

+0

모든 답변 주셔서 감사합니다; 나는 이것을 지금 이해하고 있다고 생각한다. 근본적으로 일단 getRandom 함수를 떠나면 나머지 배열에 사용 된 메모리가 다시 할당되지만 함수 출력에 스택 메모리를 할당하는 'malloc()'을 사용하지 않아도됩니다. – Dant

답변

1

static 키워드는 다음 호출에서 r의 값을 "기억"하는 데 사용됩니다. 이를 제거하면 함수가 반환 될 때 r에 할당 된 메모리가 플러시되어 가비지를 반환합니다.

1

static int r[10];이 있으면 배열을 저장할 메모리가 컴파일 타임에 할당되고 모든 것이 예상대로 작동합니다.

대신 int r[10]이있는 경우 런타임 스택 프레임에 배열을 할당합니다. 런타임 스택 프레임은 함수 호출이 반환 될 때 유효하지 않게되고 다음 함수 호출로 덮어 쓰므로 가비지를 봅니다.

0

정적 배열 선언없이 getRandom()을 호출하면 getRandom() 함수가 반환되면 배열이 범위를 벗어납니다. 이것은 r이 본질적으로 버려지므로 포인터가 더 이상 r을 가리 키지 않는다는 것을 의미합니다.

제대로 getRandom()에서 반환하기 위해, 동적, 예를 들어, malloc를 사용하여 메모리를 할당해야합니다 : 우리는 우리가 할당 된 메모리를 free 얼마나

int * getRandom() { 
    int *r = NULL; 
    r = malloc(sizeof(int) * 10); /* Create room for 10 integers*/ 
    if (r == NULL) { 
    printf("Error: Could not allocate space\n"); 
    return NULL; 
    } 
    int i; 
    for (i = 0; i < 10; ++i) { 
    r[i] = i; 
    printf("r[%d] = %d\n", i, r[i]); 
    } 
    return r; /* Returns a pointer to r*/ 
} 

int main() { 
    int *p; 
    int i; 
    p = getRandom(); 
    if (p == NULL) { 
    /*Error state*/ 
    return 1; 
    } 
    for (i = 0; i < 10; i++) { 
    printf("*(p + %d) : %d\n", i, *(p + i)); 
    } 
    free(p); /* Free the memory we allocated*/ 
    return 0; 
} 

주 (그렇지 않으면 우리는 메모리 누수를 할 것이다) . 또한 우리는 필요한 메모리를 할당 할 수없는 NULL 사례를 처리해야합니다.

0

일부 경우를 제외하면 식의 배열은 항상 첫 번째 요소의 주소로 감소합니다.
이 포인터는 함수가 반환하는 값입니다.
일반적으로 메모리에있는 객체 인 배열 자체는 함수 실행이 끝난 후에 죽습니다.
그래서 함수가 반환 한 포인터가 가리키는 메모리 주소가 배열을 보존 할 수 있다고 보장되지 않으며 대신 가비지가있을 수 있습니다.
static 선언은 배열 객체를 유지하지만 함수가 배열 자체가 아닌 배열의 헤드에 대한 포인터를 반환했습니다.
함수의 내부 사용자에 대한 포인터를 반환하는 것은 나쁜 습관입니다. 함수의 임의 사용자가 함수 외부에서 배열의 값을 예측할 수있는 방식으로 변경하도록 허용하기 때문입니다. 당신이 값으로, 완전한 배열을 반환하려면
은, 아마 당신은 이런 식으로 배열 필드를 포함하는 struct 유형을 정의해야합니다

typedef struct { int sub[10]; } wrappedarray_t; 
    wrappedarray_t getRandom(void) { 
     wrappedarray_t r; 
     // sentences.... 
     return r; 
    } 
    wrappedarray_t p = getRandom(); 
    printf("0th element: %d\n", p.sub[0]); 
0

는 데이터의 로컬 할당 조각을 사용하고 있기 때문에, 프로그램이 범위를 벗어나면 저장 한 모든 데이터가 버려지고 쓰레기 값이 반환됩니다. 이 상황에서

, 당신은 두 가지를 수행 할 수 있습니다

중 하나 malloc() 포인터 배열 또는 정적 배열을 사용하고 그 중 하나를 반환합니다.

다른 옵션은 배열 매개 변수를 함수 매개 변수에 넣어 데이터가 해당 버퍼에 복사되도록하는 것입니다.