본문 바로가기

Studying/정보처리기사

[정보처리기사 실기]_C언어 특강(3)

21번

f(5) {
	if (n > 0) f(n - 2);
	printf("%d ", n);
}

함수는 재귀적으로 n이 0 이하가 될 때까지 n을 2씩 감소시키며 자신을 호출.

n > 0인 경우에만 재귀호출 하고, 그 후에 printf("%d ", n);을 실행.

재귀 함수는 함수가 자기 자신을 직접 또는 간접적으로 호출하는 함수를 의미. 이러한 호출은 함수 호출 스택 사용하여 처리되고, 함수가 호출될 때마다 새로운 인스턴스가 스택에 푸시(PUSH)되고, 함수가 반환되면 스택에서 팝(POP) 됨. 재귀 함수는 특정 종료 조건을 충족할 때까지 반복적으로 자신을 호출하여 문제 해결함.

 

1) f(5) 함수가 호출되면서 함수 안에 if문 조건 확인.

2) if(n > 0) 조건이 참이면 f(n - 2) 실행. 현재 n = 5이고, 5 > 0이므로 조건은 참이어서 f(n - 2) = f(3)이 호출.

3) f(3) 함수가 호출되면서 함수 안에 if문 조건 확인.

4) if(n > 0) 조건이 참이면 f(n - 2) 실행. 현재 n = 3이고, 3 > 0이므로 조건은 참이어서 f(n - 2) = f(1)이 호출.

5) f(1) 함수가 호출되면서 함수 안에 if문 조건 확인.

6) if(n > 0) 조건이 참이면 f(n - 2) 실행. 현재 n = 1이고, 1 > 0이므로 조건은 참이어서 f(n - 2) = f(-1)이 호출.

7) f(-1) 함수가 호출되면서 함수 안에 if문 조건 확인.

8) if(n > 0) 조건이 참이면 f(n - 2) 실행. 현재 n = -1이고, -1 > 0이므로 조건은 거짓이어서 재귀호출 수행하지 않고  if문 빠져나오고 출력.

9) printf("%d ", n)에서 n의 값을 정수로 출력하면 현재 n = -1이므로 -1 출력.

10) 호출 스택 거슬러 올라가면서, f(1) 함수는 이전 호출로 돌아감.

11) f(1) 함수는 끝나고, printf("%d ", n)이 실행되면서 n = 1이었으므로 1 출력.

12) 호출 스택 또 거슬러 올라가면서, f(3) 함수는 이전 호출로 돌아감.

13) f(3) 함수는 끝나고, printf("%d ", n) 이 실행되면서 n = 3이었으므로 3 출력.

14) 호출 스택 또 거슬러 올라가면서, f(5) 함수는 이전 호출로 돌아감.

15) f(5) 함수는 끝나고, printf("%d ", n) 이 실행되면서 n = 5이었으므로 5 출력.

 

[출력]

-1 1 3 5

22번

#include<stdio.h>

void main() {
	int a, b = 2;
	while (++b <= 30) {
		a = 1;
		while (++a < b) {
			if (b % a == 0) break;
		}
		if (a == b) printf("%d, ", b);
	}
}

 

주어진 코드는 소수를 출력하는 프로그램. 즉 2부터 30까지의 소수를 찾아 출력.

 

1) int a, b = 2;

 : 정수형 변수 a, b 선언 후 b = 2로 초기화.

 

