[정보처리기사/예상문제] - 2023 정보처리기사 실기 예상 문제 모음
C언어 기출문제 모음
비전공자용 C언어 요약 1탄
비전공자용 C언어 요약 2탄(조건문, 반복문, 배열)
비전공자용 C언어 요약 3탄(함수, 포인터)
비전공자용 C언어 요약 4탄(포인터 심화, 구조체)


목차
1. 포인터와 1차원 배열
2. 포인터와 2차원 배열
3. 포인터와 문자 배열
4. 포인터와 문자열 배열
5. 함수 심화(Call by Value, Call by Reference)
6. 구조체


1. 포인터와 1차원 배열
우선 배열의 이름은 배열의 시작주소이다.
 
아래 예문을 보자.

#include <stdio.h>

int main() {
	int array[3] = { 10,20,30 };
    printf("%x %x %x \n", array, array + 0, &array[0]);  //배열 0번째 요소의 주소 출력
	printf("%d %d %d \n", *array, *(array + 0), *&array[0]);  //배열 0번째 요소의 값 10 출력
}

*array는 array(배열 이름) 주소가 가리키는 값인 10이 출력된다
*(array+0)은 array주소에 0칸 이동한 주소가 가리키는 값인 10이 출력된다
*&가 동시에 있으면 생략이 가능하다.
즉 *&arr[0]=array[0] 따라서 역시 배열의 0번째 인덱스인 10이 출력된다
 
결국 array==array+0==&array[0]이라는 의미이다
 
다만 여기서 주의점은 int형 배열이라 요소 1개의 크기는 4바이트이고 array,array+0, &array[0]으로 출력되는 값은 동일하지만 array만 0번째 요소가 아니라 배열 전체를 가리키기 때문에 12바이트(int형이 3칸있으니 12바이트)가 된다
 
다음과 같이 포인터변수 p에 array(배열이름)으로 배열의 시작주소를 저장하면 포인터변수를 배열처럼 사용할 수 있다
아래 예문은 위의 예문과 결과값이 100% 동일하다

#include <stdio.h>

int main() {
	int array[3] = { 10,20,30 };
	int* p = array; //포인터 변수에 배열의 시작 주소를 저장

	printf("%x %x %x \n",p,p+0,&p[0]); //배열 0번째 요소의 주소 출력
	printf("%d %d %d \n", *p,*(p+0),*&p[0]); //배열 0번째 요소의 값 출력
}

 
다 필요없고 위 같은 경우 포인터변수 p랑 array랑 똑같다고 생각해주면 된다


2. 포인터와 2차원 배열
1차원배열에서는 *(array+i)==array[i]==*&array[i]는 값이라고 배웠는데
2차원 배열에서는  *(array+i)==array[i]==*&array[i]가 주소를 가리킨다
 
int array[2][3] = { 10,20,30,40,50,60 }라는 2차원 배열이 있을 때 테이블 같은 구조를 연상하지만 실제는 일직선으로 나란히 돼있는 것을 일단 상기시키고 가보도록 하자.

2차원배열에서도 1차원배열에서 처럼 &array[0][0] 이런식으로 하면 각 배열의 요소의 주소, *&array[0][0] 하면 각 배열의 요소의 값이 잘 출력된다.
 
그렇다면 아래 예문은 어떤 결과가 나올까? 

#include <stdio.h>

int main() {
	int array[2][3] = { 10,20,30,40,50,60 };

	(1)printf("%x\n", array);  
	(2)printf("%x\n", array[0]);
	(3)printf("%x\n", *(array + 0));
	(4)printf("%x\n", &array[0][0]);
    
	(5)printf("%x\n", array+1);
	(6)printf("%x\n", array[1]);
	(7)printf("%x\n", *(array + 1));
	(8)printf("%x\n", &array[1][0]);
    
    
    (9)printf("%d\n",sizeof(&array[0][0]));  //4 출력(32비트 운영체제의 경우)
    //64비트 운영체제의 경우 8로 출력된다
    
	(10)printf("%d\n", sizeof(array[0]));  //12 출력
    (11)printf("%d\n", sizeof(array));  //24 출력
}

(1)~(4)까지는 array[0][0]의 주소를 출력하고
(5)~(8)까지는 array[1][0]의 주소를 출력한다
 
