2차원 데이터의 활용
A. 포인터의 배열 – 가로축으로는 가변 개수, 세로축으로는 고정 개수인 2차원 데이터를 다룰 때 사용합니다.
다뤄야 하는 문자열의 길이가 서로 다른 경우가 대부분이므로, 여러 개의 문자열을 묶어서 처리할 때 포인터의 배열을 사용하면 좋습니다.
char lesson1[7] = "Korean";
char lesson2[8] = "English";
char lesson3[5] = "Math";
이들을 한번에 묶어 2차원 배열로 만들면 다음과 같이 할 수 있습니다.
char lesson[3][8] = {"Korean", "English", "Math"};
저장하고자 하는 문자열은 제각각 크기가 다른데, 배열은 크기가 고정 되어야 하므로 가장 크기가 큰 8에 맞춰 통일을 한 것입니다. 따라서 이렇게 하면 배열의 일부 원소는 사용하지도 않는 메모리 공간을 낭비하게 됩니다.
K | O | R | E | A | N | \n |
|
E | n | G | L | I | S | H | \n |
M | A | T | H | \n |
|
|
|
문자열 상수를 각각 포인터로 가리키기만 하려면 다음과 같이 하면 됩니다.
char *lesson1 = "Korean";
char *lesson2 = "English";
char *lesson3 = "Math";
이들을 묶어 다음과 같이 포인터의 배열로 만들 수 있습니다.
char *lesson[3] = {"Korean", "English", "Math"};
이렇게 하면 크기가 3인 char*형 배열이 만들어지고, 각 원소가 문자 상수를 가리키도록 초기화됩니다.
지난 시간에 작성했던 성적처리 프로그램에 다음과 같은 코드를 추가하면 과목명이 출력됩니다.
#include <stdio.h>
#define LESSONS 3
int main(void)
{
int students; //학생수
int sum=0; //합계
int l, s; //for루프를위한임시변수
int score[][LESSONS] = {
{85,90,95},
{70,82,60},
{92,88,88},
{94,75,79},
{95,68,78},
{82,79,88},
{68,80,95},
{78,84,92}
};
char *lesson[] = {"Korean", "English", "Math"};
students = sizeof(score)/sizeof(score[0]);
for(l=0;l<LESSONS;l++)
{
sum = 0;
for(s=0;s<students;s++)
{
sum += score[s][l];
}
printf("[%7s] Total : %d, ", lesson[l], sum);
printf("Average : %0.2f\n", (double)sum/students);
}
getchar();
}
B. 배열의 포인터
가로축으로는 고정 개수, 세로축으로는 가변 개수인 2차원 데이터를 다룰 때 사용합니다. 위에 작성했던 성적처리 프로그램은 학생 8명에 대해 각각 3과목씩의 성적을 처리하도록 크기가 고정되어 있었는데, 3과목의 성적을 처리하되 학생 수는 몇 명이라도 처리할 수 있도록 변경 해 보겠습니다.
가로축으로는 고정 개수, 세로축으로는 가변 개수인 2차원 데이터를 다루는 문제이므로, 다음과 같이 배열 포인터를 사용합니다.
Int (*score)[3] = NULL;
프로그램 실행 중 학생 수가 결정되면 실제 데이터를 저장하는 부분에 해당하는 메모리를 다음과 같이 할당 받아 그 주소를 배열의 포인터에 저장합니다.
Score = (int (*)[3])malloc(sizeof(int [3])*students);
여기서 malloc으로 할당 받은 메모리의 주소를 배열의 포인터로 캐스트하기 위해 (int(*)[3])이라고 쓴 것을 주목해서 보시기 바랍니다. 캐스트할 때 변수 이름은 쓰지 않고 데이터 타입만 쓰기 때문에 변수 선언을 할 때 썼던 int (*score)[3]에서 변수 이름은 score를 빼고 int (*)[3]라고 쓴 것입니다. 이렇게 하면 int형 데이터를 가로로 3개, 세로로 students개만큼 저장할 수 있는 공간이 할당됩니다. 그리고 할당받은 메모리는 다 쓴 후 free 함수를 호출하여 반환합니다.
Free(score);
다음 코드를 보면, 배열의 포인터를 선언하고 malloc으로 할당 받는 부분은 달라졌지만 score[s][l]로 데이터의 원소를 사용하는 것은 2차원 배열을 사용할 때와 똑같음을 볼 수 있습니다.
#include <stdio.h>
#include <malloc.h>
#include <conio.h>
#define LESSONS 3
int main(void)
{
int students; //학생수
int sum=0; //합계
int l, s; //for루프를위한임시변수
char *lesson[] = {"Korean", "English", "Math"};
int (*score)[LESSONS] = NULL;
printf("학생수를입력하세요: ");
scanf("%d", &students);
printf("---------------------------------\n");
//메모리할당
score = (int (*)[LESSONS])malloc(sizeof(int [LESSONS])*students);
for(s=0;s<students;s++) //학생수만큼루프
{
printf("%d번째학생의점수: ", s+1);
for(l=0;l<LESSONS;l++) //과목수만큼루프
{
scanf("%d", &score[s][l]); //점수입력받음
}
}
printf("---------------------------------\n");
for(l=0;l<LESSONS;l++) //과목수만큼루프
{
sum = 0;
for(s=0;s<students;s++) //학생수만큼루프
{
sum += score[s][l]; //과목별총합계산
}
printf("[%7s] Total : %d, ", lesson[l], sum);
printf("Average : %0.2f\n", (double)sum/students);
}
free(score); //메모리해제
getch();
}
이 코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다. 학생 수와 학생별 점수는 직접 입력 한 것입니다.
C. 2차원 포인터
2차원 포인터는 가로축, 세로축 으로 모두 가변 개수인 2차원 데이터를 다룰 때 사용합니다.
이번에는 학생 수와 각 학생이 수강하는 과목 수가 모두 가변적인 성적처리 프로그램을 만들어 보겠습니다. 가로축, 세로축 모두 가변인 2차원 데이터를 다루는 문제이므로, 다음과 같이 2차원 포인터를 사용합니다.
Int **score;
프로그램 실행 중 세로축의 개수가 결정되면 malloc함수를 이용하여 세로축으로 데이터를 가리킬 포인터를 저장할 메모리 공간을 할당받습니다. 예를 들어 세로축으로 students개의 데이터를 저장해야 한다면 다음과 같이 메모리를 할당 받습니다.
Score = (int **)malloc(sizeof(int *)*students);
Int *형 데이터 students개를 저장할 수 있는 공간을 할당 받아 int **형으로 캐스트하여 score에 저장한 것으로 메미로를 할당 받습니다. 끝으로 세로축의 개수만큼 루프를 돌면서 다음과 같이 세로축의 길이에 해당하는 메모리를 할당 받습니다.
for(i=0;i<students;i++)
{
score[i] = (int *)malloc(sizeof(int) * lessons);
}
사용이 끝나면 메모리를 할당 받은 순서의 역순으로 메모리를 반납합니다. 즉, 먼저 가로축 방향으로 데이터를 저장하는 메모리를 반납합니다.
for(i=0;i<students;i++)
{
free(score[i]);
}
위의 것들을 적용해 보면 먼저, 사용자로부터 성적을 처리할 학생 수를 입력 받아 2차원 포인터의 세로 길이로 설정하고, 학생 수만큼 루프를 돌면서 각 학생이 수강하는 과목 수를 입력 받아 가로 길이를 설정합니다. 그런 다음 각 학생의 점수를 입력 받아 학생 별로 평균을 계산하여 화면에 출력합니다.
2차원 포인터의 경우도 포인터를 선언하고 malloc으로 할당 받는 부분은 달라졌지만, score[s][l]과 같은 형태로 데이터의 원소를 사용하는 것은 2차원 배열을 사용할 때와 똑같음을 볼 수 있습니다.
#include <stdio.h>
#include <malloc.h>
#include <conio.h>
#include <string.h>
#define LESSONS 3
int main(void)
{
int students; //학생수
int sum=0; //합계
int l, s; //for루프를위한임시변수
char *lessons = NULL;
int **score = NULL;
printf("학생수를입력하세요: ");
scanf("%d", &students);
printf("---------------------------------\n");
//세로축에해당하는메모리할당
score = (int **)malloc(sizeof(int *)*students);
lessons = (int *)malloc(sizeof(int)*students);
for(s=0;s<students;s++) //학생수만큼루프
{
printf("%d번째학생의수강과목수: ", s+1);
scanf("%d", &lessons[s]);
//가로축에해동하는메모리할당
score[s] = (int *)malloc(sizeof(int)*lessons[s]);
printf("%d번째학생의점수(%d)개: ", s+1, lessons[s]);
for(l=0;l<lessons[s];l++) //과목수만큼루프
{
scanf("%d", &score[s][l]); //점수입력
}
}
printf("---------------------------------\n");
for(s=0;s<students;s++) //학생수만큼루프
{
sum = 0;
for(l=0;l<lessons[s];l++)
{
sum += score[s][l]; //학생별평균계산
}
printf("%d번째학생: %0.2f\n", s+1, (double)sum/lessons[s]);
}
for(s=0;s<students;s++) //학생수만큼루프
{
free(score[s]); //가로축에해당하는메모리반납
}
free(score); //세로축에해당하는메모리반납
free(lessons);
getch();
}
이 프로그램을 실행하면 다음과 같은 결과를 얻을 수 있습니다. 학생 수와 수강 과목 수, 그리고 각 과목별 점수는 사용자가 입력한 것이고 나머지는 프로그램이 출력한 것입니다.
세가지 방법을 아직 확실하게 이해한 것이 아니기 때문에, 연습문제를 풀어봐야 할 것 같네요; ㄷㄷ 다음엔 연습문제와 풀이를 정리해서 올리거나 아니면 다음 단원인 구조체,공용체에 대해서 공부 해 봐야 겠습니다.
'Study' 카테고리의 다른 글
20121001_리눅스의 장단점 (0) | 2012.11.20 |
---|---|
20121001_시스템엔지니어가 하는 일, 시스템엔지니어의 필요 지식 (0) | 2012.11.20 |
20120712_2차원 배열과 포인터 (0) | 2012.11.20 |
20120712_1차원배열과 포인터(2) (0) | 2012.11.20 |
20120712_Java스터디 2일차 (0) | 2012.11.20 |