본 프로그램은 n명의 학생 각각이 m개의 과목을 수강할 경우에 대한 

2차원 배열을 선언하는 형태인데 학생 수가 고정되어 있지 않고 가변이고

각 학생의 수강 과목도 고정되어 있지 않고 각각 상이하다고 할 때의 

상황이다. 이때 가장 적합한 2차원 배열의 형태가 "2차원 포인터(포인터의 포인터)"

형태로 선언하는 것에 대한 예제 코드이다.


#include <iostream>

#include <malloc.h>


using namespace std;


void main()

{

//2차원 포인터는 2차원 배열의 형태를 갖는데 

//세로(행, row)도 가변적인 배열, 가로(열, column)도 가변의 크기를 갖는 배열이라는 뜻이다.

int** score;

int studentNum = 0;

int lessonNum = 0;

int allTotalSize = 0;


cout << "학생 수 입력 : ";

cin >> studentNum;


//studentNum 갯수 만큼의 크기를 가진 배열이 선언되는데 이 배열의 각 원소가

//int형 포인터 변수이므로 각 원소가 또 동적 할당으로 임의 크기의 배열의 시작 주소를

//가리키게 되므로 결국 2차원 배열이 되는 것이다.

//즉 studentNum 갯수 만큼의 크기를 가진 int형 포인터 변수가 배열 형태로

//선언되고 그 시작 주소 값을 score에 저장한다.

//통상적으로 이렇게 생성되는 배열을 2차원 배열의 행(row, 가로)의 크기로 본다.

score = new int*[studentNum];

cout << "sizeof(score) : " << sizeof(score) << " byte" << endl;

cout << "_msize(score) : " << _msize(score) << " byte" << endl << endl;


//_msize()함수에 대해: new로 생성된 메모리는 heap 메모리 영역에 생성되고

//heap 메모리 영역은 운영체자가 관리해 주기 때문에 동적 할당된 메모리의 크기를

//알기 위해서는 운영체제의 도움이 필요하다.

//윈도우의 경우 _msize()함수를 통해 알수 있다.

//반면에 sizeof()함수는 포인터 변수 자체의 크기를 반환하는데 포인터 변수는 항상 4byte로 동일하다

//아래의 코드는 score가 가리키는 동적 할당된 메모리 전체의 크기를 반환한다.

//score = new int*[studentNum]으로 할당되었기에 

//studentNum * 4(int형의 크기가 4byte이므로)의 크기를 가진다.

allTotalSize = _msize(score);


//studentNum 갯수 만큼의 배열 각 요소인 int형 포인터 변수 각각에 대해

//동적 메모리 할당을 통해 또 다시 배열을 만든다. 따라서 2차원 배열이 되는 것이다.

//통상적으로 이렇게 생성되는 배열을 2차원 배열의 열(column, 세로)의 크기로 본다.

for (int i = 0; i < studentNum; i++)

{

cout << (i+1) << "번 학생의 수강 과목 수 : ";

cin >> lessonNum;


score[i] = new int[lessonNum];

allTotalSize += _msize(score[i]);

cout << (i + 1) << "번째 배열의 크기 : " << _msize(score[i]) << " byte" << endl << endl;

}


cout << endl << "2차원 포인터 배열 전체의 크기 : " << allTotalSize << " byte" << endl;


//여기서 성적 입력 및 평균, 총점 처리...


//메모리 해제(동적 할당된 메모리는 사용후 반드 해재해 줘야함!)

for (int i = 0; i < studentNum; i++)

{

delete[] score[i];

//delete score[i]; //이 경우는 i번째 배열 전체가 아닌 그 배열의 시작 주소만 해제 함

}


delete[] score;


cout << endl << "동적 할당 메모리 해제 완료~" << endl;

}


실행 결과는 다음과 같다.








'C++' 카테고리의 다른 글

C#의 .dll Library를 C++에서 활용하기  (0) 2017.12.08
memcpy()함수를 이용한 문자열 복사 하기  (0) 2017.07.25


#include <stdio.h>

#include <malloc.h>


struct MySMS

{

//이거 자체가 1차원 배열을 구성

//char형 포인터로 선언한 것은 실행 타임에서 메시지의 길이를

//동적으로 지정하겠다는 뜻임.

char *message;


//여기서 아래와 같이 배열로 입력 받을 문자열 갯수를 지정할수도 있으나

//이렇게 되면 메시지의 길이에 따라 메모리가 낭비되거나

//메시지 내용이 잘릴수 있다.

//char message[50];

};


void main()

