rdt2992   6년 전

제 소스는 다음과 같고

인풋은

5 4
3 1
3 2
4 3

5 3

을 넣었습니다

그런데 저렇게 map이라는 2차원 배열을 인수로 사용하면 처음에 초기화한 값이 들어가고 중간에 고쳐준 값이 반영되지 않네요

왜ㅔ그런건가요?

hun222y   6년 전

일단 map자체가 지역변수라서 그런듯 한데 ;;; 

아래처럼 고치고 맵을 전역변수로 선언 후 func에서 굳이 map을 안보내도 수정이 될듯합니다.

gallopsys   6년 전

무슨 컴파일러를 쓰시는지는 몰라도 일단 Stack에 4*210의 메모리를 할당하려고 해서 프로그램이 돌아가지도 못하고 Segmentation fault로 빠질 거 같긴 하네요..


우선 문제점을 이해하시려면 포인터의 특성을 좀 이해하셔야 합니다.

예를 들어 위처럼 int map[10001][10001];이라는 배열이 있다고 가정해봅시다. 그럼 map의 자료형은 어떻게 될까요? int, int *, int **?

저렇게 생각하셨다면 큰 오산입니다. map의 자료형은 int[10001][10001]이라는 사실에 유의하셔야 해요.


C언어에서 포인터는 반드시 한 차원만 붕괴되는 특성을 가지고 있습니다. 가령 예를 들면 int a[54];는 int *로 붕괴되고, int map[10001][10001];은 int (*)[10001]로 붕괴되게 되는 것이죠. 이에 유의하셔야할 건 map의 사이즈가 이미 정해져있다는 사실입니다.

또한 저렇게 되면 위험한 이유가, C99에 의해 가변 배열이 Microsoft VC++ 컴파일러를 제외한 거의 모든 컴파일러에서 가변 배열을 지원하고 있지만, C언어에서 컴마 연산자(Comma operator)의 우선순위는 지정되지 않았습니다. 그러니 int (*map)[size + 1]에서 size의 값이 어떻게 될지 모르고, 결과적으로 이상한 지점을 가리킬 수 있는 포인터가 될 수도 있다는 의미죠. 따라서 조금 조심해서 사용하실 필요가 있습니다... 문제를 해결하시려면 int (*map)[10001] 이라고 함수의 매개변수를 변경해주면 될 겁니다.

hun222y   6년 전

또한 참고로 문제 푸실때 map[10001][10001] 크기 선언하시고 문제 푸시면 메모리 초과날 것으로 예상합니다.

kdk8361   6년 전

제가 완전 잘못 이해하고 댓글을 달았었네요. 죄송합니다. 위에분들 답변을 참고하시는게 좋을거 같아요.

rdt2992   6년 전

gallopsys님

size+1의 값이 항상 10001보다 작은데도 문제가 생길 수 있나요??

gallopsys   6년 전

예를 들어서 말씀드릴게요. 만약 Comma Operator의 우선순위가 왼쪽에서 오른쪽이고, 이에 따라 size값이 정확히 뭔지 알 수 있다고 가정한 상태입니다.


size = 5라고 한다면 size + 1은 6이 되겠죠. 하지만 그렇게 되면 int (*map)[6];으로 map은 int[6]을 가리키는 포인터가 되어버립니다. 본래 map은 int[10001]을 가리켜야 하는 포인터인데 말이죠. 이로 인해 발생하는 문제는 상당히 큽니다. 자세한 내용은 아래의 사진을 참고해주세요.


asdfsdf.png


만약 위와 같은 상황이라면 완전히 잘못된 포인터 사용이 되겠죠? 심하면 메모리 범위를 잘못 참조해 Segmentation fault가 일어날 수도 있을 것이고요.

제가 말한 부분에서 조금 부족한 부분이 있어 보충을 하자면, size + 1의 크기가 10001보다 작아서 문제가 되는 것이 아니라 Comma operator의 우선순위가 정해져있지 않아서 어떤 컴파일러는 왼쪽에서 오른쪽으로 해석하기도 하고, 어떤 컴파일러는 오른쪽에서 왼쪽으로 해석할 수도 있다는 소리입니다.

rdt2992   6년 전

와 진짜 너무 감사합니다ㅜㅜㅜ큰 도움되었네요!!

댓글을 작성하려면 로그인해야 합니다.