티스토리 뷰

 

C언어 기초 다지기, 2019년 중간고사 문제 해설

안녕하세요, 코딩 꿈나무 여러분! 오늘은 C언어 기초를 탄탄하게 다질 수 있는 시간을 가져보려고 해요. 2019학년도 2학기 기초 프로그래밍2 중간고사에 나왔던 문제들을 함께 풀어보면서 중요한 개념들을 복습해 봅시다. 코딩이 처음이라도 괜찮아요! 차근차근 설명해 드릴 테니 잘 따라오세요!

목차

코드의 결과는? - 반복문과 조건문 (문제 1-가)

먼저 첫 번째 코드의 출력 결과를 맞춰볼까요?

for (i = 2; i < 12; i = i + 2) {
    if (i % 4 == 0) continue;
    printf("%d, ", i);
    if (i % 10 == 0) break;
}

이 코드는 `for` 반복문을 사용해서 변수 `i`를 2부터 시작해서 2씩 증가시키면서 12보다 작을 때까지 반복해요. 즉, `i`는 2, 4, 6, 8, 10 순서로 변하게 되죠.

  • `i`가 2일 때: `i % 4 == 0` (2를 4로 나눈 나머지)는 거짓이죠. 그래서 `continue`를 건너뛰고 `printf("%d, ", i);`를 실행해서 "2, "가 출력돼요. `i % 10 == 0`도 거짓이니 `break`도 건너뜁니다.
  • `i`가 4일 때: `i % 4 == 0` (4를 4로 나눈 나머지)는 참이에요! `continue`를 만나면 이번 반복은 여기서 멈추고 바로 다음 반복으로 넘어가요. 그래서 `printf`는 실행되지 않아요.
  • `i`가 6일 때: `i % 4 == 0`은 거짓. `printf`를 실행해서 "6, "이 출력돼요. `i % 10 == 0`은 거짓.
  • `i`가 8일 때: `i % 4 == 0`은 참. `continue`를 만나 `printf`는 실행되지 않아요.
  • `i`가 10일 때: `i % 4 == 0`은 거짓. `printf`를 실행해서 "10, "이 출력돼요. 그런데 이번에는 `i % 10 == 0` (10을 10으로 나눈 나머지)가 참이네요! `break`를 만나면 반복문을 완전히 빠져나와요.

따라서 최종 출력 결과는 2, 6, 10, 이 됩니다!

여기서 `continue`는 현재 반복을 중단하고 다음 반복으로 넘어가는 것, `break`는 반복문 자체를 완전히 끝내는 것이라는 차이점을 기억하는 게 중요해요!

함수와 변수의 세계 - 변수의 범위 (문제 1-나)

다음 코드의 결과를 예측해 봅시다.

int num = 10;
void fun1() { int num = 20; printf("%d\n", num); }
void fun2() { printf("%d\n", num); num = 40; }
int main() {
    int num = 30;
    fun1();
    printf("%d\n", num);
    fun2();
    fun2();
}

이 코드는 변수의 '범위(scope)'에 대한 문제예요. 같은 이름의 변수 `num`이 여러 곳에 선언되어 있죠?

  • 전역 변수 `num` (값 10): 함수 바깥 맨 위에 선언된 `num`이에요. 프로그램 전체에서 사용할 수 있지만, 같은 이름의 지역 변수가 있으면 그 지역 변수에 가려져요.
  • `fun1` 함수의 지역 변수 `num` (값 20): `fun1` 함수 안에서만 사용되는 `num`이에요.
  • `main` 함수의 지역 변수 `num` (값 30): `main` 함수 안에서만 사용되는 `num`이에요.