결과값은 동일하지만 4번과 8번의 경우는 arr[0][0], array[1][0] 처럼 특정한 요소의 주소를 가리키지만 나머지는 아래 그림과 같이 특정행을 가리킨다. 
따라서 (9)는 특정요소를 가리키므로 4가 출력되고 (10)은 행을 가리키므로 12가 출력되고 (11)은 배열 전체를 가리켜서 24가 출력된다 

 
*(array + 0)이 형태만 조금 더 살펴 보자
먼저 array는 배열 전체를 가리키지만 위치는 array[0][0] 시작주소에 가 있다

두번째 *(array+0)는 array에서 +0한 곳의 값을 읽는 것인데 2차원배열에서는 이 값이 행의 주소를 가리킨다
배열에서 특정 행을 가리키지만 위치는 array[0][0] 시작주소에 가 있다

세번째 array[0]+0은 배열에서 특정 행의 특정 요소 가리키지만 역시 위치는 array[0][0] 시작주소에 가 있다
따라서 

모두 출력되는 값은 동일하지만 크기는 다르다
이해한 것을 토대로 아래 출력결과를 예상해보자.

#include <stdio.h>

int main() {
	int array[2][3] = { 10,20,30,40,50,60 };

	(1)printf("%d\n", sizeof(array));
	(2)printf("%d\n", sizeof(array[0]+0));
	(3)printf("%d\n", sizeof(*(array + 0)));
	(4)printf("%d\n", sizeof( & array[0][0])); 
    }
정답보기

(1)은 array가 배열의 전체를 가리키므로 24

(2)는 array[0]이 2차원배열의 0번째 행을 가리키고 0번째 행의 0번째 요소를 가리키므로 4출력

(3)는 array는 배열의 전체를 가리키지만 array+0을 함으로써 0번째 행을 가리키게 돼 12가 출력된다(2차원 배열에서는 배열이름의 주소에 대한 값이 특정행의 주소를 가리키게 된다)

(4)는 0행 0열의 주소를 가리키므로 4가 출력된다

#include <stdio.h>

int main() {
	int array[2][3] = { 10,20,30,40,50,60 };

	printf("%d\n", sizeof(array));  //24출력
	printf("%d\n", sizeof(array[0]+0)); //4출력(32비트 운영체제 기준)
    //64비트 운영체제의 경우 8로 출력된다
    
	printf("%d\n", sizeof(*(array + 0))); //12출력
	printf("%d\n", sizeof( &array[0][0])); //4출력(32비트 운영체제 기준)
    //64비트 운영체제의 경우 8로 출력된다
    }
사진 출처 : C언어본색-박정민

 
하나도 이해가 안된다면 그냥 외우면된다.
1차원 배열에서는 값을 가리켰던 녀석들이 2차원 배열에서는 주소를 가리키는 것이다
 
 
1차원 배열과 동일하게 2차원 배열도 포인터를 써서 똑같이 쓸 수 있지 않을까? 생각할 수있지만 아래처럼 코드를 짜면 에러가 난다. int *p는 1차원 포인터 변수이므로 2차원 배열을 저장해도 1차원처럼 작동되기 때문이다.
따라서 이 경우에 필요한 것이 바로 배열 포인터이다.

#include <stdio.h>

int main() {
	int array[2][3] = { 10,20,30,40,50,60 };
	int* p = array;
	printf("%d\n",p[0][0]);

	return 0;
}

 
2-1.배열 포인터
배열 포인터는 배열을 가리키는 포인터 변수이다.
배열 포인터는 다음과 같이 선언한다.

앞에 int는 자료형이고 (*p)는 배열 포인터 변수 이름이고 [3]은 열 길이이다
이렇게 배열포인터로 선언을 하면 2차원 배열처럼 포인터도 접근할 수 있게 된다

#include <stdio.h>

int main() {
	int array[2][3] = { 10,20,30,40,50,60 };
	int(* p)[3] = array; //포인터 변수에 배열의 시작 주소를 저장
	printf("%d\n", array[0][0]);
	printf("%d\n",p[0][0]);

	return 0;
}

 
2-2 포인터 배열
주소를 저장하는 배열
 
포인터 배열은 다음과 같이 선언한다

앞에 int*는 자료형이고 pointer는 포인터배열 변수 이름이고 [3]은 배열 길이이다

#include <stdio.h>

int main() {
	int a = 10, b = 20, c = 30;
	int* p[3] = {&a,&b,&c};
	printf("%d\n", *p[0]);
	printf("%d\n", *p[1]);
	printf("%d\n", *p[2]);
	printf("%d\n", **(p+0));
	printf("%d\n", **(p+1));
	printf("%d\n", **(p+2));

	return 0;
}

 

정답보기

p[0]에 주소가 들어있으니 *p[0]은 그 주소의 값 따라서 10