2) while문

  ① b = 2일 때

      ⊙ ++b 가 실행되어 현재 b = 2에서 b = 3으로 저장. 3 <= 30 조건 참이므로 a = 1.

      ⊙ 다음 while문 조건은 ++a < b이고, 현재 a = 1이므로 ++a가 실행되며 a = 2로 저장. 2 < 3 조건 참이므로 if문 실행.

      ⊙ if (b % a == 0)이면 break 실행. b = 3, a = 2이므로 3 % 2 = 1이고, 조건은 거짓이므로 루프 계속 실행.

      ⊙ 다시 while 조건 보면 ++a < b이고, 현재 a = 2이므로 ++a가 실행되며 a = 3으로 저장. 3 < 3 조건 거짓이므로 내부 while문 빠져나옴.

       if (a == b) printf("%d, ", b); 가 실행되고 현재 a = 3,  b = 3이므로 3 == 3은 조건 참이므로 b의 값을 출력하면 3을 출력.

  ② b = 3일 때

      ⊙ ++b 가 실행되어 현재 b = 3에서 b = 4로 저장. 4 <= 30 조건 참이므로 a = 1.

      ⊙ 다음 while문 조건은 ++a < b이고, 현재 a = 1이므로 ++a가 실행되며 a = 2로 저장. 2 < 3 조건 참이므로 if문 실행.

      ⊙ if (b % a == 0)이면 break 실행. b = 4, a = 2이므로 4 % 2 == 0이고, 조건은 참이므로 while문 빠져나옴.

      ⊙ if (a == b) printf("%d, ", b);를 실행하면 현재 a = 2, b = 4이므로 조건 거짓이어서 출력하지 않음

  ③ b = 4 일 때

      ⊙ ++b가 실행되어 현재 b = 4에서 b = 5로 저장. 5 <= 30 조건 참이므로 a = 1.

      ⊙ 다음 while문 조건은 ++a < b이고, 현재 a = 1이므로 ++a가 실행되며 a = 2로 저장. 2 < 5 조건 참이므로 if문 실행.

      ⊙ if (b % a == 0)이면 break 실행. b = 5, a = 2이므로 5 % 2 = 1이고, 조건은 거짓이므로 루프 계속 실행.

      ⊙ 다시 while 조건 보면 ++a < b이고, 현재 a = 2이므로 ++a가 실행되며 a = 3으로 저장. 3 < 5 조건 참이므로 if 문 실행.

      ⊙ if (b % a == 0)이면 break 실행. b = 5, a = 3이므로 5 % 3 = 2이고, 조건은 거짓이므로 루프 계속 실행.     

      ⊙ 다시 while 조건 보면 ++a < b이고, 현재 a = 3이므로 ++a가 실행되며 a = 4로 저장. 4 < 5 조건 참이므로 if문 실행.     

      ⊙ if (b % a == 0)이면 break 실행. b = 5, a = 4이므로 5 % 4 = 1이고, 조건은 거짓이므로 루프 계속 실행.

      ⊙ 다시 while 조건 보면 ++a < b이고, 현재 a = 4이므로 ++a가 실행되며 a = 5로 저장. 5 < 5 조건 거짓이므로 내부 while문 빠져나옴.

      ⊙ if (a == b) printf("%d, ", b);가 실행되고 현재 a = 5, b = 5이므로 5 == 5는 조건 참이므로 b의 값을 출력하면 5를 출력.

 

3) 이와 같은 방식으로 b가 5, 6, 7, ..., 30까지 b의 값을 증가시키면서 소수 확인.

 

[출력]

3, 5, 7, 11, 13, 17, 19, 23, 29,

23번

#include<stdio.h>

int getnext(int a) {
	return (a * 2 + 1);
}
void main() {
	int i, j, k = 0;
	for (i = 1; i < 10; i++)
		for (j = 1; j < getnext(i); j++)
			k++;
	printf("k = %d\n", k);
}

 

1) int i, j, k = 0;

 : 정수형 변수 i, j, k를 선언하면서 k는 0으로 초기화.

 

2) for문

 ① i = 1 일 때

        j = 1일 때, j < getnext(i)면 현재 i = 1이므로 getnext(1) = 1 * 2 + 1 = 3. 따라서 j = 1일 때 j < 3까지 반복. k = 1.

        j = 2일 때, k = 2.

        j = 3일 때, 조건이 맞지 않으므로 안 쪽 for문 빠져나옴.

 ② i = 2 일 때

        j = 1일 때, j < getnext(i)면 현재 i = 2이므로 getnext(2) = 2 * 2 + 1 = 5. 따라서 j = 2일 때 j < 5까지 반복. k = 3.

        j = 2일 때, k = 4.

        j = 3일 때, k = 5.

        j = 4일 때, k = 6

        j = 5일 때, 조건이 맞지 않으므로 안 쪽 for문 빠져나옴.

 

3) 이와 같은 방식으로 i가 9일 때까지 반복하면서 k값 확인.

 

4) 간단하게 작성해서 확인하면

i = 1일 때 : getnext(1) = 3 → j는 1부터 2까지 반복(2회) → k += 2 → k = 2

