본문 바로가기

Studying/정보처리기사

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

31번

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

int main(int argc, char* argv[]) {
	int n, i;
	char p[] = "korea seoul";
	n = strlen(p);
	for (i = n - 1; i >= 0; i--)
		printf("%c", p[i]);
	printf("%d", n);
		
		return 0;
}

 

문자열 출력과 그 문자열의 길이를 출력하는 코드

 

1) #include<string.h>

 : strlen 함수 사용하기 위해 헤더 포함.

 

2) int n, j;

 : 정수형 변수 n, j 선언.

 

3) char p[] = "korea seoul";

 : 문자열 배열 p 선언하면서 초기화. 배열의 크기는 마지막에 널문자(\0)가 자동으로 포함되므로 11 + 1 = 12.

p k o r e a   s e o u l \0
  p[0] p[1] p[2] p[3] p[4] p[5] p[6] p[[7] p[8] p[9] p[10] p[11]

 

4) n = strlen(p);

 : 문자열 p의 길이를 계산해서 n에 저장. 문자열 p는 공백 포함하여 11이므로 n = 11.

 

 ⊙ 배열 크기 : 12

 ⊙ 문자열 길이 : 11

 

5) for문

 : for(i = 10; i >= 0; i--)은 문자열 p를 역순으로 출력하는 반복문. i는 10부터 시작하여 0보다 크거나 같을 때까지 하나씩 감소하며 실행.

 

6) printf("%c", p[i]);

 : 마지막 문자부터 첫 번째 문자까지 역순으로 출력.

 

7) printf("%d", n);

 : for문의 루프가 종료된 후 문자열 길이를 출력.

 

[출력]

luoes aerok11

32번

#include<stdio.h>

void main() {
	int a[] = { 2, 4, 6, 8, 10 };
	int b[] = { 1, 2, 3, 4, 5 };

	int *ap = a, * bp = b + 2, c, d;
	c = *(ap++);
	d = *(++bp);
	printf("%d, %d, %d, %d\n", *ap, c, *bp, d);
}

 

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

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

a는 100번지, b는 200번지로 시작한다고 가정하자.

a   2 4 6 8 10
100   100 101 102 103 104
b   1 2 3 4 5
200   200 201 202 203 204

 

2) int *ap = a;

 : a는 현재 100번지를 가리키고 그것을 포인터변수 ap에 저장하하므로 ap는 100번지를 가리키고 있음.

 

3) int *bp = b + 2;

 : b는 현재 200번지를 가리키고 있고, +2를 하면 202번지고 그것을 포인터변수 bp에 저장하므로 bp는 202번지를 가리키고 있음.

 

4) int c, d;

 : 정수형 변수 c, d선언

 

5) c = *(ap++);

 : *(ap++)는 괄호가 우선순위 높다고 안에 것을 먼저 계산하는 것이 아닌 *ap를  출력 후 ++ 연산을 해줘야 함. 즉 *ap는 현재 100번지를 가리키고 그 공간의 값은 2이므로 2를 변수 c에 저장하고 *ap는 ++ 연산을 하여 100번지가 아닌 101번지의 공간을 가리킴. (c = 2, ap는 101번지)

 

5) d = *(++bp);

 : *(++bp)는 bp가 현재 202번지를 가리키므로 ++가 앞에 있으므로 먼저 ++를 해주면 203번지를 가리키고 그 공간의 값을 변수 d에 저장함. 따라서 변수 d는 203번지가 가리키는 값인 4를 저장. (d = 4, bp는 203번지)

 

6) printf("%d, %d, %d, %d\n", *ap, c, *bp, d);

 : *ap, c, *bp, d 값을 정수로 출력하면 4, 2, 4, 4

 

[출력]

4, 2, 4, 4

여기서 잠깐

헷갈릴 수 있으니 한 번 정리하고 가기.

#include<stdio.h>

void main() {
	int code[] = { 10, 20, 30, 40, 50, 60 };
	int* p = &code;

	printf("%d ", ++*p);
	printf("%d ", ++(*p));
	printf("%d ", (*p)++);
	printf("%d\n", *p);

	printf("%d ", *p++);
	printf("%d ", *++p);
	printf("%d\n", *p);

	printf("%d ", *(p++));
	printf("%d ", *(++p));
	printf("%d\n", *p);
}

 

1) int code[] = { 10, 20, 30, 40, 50, 60 };

 : 정수형 배열 code 선언 하면서 초기화. (code의 첫 번째 공간을 100번지로 가정.)