이제 `main` 함수를 따라가 봅시다.

  1. `fun1();` 호출: `fun1` 함수 안으로 들어가요. `fun1` 안에는 지역 변수 `num` (값 20)이 있죠? `printf("%d\n", num);`는 이 지역 변수 `num`의 값인 20을 출력해요. `fun1` 함수가 끝나면 이 지역 변수 `num`은 사라져요.
  2. `printf("%d\n", num);` 실행: 다시 `main` 함수로 돌아왔어요. 여기서 `num`은 `main` 함수의 지역 변수 `num` (값 30)을 가리켜요. 따라서 30이 출력돼요.
  3. `fun2();` 첫 번째 호출: `fun2` 함수 안으로 가요. `fun2` 안에는 `num`이라는 이름의 지역 변수가 없죠? 이럴 때는 가장 가까운 바깥 범위의 변수, 즉 전역 변수 `num` (값 10)을 사용해요. `printf("%d\n", num);`는 전역 변수 `num`의 값인 10을 출력해요. 그리고 `num = 40;`을 실행해서 전역 변수 `num`의 값을 40으로 바꿔요!
  4. `fun2();` 두 번째 호출: 다시 `fun2` 함수로 가요. 이번에도 전역 변수 `num`을 사용하는데, 이전 호출에서 값이 40으로 바뀌었죠? 그래서 `printf("%d\n", num);`는 40을 출력해요. 그리고 `num = 40;`을 또 실행하지만, 이미 40이니까 값은 그대로 40이에요.

따라서 최종 출력 결과는 줄바꿈으로 구분되어 20 30 10 40 이 됩니다!

지역 변수는 그 함수 안에서만 유효하고, 지역 변수가 없을 때는 전역 변수를 사용한다는 점을 꼭 기억하세요!

포인터가 뭐길래? - 주소와 값 (문제 1-다)

포인터가 등장했네요! 다음 코드의 출력은 무엇일까요?

int num = 1;
int *p = #
printf("%d, %p, %p, %d\n", num, &num, p, *p);

포인터는 메모리의 '주소'를 저장하는 특별한 변수예요.

  • `int num = 1;`: 정수형 변수 `num`을 만들고 값 1을 저장했어요.
  • `int *p = #`: 정수형 포인터 변수 `p`를 만들고, `num` 변수의 메모리 주소(`&num`)를 저장했어요. `&`는 변수의 주소를 알아내는 연산자예요.
  • `printf(...)`: 이제 출력할 값들을 하나씩 봅시다.
    • `num`: 변수 `num`의 값인 1이 출력돼요.
    • `&num`: 변수 `num`의 메모리 주소가 출력돼요. 이건 컴퓨터마다 다르지만, 어떤 메모리 주소 값(예: 0x7ffeeabc1234)이 출력될 거예요. `%p`는 주소를 출력하는 서식 지정자예요.
    • `p`: 포인터 변수 `p`에 저장된 값, 즉 `num`의 주소가 출력돼요. 따라서 바로 앞의 `&num`과 같은 메모리 주소 값이 출력돼요.
    • `*p`: 포인터 변수 `p`가 가리키는 주소에 저장된 '값'을 가져오는 연산자(`*`)예요. `p`는 `num`의 주소를 가리키고 있으니, `*p`는 `num`의 값인 1이 출력돼요.

따라서 출력 결과는 1, [어떤 주소], [같은 주소], 1 형태가 될 거예요. (실제 주소 값은 실행 환경마다 다릅니다.)

포인터는 변수의 주소를 저장하고(`p = &num`), 그 주소를 통해 원래 변수의 값에 접근(`*p`)할 수 있게 해준다는 점이 핵심이에요!

소문자를 대문자로! - 함수 만들기 (문제 2)

키보드로 영문 소문자 하나를 입력받아서 대문자로 바꿔 출력하는 프로그램을 만드는 문제예요. `upper`라는 함수를 사용하라고 되어 있네요.

// 주어진 upper 함수
char upper(char ch) {
    return ch - ('a' - 'A');
}

// main 함수 완성하기
int main() {
    char ch;
    printf("문자: ");
    scanf("%c", &ch); // 키보드로부터 문자 하나를 입력받아 ch 변수에 저장

    // 입력받은 문자가 소문자인지 확인
    if (ch >= 'a' && ch <= 'z') {
        // 소문자라면 upper 함수를 호출하여 대문자로 변환하고 출력
        printf("%c ==> %c\n", ch, upper(ch));
    } else {
        // 소문자가 아니라면 변환할 수 없다고 알려주기 (선택 사항)
        printf("입력한 문자는 소문자가 아닙니다.\n");
    }
    return 0;
}

먼저 `scanf("%c", &ch);`를 사용해서 사용자로부터 문자 하나를 입력받아요. `%c`는 문자를 입력받는 서식 지정자고, 변수 이름 앞에 `&`를 붙여서 입력받은 값을 `ch` 변수의 메모리 주소에 저장하라는 뜻이에요.