나머지도 마찬가지

 

p는 배열의 이름이니 배열의 시작주소인데 +0으로 p의 0번째 요소가 선택되고 0번째요소의 값의 값이니 10이 된다

#include <stdio.h>

int main() {
	int a = 10, b = 20, c = 30;
	int* p[3] = {&a,&b,&c};
	printf("%d\n", *p[0]); //10
	printf("%d\n", *p[1]);  //20
	printf("%d\n", *p[2]);  //30
	printf("%d\n", **(p+0)); //10
	printf("%d\n", **(p+1)); //20
	printf("%d\n", **(p+2));  //30

	return 0;
}

3. 포인터와 문자 배열
문자배열은 그냥 1차원 배열과 포인터 개념과 동일하다
 
아래 예문을 보자.

#include <stdio.h>

int main() {
	char array[3] = { 'A','B','C'};
	char* p = array; //포인터 변수에 배열의 시작 주소를 저장
	printf("%x %x %x \n", array, array + 0, &array[0]);  //배열 0번째 요소의 주소 출력
	printf("%c %c %c \n", *array, *(array + 0), *&array[0]);  //뱌욜 0번째 요소의 값 A 출력

	printf("%x %x %x \n", p, p + 0, &p[0]); //배열 0번째 요소의 주소 출력
	printf("%c %c %c \n", *p, *(p + 0), *&p[0]); //배열 0번째 요소의 값 A 출력
	
}

 
다 필요없고 위 같은 경우 포인터변수 p랑 array랑 똑같다고 생각해주면 된다


 
4. 포인터와 문자열 배열
C언어에서 문자열이란 큰 따옴표 내에 포함된 하나 이상의 문자를 의미하며 문자열의 맨 끝에는 문자열의 끝을 알리는 종료 문자 '\0'이 삽입되어 있으며 이런 종료 문자를 널(Null) 문자라 한다
 
문자열은 문자들이 메모리 공간에 연속적으로 저장되어 있어서 보통 주소로 관리되며 문자열을 출력할 때는 서식 문자 %s를 쓴다문자열은 문자들의 집합이므로 문자의 배열이라고 생각할 수 있다
 
아래 결과를 예상 해보자.

#include <stdio.h>

int main() {
	char array[4] = "ABC";
	printf("%c%c%c\n", array[0], array[1], array[2]);
	printf("%s", array);
	printf("%d %d %d\n", array[0], array[1], array[2]);
	return 0;
}
정답보기

A를 %d로 출력하면 A의 아스키코드인 65가 출력된다

#include <stdio.h>

int main() {
	char array[4] = "ABC";
	printf("%c%c%c\n", array[0], array[1], array[2]); //ABC 출력
	printf("%s\n", array); //ABC 출력
	printf("%d %d %d\n", array[0], array[1], array[2]); //65 66 67 출력
	return 0;
}

 
다음 결과도 예상해보자.

#include <stdio.h>

int main() {
	char array[4] = "ABC";
	printf("%s\n", array);
	printf("%s\n", array+1);
	printf("%s\n", array+2);
	return 0;
}
정답보기

array일때는 전체를 가리켜서 ABC가 출력

array+1일때는 arr[1]번째 시작주소를 가리켜서 BC

array+2일때는 array[2]번째 시작주소를 가리켜서 C

#include <stdio.h>

int main() {
	char array[4] = "ABC";
	printf("%s\n", array);  //ABC 출력
	printf("%s\n", array+1); //BC 출력
	printf("%s\n", array+2);  //C 출력
	return 0;
}

 
이런 문자열을 배열이 아니라 포인터로 바꾸면 아래와 같다

#include <stdio.h>

int main() {
	char array[4] = "ABC"; //배열 방식
	printf("%s\n", array);
	printf("%s\n", array+1);
	printf("%s\n", array+2);

	char* p = "ABC";  //포인터방식
	printf("%s\n", p);
	printf("%s\n", p + 1);
	printf("%s\n", p + 2);
	return 0;
}

5. 함수 심화(Call by Value, Call by Reference)
 
함수에서 이때 까지 사용했던 방식이 Call my Value인데 그것은 값을 복사하는 방식이다.

#include <stdio.h>
int func(int);
int main() {
	int a = 10;
	printf("%d\n",func(a));  //11출력
    printf("%d\n",a);  //10출력
	return 0;
}


