4z7l   2년 전

구현 알고리즘은 생략하겠습니다 거기서 틀린게 아니라서..

일단 게시판의 반례는 다 맞고 테케도 맞는데 50%에서 틀렸습니다가 계속 떴습니다.

디버깅 2시간째라 포기상태로 그냥 변수 선언 위치만 바꿨는데 맞았습니다 떴어요..

main함수만 올려보겠습니다.

저랑 같은 문제인지 한번 확인해보시고 이유 아시는분은 알려주세요..ㅠ c++ 문자열 관련 문법 때문인거같은데..

주석처리한 5번째 줄과 20번째줄만 보시면 됩니다

+)

5번째 줄에서 char cmd[3]으로 선언하는 것도 맞았습니다 떴습니다

입력 관련해서 빠삭한분.. 논리적으로 설명해줄부 구합니다..ㅠㅠ

dps2   2년 전

우선 이미 맞았습니다를 받았음에도 불구하고 이 코드는 위험한 코드임을 미리 알려드립니다.

변수가 실제로 메모리상에 올라갈때 선언된 순서가 실제 배치된 순서와 연관이 있습니다.

제가 아래 첨부한 코드로 12를 입력으로 실행시켜보시기 바랍니다.

https://wandbox.org/

만약 결과가 제대로 뜬다면 이 싸이트에 들어가서 C++17이나 14로 실행시켜보시기 바랍니다.


분명 이상한 결과가 뜰 텐데 그 이유는 str입력 받을때 마지막에 널문자를 넣어야하기 때문에

길이 3인 char 배열이 필요합니다. 그런데 선언된 배열의 길이는 2개이기 때문에 범위를 초과하여 b값을 오염시키면서 b값의 일부에 0을 넣습니다.

그런데 이것은 아마 컴파일러마다, C++ 버전마다 다른 것 같습니다.

위 첨부한 링크에서 C++20으로 실험해본 결과 char 배열의 최대길이를 컴파일러가 확인하고 초과되지 않는 범위까지만 읽습니다.

그렇다면 이제 질문자님의 코드를 정확히 분석하자면,

기존 5번째 줄에서 char str[2]로 쓴 코드는 그 이후에 선언되어 있는 변수 cube의 값을 변경시켰을 것으로 생각됩니다.

(C++ 템플릿의 변수는 복잡해서 정확히 어떻게 변경시켰는지 알기 어렵지만 cin >> str때 다른 변수를 오염시킵니다)

그렇다면 오히려 왜 20번째 줄에 str[2]로 선언했을때는 맞았는지 분석해야합니다.

20번째 줄에 있는 str 뒤에는 다른 변수가 없습니다.

따라서 잠시 오염시켜도 어차피 다른 변수가 생성되었을때(함수가 호출되었을때 지역변수가 해당 위치에 생성됩니다.)

가비지 값이 있을 것이라고 생각하고 코딩하셨을 테니 맞았습니다가 떴을 것입니다.


그래도 배열의 범위를 벗어나 작동하는 코드는 위험한 것 같습니다.

널 문자를 고려하셔서 늘 배열을 한칸 많이 선언해주시면 좋을 것 같습니다.

jgk07014   2년 전

컴퓨터에서는 문자열의 끝을 가리키는 NULL문자라는게 존재합니다.

이 NULL('\0', ASCII CODE NUMBER = 0)문자가 있기 때문에 컴퓨터는 논리적으로 문자열의 끝은 NULL의 바로 이전이라는 사실을 알아낼 수 있습니다.

char cmd[3]으로 선언하셨을 때 정답인 이유를 실제 예시를 들어서 설명드려보겠습니다. cmd 배열에 "L-"를 입력한다고 가정하면

cmd[0] == 'L'

cmd[1] == '-'

cmd[2] == '\0'

이렇게 입력이 됩니다. 실제로 디버깅해서 cmd[2]의 데이터 값을 보시면 NULL문자가 들어가 있는 것을 확인하실 수 있으실 겁니다.

그러나 char cmd[2]으로 선언하시면 마지막 NULL문자가 들어갈 수 있는 공간인 cmd[2] 공간이 공식적으로 할당된 적이 없기때문에 NULL이 들어가더라도 cmd[2]의 값은 시스템 여건에 따라 값이 바뀔 수도 있습니다.(이 부분을 간단히 설명드리자면, 할당되지 않은 공간은 공공의 영역이기 때문에 언제든지 다른 데이터가 덧씌워질 수 있다는 가능성이 존재합니다.)

그리고 마찬가지 논리로 20번째 줄에도 cmd[2]로 선언하면 논리적으로 틀렸어야 하는데 실제로는 정답으로 나오셨다고 하셨으니 이 부분은 제 추측으로 한번 설명드려보겠습니다.

20번째 줄에 있는 char cmd[2]는 정답으로 나왔는데 5번째 줄에 있는 char cmd[2]는 오답으로 나온 이유는 두 배열의 생성과 소멸의 차이에서 비롯된 부분이 있는 것 같습니다.

5번째에서 선언되는 cmd배열은 프로그램이 진행되면서 단 1회 생성되며 main()함수의 끝 부분인 return 0;문을 만나서 소멸될 것입니다.

그러나 20번째에서 선언되는 cmd배열은 총 ( tc * N )번 생성되고 소멸될 것입니다. 이렇게 그때그때 필요할 때마다 생성되고 소멸되면 확률적으로 다른 데이터가 cmd배열의 공간에 침범하는 가능성은 낮을 것이라 판단됩니다. 5번째 줄은 처음부터 끝까지 cmd공간이 유지되면서 다른 데이터의 간섭현상이 일어날 가능성이 매우 높습니다. 이러한 차이 때문에 20번째 줄에 선언한 char cmd[2]는 정답으로 나오지 않았을까요?

그래도 논리적으로 정확한 표현은 char cmd[3]이므로 안전하게 NULL문자를 고려해서 문자열 변수를 선언하실 때에는 (실제 필요한 공간 + 1)만큼 배열의 크기를 선언하시는 습관이 중요합니다.

4z7l   2년 전

다들 감사합니다. 


가장 궁금했던건 테케는 되고 제출시 히든 테케는 틀리는 이유가 궁금했던 건데 아마 제 로컬과 백준 서버의 컴파일러나 c++ 버전 차이때문인가봐요

이 문제를 계기로 char 쓸때 좀더 주의하는 습관을 기르려고요!! 🤗

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