[해결]C언어 배열범위를 벗어난 참조를할때

hohodori의 이미지

간단한 예로

#include

main(){
static int a[]={100,200,300};
int *b;
b=a+3;
printf("%d",*b);
}

1. 어째서 a+3을 참조하니 0이 되는 걸까요?
왜 0인지 알고싶습니다.

x=y=z=1 일때

++x && ++y && ++z x=2, y=2, z=2
++x && ++y || ++z x=2, y=2, z=1
++x || ++y && ++z x=2, y=1, z=1
++x || ++y || ++z x=2, y=1, z=1

반대로 x,y,z가 -1일때.

++x && ++y && ++z x=0, y=0, z=-1
++x && ++y || ++z x=0, y=-1, z=0
++x || ++y && ++z x=0, y=0, z=-1
++x || ++y || ++z x=0, y=0, z=0

2. && 연산의 경우 좌변이 거짓이면 항상 거짓이므로 나머지가 연산되지 않고
|| 연산의 경우 좌변이 참이면 항상 참이므로 나머지가 연산되지 않는다. 이렇게 피상적으로 배웠습니다.
실제로도 ++x && ++y || ++z x=0, y=-1, z=0인 경우를 제외하면 모두 들어맞는것 같구요.

그런데x,y,z가 -1일때 ++x && ++y || ++z x=0, y=-1, z=0 z가 -1이아니라 0이 되는 이유는 무엇일까요?
++x는 0이니까 AND연산을 하면 무조건 거짓이므로 나머지 우변의 처리를 전혀 하지 않아도 되는게 아닐까요?

3. 이런 문제들은 컴파일러에 대한 공부가 필요해 보이던데
컴파일러에 대해 공부하려면 학생인 제가 고려해야 될 부분은 무엇일까요?
정말 제가 무엇을 모르는지에 대해 알수 없는게 힘듭니다.
무슨 언어의 컴파일러를 써야할지, 제가 쓰는 VS 2008과 2010과 VC 6.0과의 차이점등은 어떻게 습득하는지 등등이 궁금합니다.

4. 마지막으로 이곳에 이런 기초적인 질문을 올려도 되나요?
아니면 그런 질문이 가능한 사이트나 포럼은 어떤게 있을까요?

공부하는 학생이라 너무 막연해서 도움청해드립니다.

익명 사용자의 이미지

1. 어째서 a+3을 참조하니 0이 되는 걸까요?
왜 0인지 알고싶습니다.

==> 0이 아닐수도 잇습니다. 저같은경우네 한컴퓨터에선 268435752 라는 값이 다른 컴퓨터에서는 -1 값이
또 다른 컴퓨터에서는 또다른 값이 나올수도 잇습니다.
위에 보시면 a+3 의 값은 a[3] 과 같은데..
실제로 선언하신것은 a[0], a[1], a[2] 까지만이고 a[3] 은 프로그램내에서는 쓰지 않고 있습니다. 메모리 참조 오류 입니다.
a 라는 메모리를 기준으로 접근을 할수 있지만 a+3(즉 a[3]) 에 값을 대입한다면, 다른프로그램에도 오류를 발생시킬 가능성이 있습니다.
할당된 메모리 영역만을 사용하는것이 좋겟지요.

실제로도 ++x && ++y || ++z x=0, y=-1, z=0인 경우를 제외하면 모두 들어맞는것 같구요.
==> 위 조건대로라면 ++x && ++y || ++z 이 식을
1 && 0 || 1 이렇게 해석해서 볼수 잇는데 && 논리 곱의 연산과 || 논리 합의 연산에서 약간 놓치신분이 있으신거 같습니다.
x y z
&& 연산의 경우는 둘다 맞아야 참. 둘중에 하나라도 틀리면 거짓
|| 연산의 경우는 둘중 하나라도 맞으면 무조건 참. 둘다 거짓이어야 거짓 입니다.
위의 경우 1 && 0 || 1 이어서 참, 거짓을 순서대로 본다면
++x && ++y -> 1 && 0 -> 거짓
거짓 || ++z -> 거짓 || 1 -> 참
이렇게 처리가 되어 ++x && ++y || ++z x=0, y=-1, z=0 역시 맞는 경우입니다.
위에 말씀하신대로 의 말이 맞습니다. 쉽게 저렇게 이해하여도 되지요.
"&& 연산의 경우 좌변이 거짓이면 항상 거짓이므로 나머지가 연산되지 않고
|| 연산의 경우 좌변이 참이면 항상 참이므로 나머지가 연산되지 않는다. 이렇게 피상적으로 배웠습니다."