code   10 20 30 40 50 60
100   100 101 102 103 104 105

2) int *p = &code;

 : 포인터 배열 p에는 code의 주소값인 100번지를 저장.

 

3) 출력

     ① ++*p : p는 100번지를 저장하고 있으므로 그 주소값의 값인 10에 ++연산(1 + 10) 하면 11을 출력. (*p + 1이랑 같은 의미)

                      100번지에는 10이 아닌 11로 변경.

     ② ++(*p) : 위와 같은 의미. 따라서 현재 100번지는 11을 가지고 있으므로 ++연산(1 + 11)을 하면 12를 출력.

                        현재 100번지는 11이 아닌 12로 변경.

     ③ (*p)++ : 잘 알아둬야 함! p의 주소값 100번지의 12를 출력 후 ++ 연산(12 + 1)하면 100번지 공간13으로 변경.

                        ☞ 해당하는 값이 변경!

     ④ *p : 현재 p의 주소값은 100번지로, 100번지의 값은 13을 출력.

 

4) 출력

     ① *p++ : 잘 알아둬야 함! p의 주소값 100번지의 13을 출력  후 ++ 연산을 함.

                      이 때 그 공간의 값이 아닌 p가 가지고 있는 주소값이 ++ 연산 되는 것. 따라서 100번지에서 101번지로 변경. (p는 101번지)

                      ☞ 해당하는 주소값(공간)이 변경!

     ② *++p : p의 주소값에서 ++연산 후 그 값을 구하는 것.

                      p는 101번지를 저장하고 있으므로 ++연산하면 102번지로 변경하고 그 값인 30을 출력. (p는 102번지)

     ③ *p : 현재 p의 주소값의 값을 출력. 현재 102번지로, 102번지의 값은 30을 출력. (p는 102번지)

 

5) 출력

     ① *(p++) : p의 주소값을 ++하기 전 그 값을 구 한 후, p의 주소값을 ++연산.

                        현재 p는 102번지로, 102번지의 값 30을 출력 후 p의 주소값은 ++연산하면 103번지. (p는 103번지)

     ② *(++p) : p의 주소값을 ++연산 후 그 주소값의 값을 구함.

                        현재 p는 103번지를 가지고 있고 ++연산하면 104번지의 주소값을 가지고 있음. 그 주소값의 값은 50을 출력. (p는 104번지)

      ③ *p : 현재 p의 주소값의 값을 출력. 현재 104번지로, 104번지의 값은 50을 출력. (p는 104번지)

 

[출력값]

11 12 12 13
13 30 30
30 50 50

33번

#include<stdio.h>

void main() {
	char a[30] = { "ENG\0INE\0AC" };
	char (*p)[5];
	p = a;
	printf("%s, ", p);
	printf("%s ", ++p);
	printf("%s", ++p);
}

 

1) char a[30] = { "ENG\0INE\0AC" };

 : 길이 30인 문자열 배열 a 선언하면서 초기화. 여기서 문자열들은 NULL(\0) 문자를 만나면 해당 문자열이 종료.

   a의 시작 주소를 100번지로 가정. 

 

2) char (*p)[5];

 : 문자열 배열 가리키는 포인터 p를 선언. p는 길이가 5인 문자열을 가리킴.

P E N G \0 I
  N E \0 A C

 

3) p = a;

 : 포인터 p는 문자열 배열 a의 시작 주소로 초기화.

  ⊙ p : 100번지

  ⊙ p[0] = "ENG\0I" → 100번지

  ⊙ p[1] = "NE\0AC" →101번지

 

4) 출력

 ① printf("%s, ", p);

     : p가 현재 100번지고 문자열은 NULL을 만나면 종료되기 때문에 100번지인 ENG\0I에서 NULL 문자 전인 ENG만 출력. (p는 100번지)

 ② printf("%s ", ++p);

     : ++p를 사용하여 현재 p의 주소값 100번지를 101번지로 증가시켜 해당 문자열을 출력. NULL 문자 전인 NE 출력. (p는 101번지)

 ③ printf("%s", ++p);

     : ++p를 사용하여 현재 p의 주소값 101번지를 102번지로 증가하고 해당 문자열을 출력. (p는 102번지)

       하지만 p가 가리키는 주소값의 문자열은 없으므로 아무것도 출력하지 않음.

 

[출력]

ENG, NE