그 다음 `if (ch >= 'a' && ch <= 'z')` 조건문으로 입력받은 문자가 소문자인지 확인해요. C언어에서 문자는 내부적으로 숫자로 처리되기 때문에 이렇게 비교할 수 있어요.

만약 소문자가 맞다면, `upper(ch)` 함수를 호출해요. `upper` 함수는 소문자(`ch`)와 대문자의 아스키 코드 값 차이('a' - 'A')를 이용해서 대문자로 변환한 값을 돌려줘요. 예를 들어 'a'가 들어오면 'a' - ('a' - 'A') = 'A'가 되는 원리죠. 그리고 `printf`를 이용해 원래 소문자와 변환된 대문자를 함께 출력해요.

만약 소문자가 아니라면, 변환하지 않고 그냥 넘어갈 수도 있고, 위 코드처럼 안내 메시지를 출력해 줄 수도 있어요.

값이 변하지 않는 이유? - 값에 의한 호출 (문제 3)

마지막 문제는 `increment` 함수를 호출했는데 왜 `main` 함수의 `num` 값이 변하지 않았는지 설명하는 거예요.

int increment(int num) {
    return ++num; // 함수 안의 num 값을 1 증가시키고 그 값을 반환
}

int main() {
    int num = 10;
    increment(num); // 함수 호출
    printf("%d\n", num); // main 함수의 num 값 출력
    return 0;
}

C언어에서 함수를 호출할 때 인자를 전달하는 방식은 기본적으로 '값에 의한 호출 (call by value)'이에요. 이게 무슨 말이냐면, `increment(num);` 이렇게 함수를 호출할 때 `main` 함수의 `num` 값인 10 '자체'가 넘어가는 게 아니라, 10이라는 '값'이 복사되어서 `increment` 함수의 매개변수 `num`에 전달된다는 뜻이에요.

그래서 `increment` 함수 안에서 `++num`을 실행하면, 복사된 값 10이 11로 바뀌는 것이지, `main` 함수에 있는 원래 `num` 변수의 값이 바뀌는 게 아니에요. `increment` 함수가 끝나면 복사되었던 값은 사라지고, `main` 함수의 `num`은 여전히 원래 값인 10을 가지고 있는 거죠. 그래서 `printf`로 출력하면 10이 나오는 거예요.

만약 `main` 함수의 `num` 값을 바꾸고 싶다면, `increment` 함수가 반환하는 값(증가된 값)을 다시 `main` 함수의 `num`에 저장해 줘야 해요. 이렇게요:

num = increment(num); // increment 함수가 반환한 값을 num에 저장
printf("%d\n", num); // 이제 11이 출력될 거예요!

또는 포인터를 사용해서 함수가 직접 `main` 함수의 변수 주소에 접근하게 하는 방법도 있답니다. (이건 나중에 더 자세히 배울 거예요!)

오늘 C언어 중간고사 문제를 풀어보면서 반복문, 조건문, 변수의 범위, 포인터, 함수 호출 방식 등 중요한 개념들을 복습해 봤어요. 꾸준히 연습하면 코딩 실력이 쑥쑥 늘 거예요! 화이팅!

 

개념 설명 관련 코드/키워드
반복문 제어 `continue`: 현재 반복 중단 후 다음 반복 진행.
`break`: 반복문 전체를 즉시 종료.
`for`, `while`, `continue`, `break`
변수의 범위 (Scope) 변수가 유효한 영역. 지역 변수는 함수 내에서만, 전역 변수는 프로그램 전체에서 (단, 지역 변수에 가려질 수 있음). 지역 변수 (함수 내 선언), 전역 변수 (함수 밖 선언)
포인터 메모리 주소를 저장하는 변수. 주소를 통해 값에 접근 가능. `*` (포인터 선언, 값 접근), `&` (주소 연산자), `%p` (주소 출력)
함수 인자 전달 값에 의한 호출 (Call by Value): 인자의 '값'이 복사되어 전달됨. 함수 내에서 매개변수 값을 변경해도 원본 변수에는 영향 없음. 함수 호출 시 인자 전달 방식
문자 처리 문자는 내부적으로 숫(아스키 코드)로 처리되어 비교 및 연산 가능. `char`, `'a'`, `'A'`, `scanf("%c", ...)`
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함