티스토리 뷰

반응형

 

C언어 기초 Chapter 14: 포인터와 함수 (배열 전달, Call by Value & Reference, const)


14-1. 함수의 인자로 배열 전달하기

배열 전달 기본

  • 함수에 배열을 넘기면, 사실은 배열의 첫 번째 원소 주소가 전달됨
  • 따라서 배열 크기 정보는 따로 넘겨줘야 함
#include <stdio.h>
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main(void) {
    int nums[5] = {1, 2, 3, 4, 5};
    printArray(nums, 5);
    return 0;
}

👉 출력: 1 2 3 4 5


배열 원소 수정하기

#include <stdio.h>
void addOne(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] += 1;
    }
}

int main(void) {
    int nums[3] = {10, 20, 30};
    addOne(nums, 3);
    for (int i = 0; i < 3; i++) {
        printf("%d ", nums[i]);  // 11 21 31
    }
    return 0;
}

👉 함수 안에서 배열 값이 실제로 변경됨 (주소 전달 방식이기 때문)


14-2. Call by Value vs. Call by Reference

Call by Value (값에 의한 전달)

  • 변수 값 자체를 복사해서 함수에 전달
  • 원본 값은 변하지 않음
#include <stdio.h>
void changeValue(int x) {
    x = 100;  // 지역 변수 x만 변경
}
int main(void) {
    int a = 10;
    changeValue(a);
    printf("a = %d\n", a);  // 10
    return 0;
}

Call by Reference (참조에 의한 전달)

  • 변수의 주소를 전달
  • 함수 안에서 원본 값을 직접 변경 가능
#include <stdio.h>
void changeValue(int *x) {
    *x = 100;  // 실제 변수 값 변경
}
int main(void) {
    int a = 10;
    changeValue(&a);
    printf("a = %d\n", a);  // 100
    return 0;
}

👉 C언어는 기본적으로 Call by Value지만, 포인터를 이용하면 Call by Reference 효과를 낼 수 있음


14-3. 포인터 대상의 const 선언

const 포인터 종류

  1. 포인터가 가리키는 값 변경 불가
const int *p;
  • p는 다른 곳을 가리킬 수 있음
  • 하지만 *p 값은 변경 불가
int a = 10, b = 20;
const int *p = &a;
p = &b;      // 가능
//*p = 30;   // ❌ 불가능

  1. 포인터 자체 변경 불가
int * const p = &a;
  • p가 다른 변수를 가리킬 수 없음
  • 하지만 *p 값은 변경 가능
int a = 10, b = 20;
int * const p = &a;
*p = 30;    // 가능
// p = &b;  // ❌ 불가능

  1. 값도 변경 불가, 포인터도 변경 불가
const int * const p = &a;

핵심 정리 ✅

  • 배열은 함수에 전달될 때 주소(포인터) 로 전달됨
  • C는 기본적으로 Call by Value → 원본 불변
  • 포인터를 사용하면 Call by Reference처럼 원본 수정 가능
  • const 와 포인터 조합은 값 보호 / 포인터 보호 / 둘 다 보호 가능

연습 문제 ✍️

  1. 배열 {1,2,3,4,5} 를 함수로 전달해 모든 원소에 +10 한 뒤 결과 출력하세요.
  2. Call by Value와 Call by Reference 차이를 보여주는 예제를 작성하세요.
  3. const int *p, int * const p, const int * const p 의 차이를 실험해 보세요.

 

👉 연습문제 정답은? ▼

 

Chapter 14 연습문제 풀이


1) 배열 {1,2,3,4,5} 를 함수로 전달해 모든 원소에 +10 하기

#include <stdio.h>

void addTen(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        arr[i] += 10;
    }
}

int main(void) {
    int nums[5] = {1, 2, 3, 4, 5};

    addTen(nums, 5);

    printf("배열 원소: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", nums[i]);
    }
    return 0;
}

👉 출력:

배열 원소: 11 12 13 14 15

2) Call by Value vs Call by Reference 차이

#include <stdio.h>

void changeByValue(int x) {
    x = 100;   // 지역 변수만 바뀜
}

void changeByReference(int *x) {
    *x = 200;  // 실제 값 바뀜
}

int main(void) {
    int a = 10;

    changeByValue(a);
    printf("Call by Value 후 a = %d\n", a);  // 10

    changeByReference(&a);
    printf("Call by Reference 후 a = %d\n", a);  // 200

    return 0;
}

👉 출력:

Call by Value 후 a = 10
Call by Reference 후 a = 200

3) const int *p, int * const p, const int * const p 차이 실험

#include <stdio.h>

int main(void) {
    int a = 10, b = 20;

    // 1) const int *p → 값 변경 불가, 포인터 이동 가능
    const int *p1 = &a;
    // *p1 = 30;   // ❌ 불가능
    p1 = &b;       // ✅ 가능

    // 2) int * const p → 포인터 이동 불가, 값 변경 가능
    int * const p2 = &a;
    *p2 = 40;      // ✅ 가능
    // p2 = &b;    // ❌ 불가능

    // 3) const int * const p → 값 변경 불가, 포인터 이동 불가
    const int * const p3 = &a;
    // *p3 = 50;   // ❌ 불가능
    // p3 = &b;    // ❌ 불가능

    printf("a = %d, b = %d\n", a, b);
    return 0;
}

👉 실행 결과는 컴파일러에 따라 경고 또는 오류가 다를 수 있지만, 원칙은:

  • const int *p → 값 보호
  • int * const p → 포인터 보호
  • const int * const p → 값과 포인터 모두 보호

핵심 정리 ✅

  • 배열을 함수에 전달하면 원소 값 변경 가능 (주소 전달)
  • C는 기본적으로 Call by Value, 포인터 이용 시 Call by Reference 구현 가능
  • 포인터 + const 조합으로 안전한 코드 작성 가능

 

반응형