cCcode

C Language [핵심정리] - 37 본문

C Language Basic

C Language [핵심정리] - 37

cCcode 2021. 7. 11. 18:32

1. 함수에서 매개변수 사용하기

매개변수를 사용하려면 함수정의할 때 괄호 안에 자료형변수 이름을 지정해주면 됩니다.

자료형 매개변수
함수로 파라미터(매개 변수)전달
결과

함수 안에서 파라미터로 전달된 값을 사용하려면 함수 정의를 하면서 명시한 변수명을 사용합니다. (파라미터로 전달할 때 사용한 변수가 아니라)

 

함수에서 매개변수를 여러 개 받으려면 매개변수를 ,(콤마)로 구분하면 됩니다. 이를 이용해 간단한 곱셈 연산수행해보겠습니다.

간단한 곱셈 연산
결과

 

함수 안에 들어가는 값은 매개변수, 파라미터(parameter), 형식 매개변수(formal parameter), 인자(함수 바깥에서 전달 된 값이 저장되는 변수)등 많은 용어로 불립니다. 그리고 함수를 호출할 때 전달하는 값이나 변수는 인수, 전달 인자, 아규먼트(argument), 실행 전달인자(actual argument) - [함수를 호출할 때 전달하는 값이나 변수]라고 불립니다.

 

헷갈리나요? 그럼 다음 그림을 보시죠.

매개 변수
인수

함수를 기준으로 용어를 나누었을 뿐이지 모두 같은 변수들 입니다.

 

지금까지 매개변수는 함수에 값을 전달하고, 함수 외부에서 값을 가져오는 용도로만 사용했습니다. 즉, MUL 함수로 전달된 매개변수 a, b는 오직 함수 내부에서만 사용할 수 있었습니다.

매개변수의 한계

하지만 매개변수의 형태포인터로 준다면 함수 안에서 바뀌어진 내용을 함수 외부에서도 작용할 수 있습니다. 따라서 함수 바깥으로 값을 전달할 수 있는것이죠.(return □ 처럼 반환값 형태가 아닌 상태로)

포인터 매개변수
포인터 매개변수 X 인 경우
포인터 매개변수 X 인 경우 - 2
결과

결과를 보면 우리가 swap_num을 호출해도 해당 함수의 수행결과에 반영되지 않았습니다. 왜냐하면 값 자체를 전달하는 게 아닌 값을 복사해서 전달하기 때문에 아까전에 말씀드린 것처럼 값을 전달하는 역할일 뿐 함수 외부의 변수와는 전혀 상관이 없기 때문입니다.

 

이제 매개변수포인터를 전달해보겠습니다.

포인터 전달
포인터 매개변수로 받은 함수
인수 전달
결과

위 코드는 변수의 메모리 주소인수로 줘서 함수로 전달하면 함수 안에서는 역참조를 통해 메모리에 접근해 값을 저장했습니다. 따라서 반환값 없이 매개변수를 외부에서 사용하고 싶다면 인수로 해당 변수의 주소를 준다는 점 기억하세요. (그럼 주소를 가지고 있지 않는 literal 값은 인수로 주기 힘들겠죠?) 

 

그전에 구조체를 함수의 반환 값으로 만들어 여러개의 값을 전달한것처럼 포인터 매개 변수를 이용하면 함수 외부로 여러 개의 값을 전달할 수 있습니다. 이를 통해 우리는 scanf 함수에서 변수에 주소 연산자를 사용하는 이유를 알아냈습니다.

[scanf 함수에서 여러 개의 값을 입력 받을 경우 여러 개의 값을 개수에 상관없이 가져오기 위해서]

 

포인터 중에서도 void 포인터 매개변수를 사용하면 자료형 변환을 하지 않아도 모든 자료형을 함수에 담을 수 있어요.

void 매개변수 - 1
void 매개변수 - 2
void 매개변수 - 3
결과

void 포인터 매개 변수에는 변수의 메모리주소 뿐만 아니라 메모리를 할당한 포인터, 구조체, 공용체, 열거형 등의 포인터도 넣을 수 있습니다.

 

그전에는 반환값으로 메모리 주소를 반환 받았는데, 그럼 매개변수로도 메모리 주소(동적할당 된)를 얻을 수 있을까요?

함수에 포인터를 준 후 동적할당
결과 - 비정상적인 종료

여기서 제가 numPtr 포인터 변수 NULL초기화시켜 준 이유는 동적할당한 후 값을 역참조로 수정했을 때 수정 여부를 알기 위해서 입니다. 수정되지 않았다면 동적할당 또한 제대로 되지 않았다는 뜻이 되겠지요. 아직 확실한 건 없기 때문에 디버깅을 통해 알아보겠습니다.