i = 2일 때 : getnext(2) = 5 → j는 1부터 4까지 반복(4회) → k += 4 k = 6

i = 3일 때 : getnext(3) = 7 → j는 1부터 6까지 반복(6회) → k += 6 k =12

i = 4일 때 : getnext(4) = 9 → j는 1부터 8까지 반복(8회) → k += 8 k = 20

i = 5일 때 : getnext(5) = 11 j는 1부터 10까지 반복(10회) k += 10   k = 30

i = 6일 때 : getnext(6) = 13 → j는 1부터 13까지 반복(12회) → k += 12 k = 42

i = 7일 때 : getnext(7) = 15 → j는 1부터 14까지 반복(14회) → k += 14  k = 56

i = 8일 때 : getnext(8) = 17 → j는 1부터 16까지 반복(16회) → k += 16 k = 72

i = 9일 때 : getnext(9) = 19 → j는 1부터 18까지 반복(18회) → k += 18 k = 90

 

5) printf("k = %d\n", k);

 : k의 값을 정수로 출력하면 90

 

[출력]

k = 90

24번

#include<stdio.h>

f() {
	int i = 1;
	static int j = 1;
	printf("i= %d j = %d ", i++, j++);
}
void main() {
	f(); f(); f();
}

 

여기서 알아야 할 것은 static. 정적변수 static은 초기화를 반드시 한 번만 해야 함!

 

1) f(); f(); f();

 : main 함수에서 시작하며 함수 f()를 호출.

 

2) 함수 f() 내부

 : f() 내부로 올 때 마다 i는 매번 1로 초기화되며, j는 정적변수로 이전 호출에서의 값을 유지.

 

 ① f();

       : 처음 f()를 호출 했을 때 i = 1, j = 1로 초기화 되어있고, 출력 후  i와 j의 값을 증가.

         따라서 i = 1 j = 1 (i = 2, j = 2로 증가)

 ② f();

       : 두번째로 f()를 호출하여 가면 i는 1로 다시 초기화 되어있고, j는 이전에 호출했을 때 2의 값을 유지하며 옴.

         따라서 출력하면 i = 1 j = 2 (i = 2, j = 3으로 증가)

 ③ f();

       : 세번째로 f()를 호출하면 i는 1로 다시 초기화 되어있고, j는 이전에 호출했을 때 3의 값을 유지하며 옴.

         따라서 출력하면 i = 1 j = 3 (i = 2, j = 4로 증가)

 

 4) printf("i= %d, j = %d ", i++, j++);

 : 출력하면 함수를 호출 했을 때 i와 j의 값을 정수로 출력하면 i= 1 j = 1 i= 1 j = 2 i= 1 j = 3

 

[출력]

i= 1 j = 1 i= 1 j = 2 i= 1 j = 3

25번

#include<stdio.h>

int x = 0;
foo();

void main() {
	foo();
	foo();
}
foo() {
	static int a = 0;
	a += 10;
	x += 2;
	printf("%d %d ", a, x);
}

 

1) int x = 0;

 : 정수형 전역 변수 x를 선언하면서 0으로 초기화. 

 

2) foo() 함수

 : static int a = 0; → static 지역 변수 a는 프로그램 전체 실행 중 한 번만 초기화됨.

   a += 10; → foo 함수 호출 될 때마다 a에 10을 더함.

   x += 2; → 전역변수 x에 2를 더함.

 

2) 메인 함수 안에 foo();

 ① foo();

      첫 번째 foo() 호출. static int a = 0;이 처음 호출되어 a = 0으로 초기화되고, a += 10;이 실행되어 a = 10.

      전역 변수 x는 처음에 0이 었으며 x += 2;가 실행되어 x = 2.

      printf("%d %d ", a, x);에 의해 10 2가 출력

 ② foo();

      두 번째 foo() 호출. static 변수 a는 10이 남아 있으므로 다시 초기화되지 않고, a += 10;이 실행되어 a = 20.

      전역 변수 x는 이전 호출에서 2를 저장하고 있었으므로, x += 2;가 실행되어 x = 4.

      printf("%d %d ", a, x);에 의해 20 4가 출력

 

[출력]

10 2 20 4

26번

#include<stdio.h>

int a[] = { 1, 0, 3, 0, 5 };

