C 언어/멘토링

[C언어/멘토링] 멘토링 시험 오답 정리

luckyd8 2025. 6. 8. 18:42

 

문제 1. 

A를 입력받고, 윤년인지 아닌지 판별. 윤년이면 1, 아니면 0을 반환

4의 배수면 윤년, 100의 배수면 윤년 아님, 400의 배수면 윤년

 

문제의 핵심은 윤년의 조건을 제대로 구분하는 데에 있다. 

윤년은 4의 배수이면서, 100의 배수가 아닐 때 혹은 400의 배수일 때이다. 

즉, (4의배수 and 100의 배수) or 400의 배수의 조건을 가진다.

 

답으로 작성한 코드이다. 

#include<stdio.h>

int main()
{
	int A;

	scanf_s("%d", & A);

	if (A % 4 == 0 || A % 400)
	{
		printf("1");
	}
	else if (A % 100 ==0) {
		printf("0");
	}
}

 

 

A가 윤년인 경우 조건을 4의 배수 혹은 400의 배수로 설정했다. 또한 A가 윤년이 아닐 경우 조건은 100의 배수로 설정했다.

결과 자체는 예제와 동일하다. 하지만 다른 윤년의 수를 입력하는 경우, 잘못된 결과가 출력될 수 있다.

즉, 오답의 원인은 조건 분석의 불명확함에 있다. 이를 바탕으로 오답을 수정했다.

#include <stdio.h>

int main()
{
	int A;
    scanf_s("%d", &A);
    
    if ((A % 4 == 0 && A % 100) || A % 400 == 0) // 윤년의 조건: 4의 배수이면서 100의 배수일 때 or 400의 배수일 때
    {
    	printf("1");
    } else {
    	printf("0");
    }
}



문제 2.

숫자 A를 입력받고, A!(팩토리얼) 값을 출력. 단, for, while, do while, goto문 사용 금지.

 

사용자 정의 함수로 '팩토리얼'을 생성하고 재귀 함수로 출력하는 방식으로 접근하는 것이 좋겠다고 생각했다.

답으로 작성한 코드는 다음과 같다.

#include<stdio.h>

int 팩토리얼(int A)
{
	int A* (A - 1);
}

int main()
{
	int a;
	scanf_s("%d", &a);
	printf("%d", 팩토리얼(a));
}

 

결과는 컴파일 오류가 났다. 오류의 주요 원인은 사용자 정의 함수 '팩토리얼' 속 코드를 제대로 설정하지 못한 것에 있다.

우선, int A * (A-1);은 단순 곱셈 식으로, 계산 후에 저장하거나 반환하는 코드가 없다.

즉, 반환 값을 추가해 코드를 수정해야 한다. 또한 0!=1의 경우 또한 고려해 작성해야 한다.

이를 바탕으로 오답을 수정했다. 

#include <stdio.h>

int 팩토리얼(int A)
{
	if (A <= 1) return 1; // 0!=1의 경우
	return A * 팩토리얼(A - 1);
}

int main() {
	int a;
	scanf_s("%d", &a);
	printf("%d \n", 팩토리얼(a));
}

 

문제 3.

숫자를 입력받고, 입력받은 높이의 오른쪽으로 정렬된 삼각형을 출력.

 

이중 for문을 이용해서 숫자 N개가 i번 반복되는 동안, 공백 k와 별 문자(*) a가 출력되는 형식으로 코드를 작성했다.

N이 1일 때,  k는 1부터 N-1개까지 출력 → 별 문자(*) a는 하나 출력 → 줄 바꿈 으로 진행하고자 했다.

답으로 작성한 코드는 다음과 같다. 

#include<stdio.h>

int main()
{
	int N;
	scanf_s("%d", &N);

	for (int i = 1; i <= N; i++)
	{
		for (int k = 1; k < N; k++)
		{
			printf(" ");
		}

		for (int a = 1; a <= N; a++)
		{
			printf("*");
		}
		printf("\n");
	}
}

 

하지만 이 코드는 내가 원한 시나리오대로 출력되지 않는다. '공백은 N - 1(k < N)개를 출력 -> → 별 문자(*)는 N개 출력 → 줄바꿈' 을 N번 반복하는 꼴이다. 결국 동일한 내용을 N번 반복해 다음과 같은 결과를 출력한다. 

 

이를 수정하기 위해선 공백과 별의 개수를 줄 번호 i에 따라 변경해야 한다. (줄 번호 i 일 때, 공백 N - i 개 출력 → 별 i 개 출력)

이를 바탕으로 오답을 수정했다.

#include <stdio.h>

int main()
{
	int N;
	scanf_s("%d", &N);

	for (int i = 1; i <= N; i++)
	{	
		for (int k = 1; k <= N - i; k++) // 공백 N-i개
			printf(" ");

		for (int a = 1; a <= i; a++) // 별 i개
			printf("*");

		printf("\n");
	}
}

 

 

 

문제 4. 

숫자 A를 입력받고, A가 짝수인지 홀수인지 판별하세요. 단, %연산자 사용 금지

 

우선, % 연산자를 사용하지 말라는 조건을 제대로 확인하지 못한 채로 문제를 풀었다.

그리고 짝수, 홀수를 명칭하는 영어를 정확히 몰라서 한글로 표기했다. 

답으로 작성한 코드이다. 

#include<stdio.h>

int main()
{
	int A;
	scanf_s("%d", &A);

	if (A % 2 == 0)
	{
		printf("짝수");
	}
	else {
		printf("홀수");
	}
}

 