34번

#include<stdio.h>

void main() {
	char *p[3] = { "ENG", "INER", "AC" };
	printf("%c, %c, %c\n", *p[0], *p[1], *p[2]);
	printf("%s, %s, %s\n", p[0] + 1, p[1] + 1, p[2] + 1);
}

 

1) char *p[3] = { "ENG", "INER", "AC" };

 : 세 개의 문자열 가리키는 포인터 배열 선언하면서 초기화.

  ⊙ p[0] = "ENG"

  ⊙ p[1] = "INER"

  ⊙ p[2] = "AC"

  p[0] E N G  
p p[1] I N E R
100 p[2] A C    

 

2) printf("%c, %c, %c\n", *p[0], *p[1], *p[2]);

   ① *p[0] : "ENG" 문자열의 첫 번째 문자를 가리키므로 'E' 출력.

                   = *(p + 0) = *(*(p + 0) + 0) = p[0][0]   // 0행 0열 가리킴

   ② *p[1] : "INER" 문자열의 첫 번째 문자를 가리키므로 'I' 출력.

                   =*(p + 1) = *(*(p + 1) + 0) = p[1][0]   // 1행 0열 가리킴

   ③ *p[2] : "AC" 문자열의 첫 번째 문자를 가리키므로 'A' 출력.

                   =*(p + 2) = *(*(p + 1) + 0) = p[2][0]   // 2행 0열 가리킴

3) printf("%s, %s, %s\n", p[0] + 1, p[1] + 1, p[2] + 1);

   ① p[0] + 1 : "ENG" 문자열의 두 번째 문자부터 끝까지 출력. (\0을 만나기 전까지 출력.) 따라서 "NG" 출력.

   ② p[1] + 1 : "INER" 문자열의 두 번째 문자부터 끝까지 출력. (\0을 만나기 전까지 출력.) 따라서 "NER" 출력.

   ③ p[2] + 1 : "AC" 문자열의 두 번째 문자부터 끝까지 출력. (\0을 만나기 전까지 출력.) 따라서 "C" 출력.

⊙ %c는 "character"를 나타냄. 하나의 문자를 출력하는데 사용. 따라서 문자 값 자체를 출력.

⊙ %s는 "String"을 나타냄. 문자열을 출력하는데 사용. 따라서 문자열의 시작주소부터 NULL 문자를 만나기 전까지 출력.

 

[출력]

E, I, A
NG, NER, C

35번

#include<stdio.h>

int main(int argc, char* argv[]) {
	int i, a[5] = { 10, 25, 30, 40, 80 };
	void *p = a + 2;
	*(int *)p += 12;
	*((int *)p + 2) += 2;
	for (i = 0; i < 5; i++)
		printf("%d ", a[i]);
}

 

1) int i, a[5] = { 10, 25, 30, 40, 80 };

 : 정수형 변수 i 선언. 길이가 5인 정수형 배열 a 선언하면서 초기화.

a   10 25 30 40 80
100   100 101 102 103 104

 

2) void *p = a + 2;

 : 포인터 변수 p는 배열의 세 번째 요소인 a[2]의 주소를 가리킴. 즉 a는 현재 100번지로 100 + 2 = 102번지를 가리킴.

 

3) *(int *)p += 12;

 : p를 int 포인터로 캐스팅하고 해당 위치의 값을 12 증가시킴. *p는 a[2]의 값이므로 30 + 12 = 42의 값으로 변경됨.

 

4) *((int *)p + 2) += 2;

 : p + 2를 int 포인터로 캐스팅하고 해당 위치의 값을 2 증가시킴. p + 2는 p는 현재 a[2]이고, +2하면 a[4]를 가리킴. 따라서 a[4]의 값인 80을 +2하면 82의 값으로 변경됨.

 

5) for문

 : 배열 a의 각 요소를 출력함.

a   10 25 42 40 82
100   100 101 102 103 104

 

[출력]

10 25 42 40 82

36번

#include<stdio.h>

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

 

1) int a[2][3] = { {-3, 14, 5}, {1, -10, 8} };

 : 2차원 정수 배열 a 선언하면서 초기화. 첫 번째 시작 위치를 100번지로 가정.

    ⊙ a : 100번지 → a는 100번지인 -3을 가리키는 것이 아닌 a[0]인 100번지를 가리키는 것

    ⊙ a[0] : 100번지(-3, 14, 5) → -3 : 100번지 / 14 : 101번지 / 5 : 102번지

    ⊙ a[1] : 103번지(1, -10, 8) → 1 : 103번지 / -10 : 104번지 / 8 : 105번지