{

int row;

int col;


//아래와 같이 선언하는 건 2차원 배열이라는 뜻

//2차원 배열 중에서 행도 가변, 열도 가변의 2차원 포인터가 되시겠다.

//혹은 이런 식도 가능 하겠다.

//struct MySMS arr[10]; //이렇게 하면 열의 갯수는 가변이나

//행의 갯수가 고정이 되는 형태인데 이를 '포인터의 배열'이라고 한다.

//arr[0].message = (char*)malloc(sizeof(char) * 10); //문자열 9개를 받겠다는 뜻

struct MySMS *obj = NULL;


printf("메시지 갯수(행의 갯수) 입력 : ");

scanf("%d", &row);


//2차원 배열 중 행(row)의 갯수

//배열과 달리 실행 타임에 동적으로 크기를 결정 가능.

obj = (struct MySMS *)malloc(sizeof(MySMS) * row);


printf("문자열 갯수(열의 갯수) 입력 : ");

scanf("%d", &col);


//입력한 수치 만큼 실제로 문자열(메시지) 입력 받기 위해

//맨 끝에는 문자열의 끝을 나타내는 널 문자(\0)가 들어가기 때문이다.

col++; 

obj[0].message = (char*)malloc(sizeof(char) * col);


//printf("사이즈 : %d\n", sizeof(char) * 6); //이건 6 byte

//printf("사이즈 : %d\n", sizeof(char*) * 6); //이건 24 byte


scanf("%s", obj[0].message);

printf("%s\n", obj[0].message);


//아래와 같은 순으로 반드시 메모리 해제를 해줘야 된다.

free(obj[0].message);

free(obj);

}


만일 위의 scanf("%d", &col);에서 입력한 col의 수치 보다 더 많은 문자열을 입력하게 하면 다음과 같은 에러 발생






C언어에서 2차원 배열의 형태가 몇 가지 있는데


(1) 행(row)이 고정 갯수, 열(column)이 고정 갯수 일때

  • '2차원 배열'을 이용하면 되고
  • 예) int [3][5]


(2) 행(row)이 고정 갯수, 열(column)이 가변 갯수 일때

  • '포인터의 배열'을 이용하면 되고
  • 예) char *pArr[5]

(3) 행(row)이 가변 갯수, 열(column)이 고정 갯수 일때
  • '배열의 포인터'를 이용하면 되고
  • 예) char (*pArr)[10]


(4) 행(row)이 가변 갯수, 열(column)이 가변 갯수 일때

  • 2차원 포인터를 이용하면 된다
  • 예) char **ptr


아래는 배열의 포인터를 이용해서 2차원 배열에 값을 저장하고 출력하는 간단한 개념을 구현한 것이다.

이때 scanf라는 좀 독특한 성격의 함수에 어떻게 값을 입력해 주어 2차원 배열에 값을 저장하는지를 예제로 보여주는 코드이다.


#include <stdio.h>

#include <malloc.h>

#define LESSONS 3


int main(void)

{

int l, s;

int sum;

int students;


char *lssn[] = {"Korean", "English", "Math"};


//2차원 배열. '배열의 포인터'

//'배열의 포인터'는 2차원 배열 중에서 열(column)은 고정 갯수이고

//행(row)는 가변 갯수일 때 사용할수 있는 2차원 배열의 형태이다.

int(*score)[LESSONS] = NULL;


printf("학생 수를 입력하세요 : ");

scanf("%d", &students);


score = (int(*)[LESSONS])malloc(students * sizeof(int[LESSONS]));

//score = (int(*)[3])malloc(sizeof(int[LESSONS]) * students);


for (s = 0; s < students; s++)

{

printf("%d번째 학생의 점수 : ", s + 1);

for (l = 0; l < LESSONS; l++)

{

//scanf함수는 공백이 있는 곳까지 읽거나 엔터 키까지 읽거나

//혹은 탭문자까지 읽는 성질머리를 가진 함수이다.

scanf("%d", &score[s][l]);

printf("%d, %d ==> %d\n", s, l, score[s][l]);

}

}


printf("%d\t", score[0][0]);

printf("%d\t", score[0][1]);

printf("%d\n", score[0][2]);


free(score);

return 0;

}


위를 실행하면 다음과 같은 결과를 출력한다.

이때 for문 안에서 scanf 값을 11 22 33과 같이 값을 입력한 후 엔터키를 치면 안쪽 for문이 한 바퀴 돌면서 2차원 배열에 값을 저장한다.

만일 다음과 같이 해도 결과는 동일하다.

11

22

33

혹은 11(탭키)22(탭키)33(엔터)






+ Recent posts