myonghuni   1년 전

런타임에러(segfault, outofbounds)를 해결하고 싶습니다.

djm03178   1년 전

c는 struct point의 포인터를 100만 개 가진 배열입니다. 배열의 0번째 원소부터 999999번째 원소까지 각각에는 아무것도 할당이 안 되어 있습니다.

이 상태에서 28번째 줄은 c의 존재하지 않는 100만번째 원소에 malloc이 반환한 값을 대입하려 하고 있습니다. 여기에서 이미 문제가 발생합니다.

그 후에도 계속해서 0번부터 n-1번까지의 아무것도 할당하지 않은 인덱스가 가리키는 알 수 없는 공간에 값을 쓰고 있습니다.

bamgoesn   1년 전

위 코드는 Segfault가 발생하는 부분 말고도 다른 부분도 잘못되어 있어 Segfault를 해결한다 해도 정답을 받지는 못할 겁니다. 그래도 그런 로직 부분은 고민하시면 스스로 생각해내실 수 있을 만하니까 잘 보이지 않을 법한 Segfault 부분만 답변드리겠습니다.

우선 위 코드가 하는 일을 설명해보겠습니다.

26행에서 "struct point*", 즉 struct point "포인터" 백만 개로 이루어진 배열을 선언합니다. 이 배열은 스택에 선언됩니다.

28행에서 malloc 함수를 통해 힙 영역에 sizeof(struct point) * n 만큼의 공간을 할당하고, 그 맨앞 부분의 주소값을 반환받습니다. 이 반환된 주소값을 c[1000000], 즉 앞서 선언한 포인터의 배열 c의 1000000번 포인터에 할당합니다.

그런 다음 30행의 루프에서 포인터 배열인 c의 원소를 하나씩 돌면서 값을 입력받고 있습니다.

---

뭔가 잘못된 게 보이시나요?

우선 26행에서 스택 영역에 struct point의 "포인터" 배열을 선언하셨는데, 이는 struct point "구조체"를 백만 개 만드신 게 아닙니다. 그저 struct point가 있는 다른 위치를 "가리키기만 하는 포인터"를 백만 개 만드신 겁니다.

게다가, 아시다시피 스택에 배열을 초기화 없이 선언하면 그 배열엔 쓰레기값이 들어갑니다. 때문에 c 배열에 들어간 포인터들은 아무 의미 없는 주소값을 담고 있을 것이며, 여기에 접근하려고 하면 segfault가 날 겁니다.

정작 struct point 구조체를 만드시는 부분은 28행의 malloc입니다. malloc은 sizeof(struct point) * n 만큼의 빈 공간을 실제로 만들어 주므로, 이 부분에선 단순히 포인터만 만든 게 아닌 실제 구조체를 n개 만드신 셈이 됩니다.

---

다음으로 28행에서 malloc에서 반환된 주소값을 c[1000000]에 넣고 계시는 부분이 잘못되었습니다. c는 그저 크기가 백만인 어떤 배열입니다. 여기에 c[1000000]라고 하시면 인덱스가 백만인 c의 원소를 의미할 뿐입니다.

그런데 배열 c의 크기는 백만이기 때문에 인덱스가 백만인 원소는 존재하지 않습니다. 여기에서 outofbound가 발생합니다. 배열 c의 크기는 백만이므로 인덱스가 백만인 원소가 없는 겁니다.

bamgoesn   1년 전

추측하기로는 질문자님께선 c 배열을 좌표를 담는 배열로 쓰고 싶으셨던 것 같은데, 동적 할당을 활용하는 방법은 그런 방식이 아닙니다.

동적 할당으로 크기 n인 struct point 배열이 만들 땐, malloc을 통해 그 크기만큼의 공간을 할당하고, malloc이 반환하는 그 공간의 첫 번째 주소를 받아서, 그 주소를 struct point* 형으로 변환(캐스팅)하여 struct point* 변수에 저장한 다음, 그 변수를 배열처럼 사용하는 방식으로 이뤄집니다.

즉, 26~28행은 struct point* c = (struct point*)malloc(sizeof(struct point) * n); 와 같이 변경하는 게 올바릅니다. 설명드린 걸 토대로 무얼 의미하는지 생각해보세요.

다만 코드를 이렇게 고치면 그 밑에 수많은 오류가 발생할 건데, 이는 기존에 c가 struct point*[] 형이었다가 struct point*형으로 바뀌어서 -> 연산자가 의미하는 바가 틀어지면서 생기는 문제입니다. 이 오류는 코드에서 메모리가 어떻게 동작하고 있는지 생각해보면서 고쳐보세요.

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