void main() {
	int *p = a;
	while (*p)
		printf("%3d", *p++);
}

 

1) int a[] = { 1, 0, 3, 0, 5 };

 : 정수형 배열 a 선언하면서 초기화.

a   1 0 3 0 5
100   100 101 102 103 104

a의 첫 번째 공간을 100번지로 가정해서 하나씩 커진다고 하자. p는 a의 첫 번째 요소를 가리키므로 *p는 100번지첫 번째 요소 1을 가리킴.

 

2) int *p = a;

 : 포인터 p는 배열 a의 첫 번째 요소 가리킴. 즉 p = &a[0]과 동일. (첫 번째 시작하는 열 주소값을 가지는 것)

 

3) while문

 ⊙ while (*p)는 *p가 0이 아닐 때까지 반복. 즉 배열에서 0을 만나면 루프가 종료.

 ⊙ 처음 *p는 1이므로 1을 출력. (3d는 정수형으로 세자리 수 출력)

  출력 후 *p++ 증가하면 *p는 101번지두 번째 요소 0을 가리킴.

 ⊙ 다시 돌아와 while (*p) 조건 확인하면 현재 p가 가리키는 요소는 0이므로 조건은 거짓이 되어 루프가 종료.

 

4) printf("%3d", *p++);  : 정수로 출력하며 필드 너비는 3자리. __1

 

[출력]

  1

27번

#include<stdio.h>

void swap(int* A, int* B) {
	int *temp;
	temp = A;
	*A = *B;
	B = temp - 10;
}
void main() {
	int a = 10;
	int b = 20;
	swap(&a, &b);
	printf("%d %d", a, b);
}

 

1) int a = 10; int b = 20;

 : 정수형 변수 a, b 선언하면서 각 값으로 초기화.

 

2) swap(&a, &b);

 : swap 함수 호출되면 A와 B에는 a와 b의 각각의 주소가 전달.

  (a에 100번지, b에 200번지 주소가 저장되어 있다고 가정하자.)

10   20
a   b
100   200

 

3) swap 함수

 ① int *temp; → 포인터 변수 temp 선언

 ② temp = A; → A의 주소를 temp에 저장. 따라서 temp는 A의 주소인 100번지를 저장. temp와 A는 같은 주소를 가리키고 있음.

 ③ *A = *B; → B가 가리키는 공간의 값(20)을 A가 가리키는 공간의 값으로 변경. 즉 B가 가리키는 공간 200번지의 값인 20을 A가 가리키는 공간 100번지의 값인 10을 20으로 변경.

 ④ B = temp - 10; → 헷갈릴 수도 있는게 여기에서 B는 B가 가리키는 공간의 값을 바꾸는 것이 아닌 포인터 자체에 새로운 값을 대입하는 것.

   즉 temp - 10의 값을 B에 저장하는 것으로 temp에 100번지라고 가정했던 번지수에서 -10을 하면 90을 B에 저장하지만 b값과는 아무런 관계가 없음. 따라서 a, b의 값 교환은 이루어지지 않는 것을 알 수 있음.

 

3) printf("%d %d", a, b);

 : a와 b의 값을 정수로 출력하면 20 20.

 

4) 값 교환이 이루어지려면 아래와 같은 코드로 작성해야 함.

#include<stdio.h>

void swap(int* A, int* B) {
	int *temp;
	temp = *A;  // temp에 A가 가리키는 공간의 값 저장. (즉 a의 값)
	*A = *B;
	*B = temp; // B가 가리키는 공간의 값에 temp에 저장된 값 저장. (즉 b에 a의 원래 값 저장)
}
void main() {
	int a = 10;
	int b = 20;
	swap(&a, &b);
	printf("%d %d", a, b);
}

// 출력
20 10

 

[출력]

20 20

28번

#include<stdio.h>

int main() {
	static char *c[] = { "aaa", "bbb", "ccc" };
	printf("%s", *(c + 1));
	printf("%s", *c + 2);
}

 

 

1) static char* c[] = { "aaa", "bbb", "ccc" };

 : 문자열 포인터 배열 c를 선언하면서 3개의 문자열 저장. 각각을 100번지, 101번지, 102번지를 가리킨다고 가정. c는 첫 공간인 100번지를 저장

  ⊙ c[0] = "aaa"

  ⊙ c[1] = "bbb"

  ⊙ c[2] = "ccc"

    c[0] c[1] c[2]