a a[0]
(100)
-3
(100)
14
(101)
5
(102)
100 a[1]
(103)
1
(103)
-10
(104)
8
(105)

 

2) int* b[] = { a[0], a[1] };

 : 포인터 배열 b 선언하면서 배열 a의 각 행의 시작 주소를 가리키도록 초기화.

    ⊙ b[0] = a[0] = {-3, 14, 5}

    b[1] = a[1] = {1, -10, 8}

 

3) int *p = b[1];

 : 포인터 p는 b[1]을 가리키므로 p는 a[1]을 가리킴. 즉 p는 {-1, 10, 8}을 가리킴.

 

4) 출력

 ① printf("%d, ", *b[1]);

  : b[1]은 a[1]을 가리키므로 {1, -10, 8}의 첫 번째 요소 a[1][0]인 1을 출력. 따라서 *b[1] = 1.

    (b[1]은 a[1]를 가리키고 a[1]은 103번지를 나타내므로 103번지의 값인 1을 출력)

 ② printf("%d, ", *(--p - 2));

   : p는 현재 b[1]인 a[1]을 가리키고 a[1]은 103번지를 가리킴. -- 연산하면 102번지 가리키고 -2를 하면 100번지를 가리킴. 따라서 100번지의 값인 -3을 출력.

     p는 b[1] 즉 a[1]을 가리키고 있었으므로, -- 연산하면 p는 b[0] 즉 a[0]을 가리킴. 왼쪽으로 -2 하면 -3을 출력 : a[0][0]의 값

 ③ printf("%d\n", *(*(a + 1) + 1));

   : 현재 a는 100번지를 가리키지만 100번지인 -3을 가리키는 것이 아닌 행 대표 주소 a[0]을 가리키고 +1을 하면 a[0]이 아닌 a[1]을 가리킴.

     *(a + 1)은 a[1]의 공간의 값으로 해석되고 103번지를 의미함.

     *(103번지 + 1)은 *(104번지) 계산되고, 104번지의 값은 -10이므로 -10을 출력.

③ *(*(a + 1) + 1)

 

1) *(*(a + 1) + 1)  : a는 현재 a[0]의 100번지를 가리킴. 따라서 +1을 하면 a는 a[0], a[1]의 행을 가지고 있으므로 a[0] 다음인 a[1]을 의미.

2) *(*(a + 1) + 1) : a + 1은 a[1]을 의미하고 앞에 *을 붙이면 a[1]의 값을 의미하므로 a[1]은 103번지를 가리키므로 103번지를 의미.

3) *(*(a + 1) + 1) : 103번지 + 1 = 104번지를 의미.

4) *(*(a + 1) + 1) : 104번지 앞에 *을 붙이면 104번지의 값을 의미하므로 -10을 출력.

 

[출력]

1, -3, -10

37번

#include<stdio.h>
int main()
{
	int a[2][3][5] = {
		{
			{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}
		} };
	printf("%d\n", *(*(*(a + 1) + 2) + 3) + *(**a + 2) + *(**(a + 1) + 2));
	return 0;
}

 

1) 3차원 배열 

 : 3차원 정수 배열 a 선언 하면서 초기화. a의 첫 번째 주소를 100번지로 가정. (면, 행, 열)

a
(100)
a[0]
(100)
a[0][0]
(100)
1
(100)
2
(101)
3
(102)
4
(103)
5
(104)
    a[0][1]
(105)
6
(105)
7
(106)
8
(107)
9
(108)
10
(109)
    a[0][2]
(110)
11
(110)
12
(111)
13
(112)
14
(113)
15
(114)
  a[1]
(115)
a[1][0]
(115)
16
(115)
17
(116)
18
(117)
19
(118)
20
(119)
    a[1][1]
(120)
21
(120)
22
(121)
23
(122)
24
(123)
25
(124)
    a[1][2]
(125)
26
(125)
27
(126)
28
(127)
29
(128)
30
(129)

 

