본문 바로가기
Study

20120718_2차원 데이터의 활용

by hyeongjin's_life 2012. 11. 20.

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();

}

이 프로그램을 실행하면 다음과 같은 결과를 얻을 수 있습니다. 학생 수와 수강 과목 수, 그리고 각 과목별 점수는 사용자가 입력한 것이고 나머지는 프로그램이 출력한 것입니다.


세가지 방법을 아직 확실하게 이해한 것이 아니기 때문에, 연습문제를 풀어봐야 할 것 같네요; ㄷㄷ 다음엔 연습문제와 풀이를 정리해서 올리거나 아니면 다음 단원인 구조체,공용체에 대해서 공부 해 봐야 겠습니다.