c   "aaa" "bbb" "ccc"
100   100 101 102

 

2) printf("%s", *(c + 1));

 : *(c + 1)은 c라는 공간 100번지 + 1 = 101번지의 값을 구하는 것. 즉 c[1]과 동일한 의미. 따라서 "bbb" 출력.

 

3) printf("%s", *c + 2);

 : *c + 2는 c라는 공간 100번지의 값("aaa")에서 +2인 두 번째 인덱스를 가리킴.

   즉 "aaa" 문자열에서 세번째 문자인 "a"부터 시작하는 부분 문자열인 "a"를 출력.

 

[출력]

bbba

29번

#include<stdio.h>

int main() {
	int data[][3] = { 1, 3, 4, 5, 2, 9, 6, 8, 7 };
	int *p = data[1];
	int x, y;
	x = *p;
	y = *(p + 2);
	printf("x = %d, y = %d\n", x, y);
}

 

x = *p는 p의 값이라고 읽어서 풀면 이해하기 쉬움.

 

1) int data[][3] = { 1, 3, 4, 5, 2, 9, 6, 8, 7 };

 : 2차원 정수 배열 data를 선언하면서 초기화. ([][]가 두 개면 이차원 배열 의미) 즉 3개의 열과 3개의 행을 가짐.

   첫 번째 시작하는 위치를 100번지라고 가정. 행 대표는 첫 번째 시작하는 열 주소값을 의미.

  ⊙ data : 100번지

  ⊙ data[0] : 100번지(1, 3, 4) → 1 : 100번지 / 3 : 101번지 / 4 : 102번지

  ⊙ data[1] : 103번지(5, 2, 9)  → 5 : 103번지 / 2 : 104번지 / 9 : 105번지

  ⊙ data[2] : 106번지(6, 8, 7)  → 6 : 106번지 / 8 : 107번지 / 7 : 108번지

  data[0] 1 3 4
data data[1] 5 2 9
  data[2] 6 8 7

 

2) int *p = data[1];

 : 포인터 변수 p는 data[1]을 가리키므로 103번지. 즉 data[1][0]을 의미하고 5를 가리킴.

 

3) int x, y;

 : 정수형 변수 x, y 선언.

 

4) x = *p;

 : p가 가리키는 공간의 값을 x에 저장하는 의미. 현재 p는 103번지를 가리키고 그의 값인 5를 x에 저장하면 x = 5.

 

5) y = *(p + 2);

 : p라는 공간 103번지 + 2 = 105번지의 값을 y에 저장. 105번지의 값은 9이므로 y에 저장하면 y = 9.

 

6) printf("x = %d, y = %d\n", x, y);

 : x, y의 값을 정수로 출력하면 x = 5, y = 9

 

[출력]

x = 5, y = 9

30번

#include<stdio.h>

void main() {
	int a[] = { 2, 4, 6, 8, 10 }, b, c;
	int *p = a + 3;
	b = *p - 2;
	c = p[-2];
	printf("%d, %d\n", b, c);
}

 

1) int a[] = { 2, 4, 6, 8, 10 }, b, c;

 : 정수형 배열 a 선언하면서 초기화. 정수형 변수 b, c 선언. 첫 번째 시작 위치를 100번지로 가정.

a   2 4 6 8 10
100   100 101 102 103 104

 

2) int *p = a + 3;

 : 포인터 변수 p는 a가 가리키는 공간 100 + 3 = 103번지. 즉 *p =  a[3] = 8을 의미.

 

3) b = *p -2;

 : 포인터 변수 p는 현재 103번지 공간의 8을 가리키고 그 값에서 -2하면 6을 변수 b에 저장. b = 6.

 

4) c = p[-2];

 : 현재 p가 가리키는 공간에서 왼쪽으로 2칸 이동하면 101번지 공간의 값인 4를 c에 저장. c = 4.

 

5) printf("%d, %d\n", b, c);

 : b, c의 값을 정수로 출력하면 6, 4

 

[출력]

6, 4

 

 

 

 

 

! 강의 보며 혼자 공부한 것으로,

틀린 거 있을 시 댓글로 가르쳐주시면 감사하겠습니다!