int func(int a) {
	a = a + 1;
	return a;
}

 
main 함수에서 변수 a를 선언하면서 초기화 한 후 a변수를 인수로 전달하면서 매개변수 a로 값이 복사된다
값을 복사하는 방식으로 main()함수의 지역변수 a 값 변동에는 영향을 미치지 않는다

다음은 새로 배우게 될 Call by Reference(주소 참조) 방식이다
주소를 인수로 받아서 값을 바꾸기 때문에 main()함수의 지역변수 a에도 영향을 미친다

#include <stdio.h>
int func(int);
int main() {
	int a = 10;
	printf("%d\n",func(&a)); //11 출력
	printf("%d", a);  //11 출력
	return 0;
}


int func(int* a) {
	*a = *a + 1;
	return *a;
}

int func(int* a)인 이유는 주소를 전달받기 때문이다
쉽게 생각해서 포인터변수를 선언할 때 int *p=&a; 이런식으로 선언하는 것을 생각하면 된다
주소를 받기 때문에 함수의 매개변수 형태가 포인터변수가 되는 것이다
 


6. 구조체
하나 이상의 변수를 묶어 그룹화하는 사용자 정의 자료형이다
배열이 같은 자료형만 담을 수 있다면 구조체는 다른 자료형도 담을 수 있다
 
아래와 같은 형식으로 구조체를 정의한다
struct : 구조체 키워드
student : 구조체 이름
 
int score, char name은 구조체 멤버 변수

struct student
{
	int score;
	char name;
};

구조체 정의를 하고 구조체 변수 선언을 동시에 하는 방법은 아래와 같다.

struct student
{
	int score;
	char name;
}p1, p2, p3;

 
따로 선언하는 방식은 아래와 같다.

#include<stdio.h>
struct student
{
	int score;
	char name;
};

int main(){
	struct student p1, p2, p3;


return 0;
}

 
구조체 변수에 .(도트 연산자)를 이용하면 각 변수별 멤버변수에 접근할 수 있다
p1.score이라고 하면 p1의 score에 접근이 가능해지며
p1.score=30; 이라고 하면 p1.score 자리에 30이 저장된다

#include<stdio.h>
struct student
{
	int score;
	char name;
};

int main(){
	struct student p1, p2, p3;
	p1.score = 30;
	printf("%d", p1.score);  //30출력

return 0;
}

 
6-1 구조체와 배열
멤버변수로 배열도 사용 가능하다
 
학생 수가 많아지면 구조체 변수 p1,p2,p3가 무한히 많이 필요할 텐데 이런 문제를 해결하기 위해 구조체 변수를 배열로 사용하면 된다

#include<stdio.h>
struct student {
	char no[10];
	char name[20];
	double math;
	double english;
};

int main(){
	struct student stu[3] = {
		{"12345","Lee",90,90},
		{"12346","KIM",80,70},
		{"12347","Park",50,100}
	};

return 0;
}

 

 
6-2 구조체와 포인터

#include<stdio.h>
struct p {
	int* x;
	int* y;
};

int main(){
	int a = 5;
	int b = 4;
	struct p p1;
	p1.x = &a;
	p1.y = &b;

	printf("%d %d\n", a, b);
	printf("%d %d\n", *p1.x, *p1.y);

return 0;
}

출력결과를 예상해보자

 
 
구초제 변수로 포인터를 사용할 수 도 있다
구조체 변수로 포인터를 사용한다는 것은 구조체 변수에 간접 접근할 수 있다는 의미이다
 
(*p)를 한 이유는 .연산자가 *연산자보다 우선순위가 높아 *p를 먼저 연산하기 위함이다
p는 포인터변수인데 p가 구조체 변수 stu의 주소를 담고 있으므로 *p는 stu의 값을 가리킨다
->연산자는 포인터 변수만으로 구조체의 멤버 변수에 접근할 때 사용한다

#include<stdio.h>
struct student {
	char no[10];
	char name[20];
	double total;
};

int main(){
	struct student stu = {"12345","KIM",20};
	struct student* p = &stu;

	printf("%s %s %lf\n", (*p).no, (*p).name, (*p).total); //12345 KIM 20 출력
	printf("%s %s %lf\n", p->no, p->name, p->total);//12345 KIM 20 출력

return 0;
}

 
 
 
[정보처리기사/예상문제] - 2023 정보처리기사 실기 예상 문제 모음
C언어 기출문제 모음
비전공자용 C언어 요약 1탄
비전공자용 C언어 요약 2탄(조건문, 반복문, 배열)
비전공자용 C언어 요약 3탄(함수, 포인터)
비전공자용 C언어 요약 4탄(포인터 심화, 구조체)

+ Recent posts