2) printf("%d\n", *(*(*(a + 1) + 2) + 3) + *(**a + 2) + *(**(a + 1) + 2));

 *(*(*(a + 1) + 2) + 3)

    ⅰ. (a + 1) : a는 a[0]을 가리키고 있으며 a + 1은  a[1]을 의미. (a[0], a[1]의 면으로 이루어져 있으므로)

    ⅱ. *(a + 1) : a[1]의 값은 a[1][0]을 의미. (a[1]은 a[1][0]의 대표주소이므로)

    ⅲ. *(a + 1) + 2 : a[1][0]에서 +2를 하면 a[1][2]를 의미. (a[1][0], a[1][1], a[1][2]의 행으로 이루어져 있으므로)

    ⅳ. *( *(a + 1) + 2) : a[1][2]의 값은 125번지를 가리킴.

    ⅴ. *(*(a + 1) + 2) + 3 : 125번지 + 3 = 128번지를 의미.

    ⅵ. *(*(*(a + 1) + 2) + 3) : 128번지의 값은 29를 의미하므로 29를 출력.

 

 ② *(**a + 2) 

    ⅰ. **a : a가 가리키는 100번지 공간은 a[0](a의 값)을 가리키고 a[0]이 가리키는 100번지 공간은 a[0][0](a의 값의 값)을 가리킴.

                  따라서 a의 값의 값은 a[0][0]인 100번지를 의미.

    ⅱ. **a + 2 : a[0][0]은 100번지를 의미하고 +2를 하면 102번지를 의미.

    ⅲ. *(**a + 2) : 102번지의 값은 3을 의미하므로 3을 출력.

 

*(**(a + 1) + 2)

    ⅰ. a + 1 : a는 a[0]을 가리키고 +1을 하면 a[1]을 의미.

    ⅱ. **(a + 1) : a+1의 값의 값은 a[1]인 115번지의 값은 a[1][0]인 115번지를 의미.

    ⅲ. **(a + 1) + 2 : 115번지 + 2를 하면 117번지를 의미.

    ⅳ. *(**(a + 1) + 2) : 117번지의 값은 18을 의미하므로 18을 출력.

 

따라서 29 + 3 + 18 = 50을 출력하게 됨. 헷갈리면 표를 그려서 100번지 시작을 가정하여 면, 행 대표주소를 작성하며 생각해보자.

 

[출력]

50

38번

#include<stdio.h>

int main(int argc, char* argv[]) {
	int i = 10, *ip = &i;
	char c = 'D', *cp = &c;

	*ip++ = ++i;
	++*--ip;
	++*cp++;
	*--cp = c + 3;

	printf("i= %d, c = %c\n", i, c);
	return 0;
}

 

1) int i = 10, *ip = &i;

 : 정수형 변수 i를 선언하면서 10으로 초기화하고, ip는 i의 주소값을 가리키는 포인터 변수.

 

2) char c = 'D', * cp = &c;

 : 문자 변수 c를 선언하면서 'D'로 초기화하고, cp는 c의 주소값을 가리키는 포인터 변수.

 

3) 연산

 ① *ip++ = ++i;

   ⅰ.++i : 계산하면 i는 ++ 연산하여 10에서 11로 증가. (i = 11)

   ⅱ. *ip++는 ip가 가리키는 위치(i)에 ++i 값을 할당한 후, ip는 후위 증감 연산으로 ip + 1이 되어 다른 주소값을 가리킴.

   ⅲ. 따라서 i의 값은 11이고, ip는 i가 아닌 다른 주소값을 가리킴.

 

 ② ++*--ip;

   ⅰ. --ip : 계산하면 ip는 -- 연산하여 다시 i의 주소값을 가리킴.

   ⅱ. *--ip : i의 주소값의 값을 의미하므로 11을 의미.

   ⅲ. ++*--ip : 11은 ++연산하여 12를 의미. 따라서 i = 12

 

 ③ ++*cp++;

   ⅰ. cp++ : cp가 가리키는 곳을 참조(c = 'D')하고, 이후 cp는 다음 주소값을 가리킴.

   ⅱ.  ++*cp : cp가 가리키는 c값을 ++연산 하면 c = 'E'로 변경.

 

 ④ *--cp = c + 3;

   ⅰ. --cp : 계산하면 cp는 -- 연산하여 다시 c의 주소값을 가리킴.

   ⅱ. *--cp : c의 주소값의 값을 의미하므로 'E'를 의미.

   ⅲ. c + 3 : 현재 c는 E를 의미하므로 +3을 하면 E, F, G, H 즉 'H'로 변경

 

따라서 i = 12, c = 'H'를 출력하게 됨.

 

[출력]

i= 12, c = H

 

 

 

 

 

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

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