그런데x,y,z가 -1일때 ++x && ++y || ++z x=0, y=-1, z=0 z가 -1이아니라 0이 되는 이유는 무엇일까요?
++x는 0이니까 AND연산을 하면 무조건 거짓이므로 나머지 우변의 처리를 전혀 하지 않아도 되는게 아닐까요?
==> 이것은 연산자 우선법칙에 대한 개념이 없으신거 같습니다.
http://ko.wikipedia.org/wiki/C%EC%99%80_C%2B%2B%EC%97%90%EC%84%9C%EC%9D%98_%EC%97%B0%EC%82%B0%EC%9E%90
다음 링크를 보면 연산자 우선법칙에 의하여 정리 되는데
++x && ++y || ++z 는
연산자 우선법칙에 의하면
1. ++x
2. ++y
3. ++z
4. &&
5. ||
순으로 적용됩니다. 그러니 당연히z 는 0 이 나와야 정상이겟지요?
위에 언급한 피상적으로 "&& 연산의 경우 좌변이 거짓이면 항상 거짓이므로 나머지가 연산되지 않고
|| 연산의 경우 좌변이 참이면 항상 참이므로 나머지가 연산되지 않는다. 이렇게 피상적으로 배웠습니다."
이 말은 && 와 || 에 적용되는 것이지 ++ 에 적용되는것은 아닙니다.

3. 컴파일러는 제가 딱 뭐라고 답변드릴수 없어 죄송합니다. 정확히 어떤것을 배우겠다 학부때는 두루 배워보고 추후 심도있게 하나씩 정하여 공부할때가 되면, 스스로 느낄수 있다고 생각합니다. 당장에 컴파일러를 공부한다는건 무리가 있는거 같습니다. 단지 컴파일러의 차이를 알고 싶으면 구글신에게 물어보시면 될꺼 같습니다.

4. 마지막으로 이곳에 이런 기초적인 질문을 올려도 되나요?
아니면 그런 질문이 가능한 사이트나 포럼은 어떤게 있을까요?
==> 저 역시 여기 올라오는 글들을 다 이해하지 못했습니다. 그런게 있구나.. 하면서 넘어간것도 있고, 정말 어처구니 없는것도 질문해보기도 했습니다.
단지 제 생각일지 몰라도 기초적인 것들을 '그냥 그런거구나..' 하면서 받아들이는 사람보다 hohodori님처럼 '왜그런거지? 진짜 그런건가? 아닌거같은데?' 이런 의심을 품고 공부하는 방법이 더 좋은거 같습니다.
정말 고수라는 분들도 그런 시절을 다 겪었고, 그분들도 hohodori 님과 같은 생각을 했을겁니다. 제가 느낀점은 KLDP 사람들은 착하다는것입니다^^ 언제든지 물어보시면 될겁니다.
갑자기 이런말이 생각나에요.

모르는척은 멍청한것이 아니다. 알려고 하지 않는것이 멍청한 것이다.

익명 사용자의 이미지

앗 오타가 낫네요..

모르는 것은 멍청한것이 아니다. 알려고 하지 않는것이 멍청한것이다.

