C 프로그래밍중 이상한점을 발견하였습니다

[code:35q2a4nx]#include <stdio.h>

int input(int* prr);
int MaxMin(int*prr2 , int** M , int** m);

int main(void)
{
int max = 0;
int min = 0;

int* pmax = &amp;max;
int* pmin = &amp;min;

int arr&#91;5&#93;;

input(arr);
MaxMin(arr , &amp;pmax , &amp;pmin);		

//printf("\n");
printf("Most big number: %d \n" , *pmax);
printf("address value of big number: %d \n" , pmax);

printf(&quot;Most small number&#58; %d \n&quot; , *pmin);
printf(&quot;address value of small number&#58; %d \n&quot; , pmin);

return 0;

}

int input(int* prr)
{
int i;

for(i=0; i&lt;=4; i++)
{
	printf(&quot;Please input number&#58;&quot;);
	scanf(&quot;%d&quot; , &amp;prr&#91;i&#93;);
}

}

int MaxMin(int*prr2 , int** M , int** m)
{
int i;
int val = 0;
int val2 = 9999;

for(i=0; i&lt;=4; i++)
{
	if(val&lt;prr2&#91;i&#93;)
	{
		val = prr2&#91;i&#93;;
		*M = &amp;val;
	}	
}

printf(&quot;Val's address value&#58;%d \n&quot; , &amp;val);

for(i=0; i&lt;=4; i++)
{
	if(val2&gt;prr2&#91;i&#93;)
	{
		val2 = prr2&#91;i&#93;;
		*m = &amp;val2;
	}
}
printf(&quot;Val2's address value&#58;%d \n&quot; , &amp;val2);

}

[/code:35q2a4nx]

/ 입력받은 배열값중 가장 큰값과 가장 작은 값을 출력시켜주는 단순한 프로그램입니다. 더블포인터를 인자로 사용 하였구요, 근대 코드를 다 작성하고 컴파일할때 에러는 나오지 않았습니다. 그리고 나서 코드를 컴파일 시켜 실행한 프로그램 또한 이상 없이 잘 돌아 갔습니다. 근대 가만히 코드를 쳐다보니 이상한점이 한두개 발견되더 군요… 바로 MaxMin함수내에 존재하는 val값과 val2값에 관한 것 이었습니다. 두개의 변수는 MaxMin함수내에서 선언되어진 지역변수인대 더블포인터M과 m이 정상적으로 참고하고 값을 출력한것 이었습니다. 제가 알기로는 지역변수는 함수가 종료되는 즉시 메모리상에서 지워지는것으로 알고있습니다. MaxMin함수가 끝나고 분명 val과 val2는 메모리에서 지워 졋을탠대 어떻게 더블포인터M과m이 정상적으로 값을 참고하여 출력을 하였는지 궁금하였습니다.(물론 해당되는 배열요소의 주소값을 *m과 *M에 대입시키는 방법도 있는것을 숙지하고 다른방법으로 해본것 이었습니다.) 또 한가지가 바로 제가 주석처리를 한 부분인대요, 출력결과과 덕지덕지 붙어있어 구분이 잘 가지 않았습니다. 그래서 줄을 하나 띄우고 출력시키기위해 주석처리한 부분을 작성하고 컴파일하여 프로그램을 실행했습니다.(물론 에러는 없었지요.) 허나 출력결과과 완전 딴판이었습니다. / (우분투환경에서 gcc로 컴파일 하였습니다.)

/ 정상적인 출력결과 /(주석처리를 하고 컴파일 하였습니다. 한줄이 띄여있지는 않구요.)
Please input number:1
Please input number:2
Please input number:3
Please input number:4
Please input number:5
Val’s address value:1315807460
Val2’s address value:1315807464
Most big number: 5
address value of big number: 1315807460
Most small number: 1
address value of small number: 1315807464

/ 비 정상적인 출력결과 / (주석처리를 지우고 컴파일 한 결과입니다. 한줄이 띄어져 있구요.)
Please input number:1
Please input number:2
Please input number:3
Please input number:4
Please input number:5
Val’s address value:2045530612
Val2’s address value:2045530616

Most big number: 0
address value of big number: 2045530612
Most small number: -631174732
address value of small number: 2045530616

줄하나 더 띄우려고 printf("\n"); 을 추가시킨것 뿐인대 왜 이런 결과과 나온걸까요? 또 val과 val2는 어떻게 포인터들이 참조한 걸까요?,
P.S)아직 많이 부족하고 배우지못해서 스스로 해결하는대 많이 힘이드내요; 여러분들의 답변 기다리고 있겠습니다…

함수를 호출할 때 넘겨줄 파라메터나 돌려받을 리턴 값, 함수의 지역변수 등을 임시로 저장하는 메모리 영역이 있습니다. 이를 call stack 이라고 합니다. Call stack은 프로그램이 처음 실행될 때 고정된 값으로 할당받으며 실행 도중에 크기가 변하지 않습니다.

[quote="SHR":3ne6m7et]제가 알기로는 지역변수는 함수가 종료되는 즉시 메모리상에서 지워지는것으로 알고있습니다.[/quote:3ne6m7et]
메모리 내용을 일부러 지우는 연산은 보통은 하지 않습니다. 성능 낭비니까요. 필요 없는 데이터는 그냥 나뒀다가 다른 데이터로 덮어 쓰이게 되죠.

main() 에서 MaxMin()의 지역변수의 값을 가져올 수 있었던 건 call stack의 해당 메모리 영역의 주소를 알고 있었고, 다른 데이터에 의해 덮어 쓰이지 않았기 때문입니다. 그리고 printf(“\n”);를 호출함에 따라 해당 메모리 영역이 다른 값으로 덮어 쓰이게 된 것이라 볼 수 있습니다.

윗 분 말씀처럼 메모리 영역에 대해서 자동으로 지우기를 하지 않습니다.
그 프로그램이 종료된 후에도, 다른 프로그램으로 그 메모리 영역에 대해 읽기 시도를 하더라도, 같은 값이 나올 것입니다.
그렇기 때문에, C언어에서 초기화 되지 않는 지역변수를 사용할 경우, 초기값이 존재하게 되고,
이것을 쓰레기값이라고 하죠.
이것은 리부팅하거나, 운영체제 혹은 다른 프로그램이나 프로세스 등에서 값을 바꾸거나, 소거하지 않는 이상 그대로 있게 됩니다.

또한, 예전에 터보C로 컴파일 할 경우, 레지스터 변수라는 것이 있었는데,
이것은 지역변수를 메모리에 잡는 것이 아니라, 자동으로 레지스터에 값을 저장하는 경우가 있었습니다.
레지스터는 어셈블리어에서 AX,BX,CX,DX,EX 등으로 표현하는데, 임시적 기억장소로 1워드(32비트 컴퓨터에서는 4바이트, 16비트 컴퓨터에서는 2바이트)만을
기억합니다.
속도는 메모리에 비해 월등하게 빠르며, CPU내에 존재하는 기억공간이고, integer 연산이 빠른 이유도 여기에 있습니다.

레지스터 변수로 처리될 경우, 함수가 끝나고, 다른 함수에서 다른 변수가 사용될 때, 자동적으로 그 값으로 대체 되기 때문에,
값이 빈번하게 바뀝니다.

메모리 변수의 경우는, 컴파일 시 메모리 모델에 따라, 메모리를 일정부분 할당하고, 이 영역 안에서,
변수를 할당하거나, 재사용하게 됩니다.
그러니까, 실제로는 프로그램이 돌아가고 있는 중에도 그 메모리 값은 변경될 수 있습니다.

지역변수는 함수가 끝이나면 바로 지워지는줄 알았는대 제가 잘못 알고 있었내요;; call stack이라는 메모리 영역이 존재하고 이 영역에서 데이터를 주고 받는다는것을 두분 덕분에 오늘 처음 알게되었습니다. :)
왜 출력이 이상했고 어떻게 값을 참조했는지 이제는 잘 알수 있을것 같습니다!
정말 감사합니다!
PS).답변이 조금 늦어서 정말 죄송합니다;;

솔직히 call stack은 함수호출스택 입니다.
스택은 FILO(First-In Last-Out)으로 구현되는 자료구조입니다.
차곡차곡 쌓고, 최근에 쌓인 값이 먼저 호출되고 제거되는 구조로, push와 pop명령이 구현됩니다.

call stack이란 함수가 다른 함수를 부르거나, 함수가 자신의 함수를 부르는 재귀적인 호출의 경우,
매개변수를 저장하는 메모리영역으로 스택의 자료구조로 보통 구현됩니다.
첫번째 매개변수를 push하고, 두번째, 세번째 순으로 push하면,
pop명령에 의해 세번째, 두번째, 첫번째 순으로 pop됩니다.

C언어와 Pascal의 함수 호출이 내부적으로 다르며, 어셈블리어와 C를 섞어 프로그램할 경우,
C언어에서 어셈블리어로 구현된 함수를 호출할 경우, __PASCAL이라는 구문을 사용하는 이유가,
매개변수가 FIFO(Fist-In First-Out)냐 FILO가 차이가 나기 때문입니다.

물론 일반적으로 C프로그래밍 하실 경우, 컴파일러가 기계어로 번역할 때,
프로시져에서 스택의 값을 로드하여 변수에 담을 때, 그에 맞게 변수에 대응시키기 때문에 신경쓰지 않아도 되지만요…

call stack은 함수 호출에 해당하는 부분이고,
자동변수에 관한것은 메모리힙(heap)이나 레지스터 변수와 관련됩니다.
이것도 컴파일러가 메모리 힙을 잡고 할당하도록 기계어로 번역하기 때문에, 프로그래머는 그다지 신경쓰지 않아도 됩니다.