결과적으로 짝수, 홀수를 잘 구분해내긴 했지만, % 연산자를 사용했으므로 오답이다.

% 연산자 없이 짝수, 홀수를 구분하는 방법에는 비트 연산자(&)를 사용하는 경우가 많다.

더보기

비트 연산자

정수형 데이터를 이진수 비트 단위로 연산하는 연산자 (&, |, ^, ~, <<, >> 등)

 

- & : 같은 위치의 비트가 모두 1이면 1을 반환

예) 5 & 3 -> 101 & 011 = 001

짝수는 이진수의 마지막 비트가 0, 홀수는 1이므로 1의 자리 비트만 비교해 값을 반환하도록 하면 된다.

이를 바탕으로 오답을 수정했다.

int main()
{
	int A;
	scanf_s("%d", &A);

	if (A & 1) { // 맨 끝자리 비트
		printf("odd"); // 홀수: odd number
	}
	else {
		printf("even"); // 짝수: even number
	}
}

 

 

문제 5. 

크기가 인 배열 arr을 선언하고, 사용자에게 숫자 5개를 입력받음.

각 숫자들을 더한 값을 출력하세요. 입력 형식은 자유입니다. 단, 배열의 선언 외에는 대괄호 사용 금지.

 

중괄호를 사용하지 않고, 배열을 입력 받을 방법을 생각해 내지 못했다. 이후 찾아보니 포인터를 활용하는 법이 있었다. 

배열 arr의 시작 주소를 포인터 p에 할당해, 배열의 각 요소의 값을 입력받는다. 그 후 sum 변수를 활용해 모든 값을 더하고 결과를 출력한다. 

 

개인적으로 p + i를 해석하기 힘들었는데, p는 배열 arr의 시작 주소(arr[0])를 담고 있으므로, p + i는 arr[0]에서 위치가 i만큼 덜어진 주소를 가리키게 된다.

이를 바탕으로 입력한 코드이다. 

#include <stdio.h>

int main() {
	int arr[5];
	int* p = arr;
	int sum = 0;
	int i;
	
	for (i = 0; i < 5; i++) {
		scanf_s("%d", p + i); // p + i = p[0] + i
	}

	for (i = 0; i < 5; i++) {
		sum += *(p + i);
	}

	printf("%d\n", sum);
}

 

 

문제 6.

두 구조체(포인터를 사용하지 않은 구조체와 동적으로 할당한 구조체)를 선언. 이후 점수가 더 높은 구조체의 이름을 출력하세요.

 

'하나의 구조체를 정적과 동적으로 설정'하는 문제이다.

더보기

'포인터를 사용하지 않은 구조체 vs 동적으로 할당한 구조체' 라고 표현하신 이유가 궁금했다.

동적으로 할당한 구조체는 포인터가 반드시 필요하다.

동적 할당 시 사용하는 malloc 함수는 메모리 공간을 '힙 영역'에 동적으로 할당, 그 메모리의 주소를 반환한다.

s2 = (student*)malloc(sizeof(student)); // 정답 코드 속 동적 할당 코드

student 크기만큼 메모리를 할당, 메모리의 주소를 s2에 저장, 즉, s2는 포인터여야만 한다.

 

반면, 포인터를 사용하지 않는 구조체는 포인터가 필요하지 않다.

이러한 구조체는 정적 메모리 할당 방식을 쓴다.

컴파일 타임에 스택(stack) 영역에 메모리가 자동으로 할당하고, 함수 종료 시 자동으로 소멸된다.

즉, 포인터를 사용하지 않은 구조체 (= 정적 할당 방식), 동적으로 할당한 구조체(=포인터를 사용한 동적 할당 방식)

정답 코드이다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct student {
	char name[20];
	int score;
}; student;

int main() {
	student s1;
	student* s2;

	s2 = (student*)malloc(sizeof(student)); // s2 포인터에 동적 할당

	printf("student1's name: ");
	scanf_s("%s", s1.name, sizeof(s1.name));

	printf("student2's name: ");
	scanf_s("%s", s2->name, sizeof(s2->name));

	scanf_s("%d", &s1.score);
	scanf_s("%d", &s2->score);

	if (s1.score > s2->score) {
		printf("%s\n", s1.name);
	}
	else if (s1.score < s2->score) {
		printf("%s\n", s2->name);
	}
    
	free(s2);
}

 

 

보너스 문제.

두숫자 A, B를 입력받음. A XORB연산을 진행한 값을 출력. 이후 이를 복호화해 다시 출력. 단, 변수는 2개 이하로 선언해야 하며, 모두 int형이여야 한다.

 

XOR 연산자 개념이 기억나지 않았다. 

더보기

XOR 연산자

XOR(^) 연산자는 비트가 서로 같은 경우에 0을 반환, 그렇지 않으면 1을 반환하는 연산자이다. 

- A ^ A -> 1

- A ^ 0 -> A // 0과 연산시 자신을 반환

- A ^ B = B ^ A // 교환법칙 성립

- (A ^ B) ^ C = A ^ (B ^ C) // 결합법칙 성립

정답 코드이다. 

( A ^ B) ^ B의 경우, (A⊕B)⊕B = A⊕(B⊕B) = A⊕0=A 이므로, 항상 A가 반환된다. 

#include <stdio.h>

int main() {
	int A, B;

	printf("A: ");
	scanf_s("%d", &A);

	printf("B: ");
	scanf_s("%d", &B);

	printf("before: %d", A ^ B); // 연산 값
	printf("after: %d", (A ^ B) ^ B); // 복호화 값
}