모르는척이라니.. 전 정말 바보군요 :(

hohodori의 이미지

1번의 경우 VS2008에서 실행해보면 꼭 0이 나오더라구요.
다른 컴퓨터에서 실행해봐도 늘 같은값이 나오길래, 혹시 다른이유가 아닐까 생각했습니다만 아닌가보네요.

zelon의 이미지

아마 배열 선언을 static 으로 해서 0 으로 초기화 되어있는 메모리를 참조할 확률이 큰 것 같습니다.

a 를 static 으로 선언하셨기 때문에 stack 이 아니라 static 영역에 들어갔고, 그 근처 영역은 static 영역일 것 입니다. static 영역은 기본적으로 0 으로 초기화되어 있기 때문에 그런 것 같습니다.

아래의 코드는 둘다 초기화를 안하지만 결과가 다릅니다.

int a;
printf("%d\n",a);

는 쓰레기 값이 출력됩니다.

static int a;
printf("%d\n",a);

는 항상 0 이 출력됩니다.

하지만, 역시 a 배열이 아닌 다른 변수의 영역을 참조한 것은 변함없는 사실이며, 잘못 사용하고 있습니다.

-----------------------------------------------------------------------
GPL 오픈소스 윈도우용 이미지 뷰어 ZViewer - http://zviewer.wimy.com
블로그 : http://blog.wimy.com

익명 사용자의 이미지

2.
++x && ++y || ++z
(++x && ++y) || ++z

윗줄은 아랫줄과 정확히 같은 식입니다.
연산자 우선순위가 && 가 ||보다 높기 때문에 이렇게 됩니다.
아랫줄을 계산해보면
++x의 결과값이 0이기 때문에 && 연산자의 우변인 ++y는 계산을 하지 않고,
(++x && ++y)의 결과값이 0이 되고,
|| 연산자의 좌변이 0이니까 || 연산자의 우변도 계산을 하게 됩니다.
그러므로 실행되는건 ++x와 ++z 뿐이니까, x = 0, y = -1, z = 0이 되지요.

3. 우선 인터넷에서 공짜로 볼 수 있는 C FAQ 번역문을 정독해 보시고
그다음에 'C언어 펀더멘탈'이란 책을 보시고
그 다음은 C언어 표준인 ISO/IEC 9899:1999 직접 보세요.
(이건 원래는 돈주고 사야 하지만... 모종의 루트로 쉽게 pdf를 구할 수 있습니다)
그러면 C언어의 공통 분모가 정확히 뭐가 있는지 알게 됩니다.
여기까지 공부하시면 각각의 회사가 제공하는 C 컴파일러 메뉴얼이 더 이상 귀신 씨나락 까먹는 소리로 보이지 않습니다.

4 여기다 기초적인 질문을 던지면 왜 기본적인 검색도 안해봤냐면서 온갖 구박이 다 날라옵니다.
개인적으론 별로 추천하고 싶진 않네요.

snowall의 이미지

그렇게까지 구박하는 사람은 별로 없어요.

질문이 그냥 "이거 해주세요"같은 식이면 구박하죠.

피할 수 있을때 즐겨라! http://melotopia.net/b

익명 사용자의 이미지

헛, 지금까지 당연하게 넘겨오다가 갑자기 의문이 들었습니다.

'연산자 우선순위'라는 면에서 보면 ++가 &&나 ||보다도 순위가 높은데,

++x && ++y || ++z

여기서 세 변수의 ++는 일단 다 수행된 다음에 &&나 ||를 따져야 할 것 같기도 한데 왜 안 그런 걸까요.. ;ㅅ;?
아니, 왜 안 그러냐라기보다는, 그렇지 않은 건 어떤 룰이 적용되고 있는 걸까요?

익명 사용자의 이미지

++연산자를 먼저 평가하기는 하지만, &&연산자나 || 연산자의 left-to-right evaluation 규칙이 먼저입니다. 왼쪽 항을 먼저 평가하고 그 결과값에 따라서 오른쪽 항을 평가하지 않을 수도 있습니다.

이렇게 생각하시면 편합니다. 수식을 수행하기 위해서는 먼저 수식을 읽을 필요가 있지요? 연산자 우선순위는 수식을 '읽는' 순서입니다. 무슨 뜻인지 읽기만 했지 아직 그 명령을 수행한건 아닙니다. 해당 수식이 언제 수행될지(정확하게는 해당 수식의 side effect가 언제 적용될지)는 연산자 우선순위가 아닌 별개의 규칙에 의합니다.

이에 대한 예를 하나 들자면

value = f1() + f2() * f3();

위 코드에서 함수 f1, f2, f3은 어떤 순서로 실행이 될까요? f2, f3, f1? 연산자 우선순위가 있으니 f2는 최소한 f1보다는 먼저 실행이 될까요?

답은 '실행 순서는 알 수 없을 뿐더러, 보장되지도 않는다' 입니다.

value = f1() && f2();

그럼 위의 수식도 f1과 f2중 어떤 것이 먼저 실행될지 알 수 없을까요?

답은 '반드시 f1이 f2보다는 먼저 실행된다' 입니다.

이걸 제대로 이해하려면 side effect와 sequence point에 대한 걸 알아야 하는데,

제가 여기서 설명하기엔 좀 길고 복잡하니, 검색해 보시는걸 권합니다.

익명 사용자의 이미지

아하 그렇군요.

그렇잖아도 C FAQ 3장을 지금 읽어봤는데도 영 어려워서 (특히 그 시퀀스 포인트 얘기)
힘들어하던 참이었는데 아래 예하고 비교하니까 납득이 가는군요. 감사합니다.

hohodori의 이미지

감사합니다. 굉장히 도움이되었어요 ^^

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.