에러 메세지

예외가 발생한 이유는 아무리 Ptr에 메모리를 할당해도 해당 함수 외부에서는 사용할 수 없기 때문입니다. (여기서 그전에 했던 동적할당한 뒤 반환했던 포인터 부분과 헷갈릴 수 도 있습니다. 하지만 그 때는 포인터 변수의 값함수를 호출해서 그 함수 안에서 따로 선언되었던 포인터 변수를 이용해 동적할당된 공간을 반환한거지 이처럼 바로 할당한 뒤 함수 외부에서 사용하지는 않았습니다. 유의해주세요)

 

그래서 함수 내부에서 할당 받은 공간을 외부에 사용하려면 이중 포인터를 사용하면 됩니다.

그럼 들어가기전 이중 포인터를 배운지 오래되셨으니 개념에 대해 한번 보고 가시죠.

이중 포인터 간단 설명
결과

지금 현재 프로그램의 흐름을 그림으로 표현하면 다음과 같습니다.

이중 포인터

Ptr이 역참조로 num의 값을 수정하고 Ptr_2가 그 흐름을 따라감으로써 20 이라는 값을 가지고 옵니다. 그러니까 여기선 이중포인터가 Ptr 즉, 포인터의 주소를 저장하는 용도로 사용되고 있습니다.

 

여기서 잠깐, 어떤 분들은 포인터를 역참조 하지 않은 상태 즉, 어떠한 연산을 수행하지 않은 선언 그대로의 상태를 출력하면 나오는 주소가 그 포인터의 주소라고 착각하시는 분들도 계시는데 아니에요.

포인터의 메모리 주소와 가지고 있는 주소
결과

포인터가 처음 가지고 있는 주소는 해당 포인터의 주소가 아니라 가리키고 있는 변수의 주소입니다. 

이중포인터 / 동적할당
결과

저희가 함수 안에 있던 변수 중 함수 외부로 끌어낼 수 있었던 변수들의 특징 중 하나는 *(Asterisk)가 사용되었다는 점입니다. 그래서 우리는 함수 안에서 Asterisk를 사용하기 위해 이중 포인터로 정의한 뒤 역참조를 통해 numPtr의 주소에 접근하는 것이죠.

포인터는 주소를 가리키는 목적성을 지니고 있기 때문에 변수의 주소를 담지 않으면, 을 사용할 수 없죠. 저희는 그전에 변수의 주소 대신에 malloc 함수를 사용해 공간(값을 저장 할)을 만들어주었는데요. 그 malloc 함수는 공간(값이 아닌)을 가리키기 때문에 주소(numPtr 가리키는 주소, 역참조 X, numPtr의 주소 X)에 malloc을 사용합니다. 

 

따라서 numPtr의 주소값(이중 포인터가 가리키고 있는 주소)을 함수로 전달하면 그 함수에서 Ptr을 역참조 합니다. 이 Ptr의 값은 numPtr의 주소값이므로 long ** 이라는 이중 포인터역참조 한것과 동일합니다. 이제 역참조 해준 상태(공간이 할당되지 않은 numPtr이 가리키는 주소)에 동적할당을 해줌으로써 이제 numPtr의 역참조를 통해 값을 사용할 수 있게 되었습니다.

1
2
2의 결과
3

여러분들은 여기서 &numPtr 즉, 단일 포인터의 메모리 주소이중 포인터와 같다는 점만 기억해주시면 됩니다.

 

함수에서 매개변수로 문자열을 받으려면 매개변수를 문자열 포인터로 지정하면 됩니다. 

문자열 매개변수
결과

함수를 호출할 때 문자열을 넣어주면 문자열의 주소매개변수에 전달됩니다.

매개변수 배열
결과

이처럼 매개변수로 배열 또한 줄 수 있기 때문에 "함수에 문자열을 주려면 무조건 포인터 형태로 줘야해!" 같은 불편한 상황은 생기지 않을거에요. 만약 매개변수배열을 받는다는 걸 확실히 해주고 싶다면 다음과 같이 매개변수[ ] (대괄호)를 사용하면 됩니다. 단, 대괄호 안에 들어가는 배열의 크기 생략합니다. (사실 얼마만큼의 배열 크기를 줄지 불확실한 상황에서 고정적으로 크기를 지정한다면 그것만큼 불편한건 없을겁니다.)

수정
결과

'C Language Basic' 카테고리의 다른 글

C Language [핵심정리] - 39  (0) 2021.07.18
C Language [핵심정리] - 38  (0) 2021.07.16
C Language [핵심정리] - 36  (0) 2021.07.09
C Language [핵심정리] - 35  (0) 2021.07.04
C Language [핵심정리] - 34  (0) 2021.07.01
Comments