#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int main()
{
int m = 0, n = 0;
scanf("%d", &m, &n);
char** matrix = malloc(sizeof(char*) * m); // 세로 크기 메모리 할당
for (int i = 0; i < m; i++)
matrix[i] = malloc(sizeof(char) * n + 1);//가로 크기 메모리 할당
for (int i = 0; i < m; i++)
{
for (int j = 0; j < m; j++)
scanf("%s", matrix[i][j]);
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < m; j++)
printf("%s", matrix[i][j]);
}
for (int i = 0; i < m; i++)
free(matrix[i]);
free(matrix);
return 0;
}
지뢰찾기 풀다가 문득 궁금해져서 올립니다...
그냥 제가 생각하기에 저렇게 해놓으면 scanf에 값을 입력해줄때마다 scanf[0][0] , scanf[0][1] ... scanf[4][4]... 이런식으로 수가 입력될 줄 알았는데.. 아예 디버그 자체가 안되네요.. 완전 초보자라 이상한 질문 죄송합니다...
혹시 이유를 좀 알 수 있을까요..? 책에 나와 있을법 한데 제가 부족해서 찾지를 못하겠습니다...
ps) 지뢰찾기를 하루종일 했는데도 못했는데.. 책엔 2시간이라고 나와있어서.. 제가 너무 쉬운걸 못하는 건지... 재능이없는건지.. 자신감이 많이 없어졌습니다.. 지뢰찾기만 잘연습하고 공부하면 그뒤 39단원~ 공부할수 있을까요..? 책 너무 잘 만들어주셨는데 이런 질문 죄송합니다.. ㅜㅜ
시각화 사이트에서 메모리 할당까지 한 단계씩 동작하면서 살펴보세요.
char** matrix로 선언했는데,
matrix는 pointer to pointer to char입니다.
그러니 %s로 받을 수 없습니다. 문자열이니까요.
%s 문자열을 입력받아서 저장할 수 있으려면
pointer to char이거나 address of array of char 이어야 합니다.
pointer to char는 문자 그대로 해석하면 문자 하나, char만 가리키는 포인터도 되지만, char 문자열이 시작되는 메모리 공간을 할당했을 때는 그 메모리 공간의 첫 번째 위치이기도 합니다. 프로그래머가 구분해서 잘 써야 합니다.
pointer to char가 문자 그대로 char 하나만 위해서 메모리를 할당한 상태라면 문자 1개만 저장할 수 있습니다. 여기에 "hello"를 입력하고 문자열을 저장하라고 하면 에러가 발생하겠지요.
scanf("%s", matrix[i][j]);
matrix[i][j]이면 결국 가리키는 것은 char입니다.
문자 하나인데 여기에 %s로 문자열을 우겨 넣으라고 한 거죠.
사람의 입은 하나이고 초코파이 한 개 넣으면 끝인데,
"입 벌려라~` 여기 초코파이 5개 넣는다!" 하면
학대입니다. 메모리에 char 문자 1개 공간 지정해놓고
"입 벌려라~ 여기 문자열 5개 넣는다!"하면 메모리 학대죠.
컴퓨터 내부에서 알아서 메모리가 5배로 뻥튀기 될거야, 공간이 5배로 생기는 것도 아닐 테고...
해설에도 있지만...
그다음에 다시 m만큼 반복하면서 scanf로 문자열을 입력받으면 문자열이 행렬 형태로 저장됩니다.
matrix[i]입니다. matrix[i]가 가리키는 것은 pointer to char이죠. 그 안에는 메모리 공간 할당해놨으니까 문자열을 저장할 수 있습니다. pointer to char는 문자열이 시작하는 첫 번째 위치를 가리키는 것이죠.
char ** matrix입니다.
matrix는 pointer to pointer to char입니다.
*matrix는 pointer to를 하나 제거하죠. 그러니 pointer to char입니다.
또는
matrix[i]도 pointer to를 하나 제거하죠. 그러니 pointer to char입니다.
**matrix는 pointer to를 두 개 제거하죠. 그러니 char입니다.
matrix[i][j]도 pointer to를 두 개 제거하죠. 그러니 char입니다.
내가 데이터에 접근할 때 2차원 배열 전체를 물고 와서 접근하고 싶다면 matrix로 접근하면 되고,
2차원 배열에서 행 전체를 접근하고 싶다면 *matrix나 matrix[i]로 접근하겠지요.
행과 열을 지정해서 그 안에 있는 셀 하나, 셀에 있는 원소 하나에 접근하고 싶다면 **matrix나 matrix[i][j]로 접근하겠지요.
5x5 크기의 행렬이 있습니다.
matrix[5][5]로 선언할 수 있겠지요.
여기서 matrix[2][3]에 접근한다고 합시다. 이걸 포인터식으로 바꾸면 다음과 같습니다.
*(matrix + 2 * 5 + 3)
5는 1층 전체의 크기입니다.
2는 height이고, 3은 width입니다.
5x5라는 것은 아파트로 치면 1층에 5호까지 있는 5층짜리 아파트인 셈이죠.
height가 2라면 2층이고(배열은 0부터 세니까 0층부터 있다고 합시다),
width가 3이니 3호겠지요(0부터 세니까 0호실부터 있다고 합시다).
그래서 matrix[2][3]인데, 항상 강조하는 matrix[height][width]입니다.
자꾸 행렬이라고 해서 matrix[width][height]로 가리키는 책이 있는데 잘못 배우는 겁니다. 회사 가면 혼나요.
UNIT 37 2차원 배열에서 가로, 세로는 다시 복습합시다.
matrix[2][3]을 포인터식으로 바꾸면
*(matrix + 2 * 5 + 3)입니다.
포인터와 배열은 바꿔 쓸 수 있습니다. 1차원 포인터라면
char *str = "Hello";도 가능하고, *(str+2)와 str[2]는 같습니다. 주소 연산이니까요.
*(*(matrix + 2) + 3)
이렇게 바꿔 쓰는 것도 가능합니다. 이건 다시 바꿔쓰면
*(matrix[2] + 3)
과 같습니다.
이렇게 바꿔쓰는 것은 실무에서 전혀 안 합니다. 어쩌다 할 수는 있겠지만, 안 합니다. 그리고 이런 것을 시험문제로 낸다면 C 언어를 잘못 가르치고 있는 겁니다. 실무에서도 안 하는 것을 시험을 위한 공부만 시킨다는 뜻이니까요.
자꾸 참조, 역참조 이런 걸로 가르치는데,
C 언어 스펙에도 쓰여 있는 것처럼 pointer to를 붙였다, 뗏다 하는 개념으로 생각하시고, 그래서 해석한 양쪽의 자료형이 일치하느냐로 보면 됩니다.
scanf의 사용이 문제가 아니라 matrix[i][j]가 가리키는 타입이 무엇인지 정확하게 모르는 데서 발생하는 문제입니다.
굳이 matrix[i][j]로 쓰고 싶다면 이건 char를 가리키니까 %c를 쓰면 됩니다. 5x5 행렬이면 scanf를 25번 쓰면 됩니다. 중첩 반복문 쓰면 되겠죠?
한다면 할 수 있죠. 근데 scanf는 엔터키를 입력의 끝으로 받아들입니다.
그렇다면 문제의 입력 방식이
5 5
.
.
*
.
.
....
이렇게 5x5 행렬이면 25줄의 문자로 된 입력이어야 합니다.
근데 지뢰찾기가 제시한 입력은 그게 아니죠? 한 번에 문자열로 받아들이라는 겁니다.
문자열이려면 pointer to char이면 됩니다.
matrix[i]는? pointer to char입니다. 그리고 이건 malloc으로 할당한 메모리의 첫 번째 위치이니까 문자열 입력이 가능하지요?
문제를 잘 해석해야 합니다. 문제 해석을 잘못하고, 나만의 상상력과 창의력과 공상력으로 가면 코딩 테스트 탈락합니다.
지뢰찾기는 어려운 문제이니 생략하고 다음 단원으로 나가세요. 나중에 다시 보면 쉽게 풀 수 있습니다.
지뢰찾기는 edge case가 문제입니다. 3x3 작은 행렬에서 지뢰의 개수를 계산해야 하는데, 전체 지도에서 바깥쪽 위치일 때 배열 범위를 벗어나지 않고 접근하는 것입니다. 따라서 종이와 펜을 꺼내서 에지 케이스일 때 i, j 인덱스 값이 어떻게 되는지, 조건식은 어떻게 되고, break냐, continue냐를 결정해야 합니다.
먼저 종이와 펜을 꺼내서 에지 케이스를 확실하게 이해하고, 조건을 작성하면 코드는 그냥 옮기면 됩니다. 하지만 종이와 펜 과정을 무시하고, 모니터 앞에서 코드만 두들기면 당연히 실패합니다.
왜요?
나의 머릿속에는 에지 케이스가 없으니까요. 그냥 실행이 안 되고, 에러가 나고, 심사 통과를 못하면 코드를 막무가내로 고치면 될까?
마치 TV가 안 켜지면 툭툭 두드리고, 발로 차 보고, 자동차가 시동이 안 걸리면 괜히 발로 차는 심리와 같습니다. -> 인간의 보편적인 행동입니다. 코딩을 배울 때도 괜히 코드를 고치면서 발로 툭툭 차는 것이죠.
5x5 행렬이 있습니다. matrix[0][0] 위치에서 에지 케이스는? matrix[0][4] 위치에서 에지 케이스는?
지뢰 개수를 카운팅하려면 3x3이죠.
개수를 카운팅 하는 가운데 위치가 (i, j)입니다. (i - 1, j - 1)의 좌표나 (i + 1, j + 1)의 좌표가 배열의 정상 범위를 벗어난 경우는?
(0, 0)인데 (-1, -1)에 접근할 수 있음?
이런 것들을 고민해야 합니다.
이상 사이트 관리자(저자 아님)의 답변입니다.
감사합니다.