관리 메뉴

나구리의 개발공부기록

Chapter 02 - C언어(함수) 본문

2024년도 수제비 실기책(6판) 내용 정리


12. 함수

1) main 함수

(1) main 함수 개념

 

  • 프로그램이 실행하는 모든 프로그램의 시작점, main 함수에 있는 명령어를 실행함

(2) main 함수 형태

자료형 main(파라미터) {
  명령어;
}
  • void main()일 경우 반환할 값이 없으므로 return; 이나 return문이 없어야 함
  • int main()일 경우 return 반환값;을 명시해 주어야 함
  • main함수나 사용자 정의 함수는 return을 만나면 그 즉시 함수를 종료함
void main int main
void main( ) {
  return;
}
int main( ) {
  return 반환값;
}
  • void는 함수를 호출한 호출자에게 결과값을 제공하지 않는다는 의미

2) 사용자 정의 함수

(1) 사용자 정의 함수(User-Defined Function) 개념

 

  • 사용자가 직접 새로운 함수를 정의하여 사용하는 방법
  • 매개변수나 생셩된 변수는 자용자 저으이 함수가 종료되면 없어짐
  • 매개변수(Parameter) : 함수를 호출할 때 인수로 전달된 값을 함수 내부에서 사용할 수 있게 해주는 변수

 

(2) 사용자 정의 함수 선언

자료형 함수명(자료형 변수명, ...) {
  명령어;
  return 반환값;
}

/*
에러 예시
C언어 에서 fn이라는 사용자 정의 함수가 main 함수 아래에 작성되고,
main함수에서 fn을 호출하는 경우에는 에러가 발생함
main에서는 fn을 모르기 때문 -> fn을 main 함수 위에 정의하거나,
fn이라는 것이 함수라는 것을 명시(선언)하여 문제를 해결할 수 있음
*/

fn(int a, int b);       // fn은 함수라는 것을 명시(선언)
int main( ) {
  fn(3, 5);
}

int fn(int a, int b) {  // fn함수를 main함수 밑에 정의
  ...
  return resutl;
}
#include <stdio.h>
char fn(int num) {  // char 타입 사용자정의 함수 fn 정의, parameter는 int 타입 변수 num
  if(num % 2 == 0)
    return 'Y';
  else
    return 'N';
}

int main() {
  char a = fn(5);  // 사용자 정의함수 fn을 호출하고 argument값을 5로 전달하여 연산 결과를 반환
                   // fn 함수의 연산결과는 'N'이 반환되여 a에 'N'이 저장됨
                   
  printf("%c\n", a);  // 문자형식으로 N 출력
  return 0;
}

 

(3) 매개변수 전달 방법

 

  • 매개변수 전달 방법(Parameter Passing Mechanism) 개념

    • 함수가 필요로 하는 값을 매개변수로 만들면 함수를 호출하는 쪽에서 매개변수를 사용하여 해당 함수에게 변수의 값, 변수의 주소값을 전달하는 방식
  • 매개변수 전달 방법 구성요소
    • 매개변수 전달 방법은 전달인자, 매개변수가 있음
구성요소 설명
전달인자
(Argument)
실 매개변수(Actual Parameters)로도 불림
함수를 호출하는 쪽에서 전달하는 변수의 값 또는 변수의 주소값
매개변수
(Parameter)
형식 매개변수(Formal Paramethers)로도 불림
함수를 선언하는 쪽에서 전달받는 변수의 값 또는 변수의 주소값
#include <stdio.h>

int fn(int x, int y) { // 매개변수
  ...
}

void main() {
  int i, j;
  ...
  fn(i, j); // 전달인자(Argument)
}

 

  • 매개변수 전달 방법 종류
종류 설명
Call by Value 변수의 값을 넘겨주고, 이 값은 새로운 공간에 할당되어 사용하는 방식
형식 매개변수의 어떠한 변화도 실 매개변수에 아무런 영향을 미치지 않음
Call by Reference 변수의 값이 아닌 변수가 사용 중인 메모리 공간의 주소를 넘겨주는 방식
실 매개변수의 주소를 형식 매개변수로 보냄
Call by Value Call by Reference
#include <stdio.h>
int fn(int x, int y) {
  ...
}

void main() {
  int i, j;
  ...
  fn(i, j);
}
#include <stdio.h>
int fn(int* x, int* y) {
  ...
}
void main() {
  int i, j;
  ...
  fn(&i, &j);
}
형식 매개변수(Formal Parameters)는 변수 선언과 동일하게 작성하고 실 매개변수(Actual Parameters)는 변수명을 작성 형식 매개변수(Formal Parameters)는 간접값 연산자(*)를 이용해 포인터 변수 선언과 동일하게 작성하고,
실 매개변수는(Actual Parameters) 주소연산자(&)를 이용해 변수의 주소값을 작성
#include <stdio.h>
int fn(int n) {
  n = 7;      // fn함수가 호출 되면 매개변수 n에 7을 대입
  return n;   // n값인 7을 반환
}

int main(){
  int n = 5;  // int타입 변수 n에 5을 저장
  fn(n);      // 전달인자로 n(5)를 넣어서 fn함수를 호출
              // fn함수의 return값을 저장할 변수가 없으므로 아무일도 일어나지 않음
              
  printf("%d" ,n); // fn함수의 return값이 아닌 처음 main 메서드안의 변수 n에 저장된 값 5가 출력됨
  return 0;
}
// 출력 : 5
#include <stdio.h>
int fn(int* m) { // 사용자 정의 함수, 포인터 변수 m에는 전달받은 변수의 주소값이 저장되어 있음
  *m = 7;        // 포인터 변수 m이 가르키는 값(매개변수의 주소값)에 7을 대입
                 // fn함수에서 argument 변수의 값이 변경되어 버림
}

int main() {  // 프로그램을 실행하는 main 함수

  int n = 5;  // int 변수 n에 5를 저장
  int o[3] = {1, 2, 3};  // int 변수 o에 길이가 3인 배열에 1,2,3을 초기화하여 저장
  int i;   // int i를 선언
  
  fn(&n);    // fn함수의 argument로 변수n의 주소값을 전달 -> n이 7이 됨
  fn(&o[1]); // fn함수의 argument로 배열o의 [1]번째 인덱스의 주소값을 전달 -> o[1]이 7이됨
  
  printf("%d\n", n); // 변경된 n의 값 7이 출력됨
  
  for(i=0; i<3; i++) // 배열의 값을 반복문으로 돌려서 출력
    printf("%d", o[i]);  // o[i]의 값이 7로 변경되었으므로 171이 출력됨
    
  return 0;
}

 

(4) 재귀함수

 

  • 재귀 함수(Recusive Function)의 개념 : 함수 자신이 자신을 부르는 함수
  • 재귀 함수 선언
자료명 함수명(자료형 변수명, ...) {
  ...
  함수명(변수명, ...)
  ...
  return 반환값;
}
#include <stdio.h>
int fn(int n){

  if(n <= 1) // 매개변수의 값이 1 이하면 1를 반환
    return 1;
    
  else
    return n*fn(n-1);  // 자기 자신을 호출하여 연산결과와 n의 값을 곱한 값을 반환
    
    // 재귀함수는 스택연산 -> 스택을쌓아 두다가 끝까지 다했으면 다시 돌아가면됨
    // 최초 매개변수 n에 3이 들어왔으므로 else문이 실행 3*fn(2)로 fn함수가 다시 호출
    // 반복되어 매개변수 n이 값이 2가되고 다시 else문이 실행되고 2*fn(1)로 fn 함수가 다시 호출
    // n이 1이되면 if문으로가서 1을 반환, 2 * fn(1) 이 2 * 1이되어 2를 반환
    // 2를 반환하여 3 * fn(2)가 3 * 2가 됨,
    // 최종적으로 6을 반환
}

int main() {
  printf("%d", fn(3)); // fn 함수에 argument값으로 3을 넣은 연산결과를 10진수 정수 형태로 출력, 6출력
  return 0;
}

3) 표준 함수

(1) 문자열 함수

 

  • strcat(String Concatenate) : 문자열끼리 연결하는 함수
strcat(dest, src); src의 문자열을 dest 문자열 뒤에 붙임
strncat(dest, src, maxlen); src의 문자열에서 maxlen의 개수만큼 dest 문자열 뒤에 붙임

 

  • strcpy(String Copy) : 문자열을 복사하는 함수
strcpy(dest, src); src의 문자열을 dest 문자열에 복사
strncpy(dest, src, maxlen); src의 문자열에서 maxlen의 개수만큼 dest 문자열에 복사
#include <stdio.h>
#include <string.h>  // 문자열 삼수를 사용하기 위한 헤더파일

int main() {
  char a[20] = "Hello";
  char b[10] = "Soojebi";
  char c[20] = "Hello";
  
  strcat(a, b);  // a의 문자열 뒤에 b의 문자열을 붙임
                 // a = HelloSoojebi가 됨
  printf("%s %s\n", a, b); // HelloSoojebi Soojebi가 출력됨
  
  strncat(c, b, 3);  // c의 문자열 뒤에 b의 문자열을 앞에 3개만 붙임
                    // c = HelloSoo가 됨
  printf("%s %s\n", c, b);  // HelloSoo Soojebi가 출력됨
  
  strcpy(a, b);  // b의 문자열을 a문자열에 복사
                 // a = Soojebi
  printf("%s %s\n", a, b);  // Soojebi Soojebi 출력
  
  strncpy(c, b, 3);  // b의 문자열의 앞에서 3개의 문자열을 c문자열에 복사 
                     // C == Soolo가 됨(앞에서 3개만 바뀌고 남은 자리의 문자열은 유지)
  printf("%s %s\n", c, b);  // Soolo Soojebi가 출력됨
  
  return 0;
}

 

  • strcmp(String Compare) : 문자열을 비교하는 함수

    • strcmp는 사전 배열 방식과 유사함, 문자열의 첫번째 문자끼리 비교하고, 다르면 아스키 코드 값을 통해 크고 작음을 판별하는 방식으로 마지막 문자까지 비교하여 같으면 같다라고 판별
    • ASCII 코드를 비교하여 s1이 s2보다 크면(s1 > s2) 1을, s1과 s2가 같으면(s1 == s2) 0을, s1이 s2보다 작으면(s1 < s2) -1을 반환함
strcmp (s1, s2); s1, s2의 대소를 비교
strncmp ( s1, s2, maxlen); maxlen 길이만큼만 s1, s2의 대소를 비교
#include <stdio.h>
#include <string.h>

int main() {
  char a[10] = "HelloA";
  char a[10] = "HelloB";
  
  int c = strcmp(a, b); // a와 b를 전체 비교한 결과값을 반환, a와 b는 다르므로 -1 반환
  printf("%d\n", c);    // -1을 출력
  
  c = strncmp(a, b, 3); // a와 b를 앞에서 3개만 비교한 결과값을 반환, 3개만 비교하면 같으므로 0 반환
  printf("%d\n", c);    // 0 출력
  
  return 0;
}

 

  • strlen(String Length) : 문자열의 길이를 알려주는 함수
  • strrev(String Reverse) : 문자열을 거꾸로 뒤집는 함수 (비표준 함수로 일부 컴파일러에서 동작 안함)
  • strchr(String find Character) : 문자열 내에 일치하는 문자가 있는지 검사하는 함수
strlen(s); s의 길이를 알려줌
strrev(str); maxlen 길이만큼만 s1, s2의 대소를 비교
strchr(str, c); str내에 c가 존재하는지 알려줌

 

#include <stdio.h>
#include <string.h>

int main() {
  char a[20] = "Hello";
  int c = strlen(a);  // a의 길이를 c에 저장
  printf("%d\n", c);  // 5
  
  strrev(a);          // 문자배열 a를 뒤집음(Null값은 제외)
  printf("%d\n", a);  // olleH
  
  strrev(a);          // 원복
  char* p = strchr(a, 'l');  // 배열 a에 문자 'l'이 처음으로 나온 위치를 반환하여 포인터 변수p에 저장
  printf("%s", p);           // 문자열 타입으로 p의 값을 출력 llo(처음l의 위치부터 끝까지 출력)
  
  return 0;
}

 

(2) 수학 함수

 

  • sqrt : 양의 제곱근을 계산하는 함수
sqrt(n); √n 의 값을 계산
양의 제곱근은 소수(약수가 1과 자기 자신만 있는 숫자)를 확인할 때도 사용함
 - a라는 값의 소수를 확인할 때,
 - 2 ~ (a-1)의 모든 정수들로 나눴을 때 나누어 떨어지지 않는지 확인
 - 2 ~ √a의 정수들만 나누어 떨어지지 않는지 확인, 위의 방법보다 확인해야할 숫자가 줄어듦
101이 소수인지 아닌지 구하기 2부터 √101(=10.05)이하의 정수인 10까지 나눠 떨어지는지만 확인하면 됨

 

  • ceil : 소수점 올림 함수
  • fllor : 소수점 내림
ceil(n); n의 값을 소수점 올림
floor(n); n의 값을 소수점 내림
#include <stdio.h>
#include <math.h>    // 수학 함수를 사용하기 위한 헤더파일선언
int main() {
  double a;
  a = sqrt(5.1);     // a에 5.1의 제곱근의 값을 저장
  
  printf("%.2f", a); // 소수점 두번째자리까지만 실수형식으로 출력, 2.26
  
  double b = 1.1;
  printf("%.2f", ceil(b));    // b의 값을 소수점 올림하여 값을 출력, 2.00
  printf("%.2f", floor(b));   // 소수점 내림하여 값을 출력, 1.00
  
  return 0;
}

 

(3) 유틸리티 함수

 

  • rand(Random) 함수 : 임의의 값을 생성하는 함수
  • srand(Seed Random) 함수 : 난수 생성 알고리즘에 사용하는 seed를 정해주는 함수, rand함수를 사용할 때 해당 seed 값에 해당하는 난수 패턴으로 생성
  • time 함수 : 현재 시간을 가져오는 함수, 1970년 1월 1일 이후로 몇 초가 경과했는지를 나타냄
rand(); 임의의 정숫값 1개를 생성
srand(seed); seed 값에 따라 난수 발생기를 초기화 시킴

컴퓨터는 난수를 난수 생성 알고리즘에 의해서 만드는데, 난수 생성 알고리즘의 seed값이 같으면 프로그램이 실행할 때마다 계속 똑같은 패턴의 난수를 만들게 되어 seed값을 프로그램 시작할 때마다 다르게 하도록 seed에 time 함수를 하용함
time(NULL); time 함수에 파라미터를 NULL로 하면 현재 시간을 리턴
현재 시간이 1970년 1월 1일 0시 0분 1초이면 1, 2초이면 2 이런식으로 값이 1씩 증가 됨
#include <stdio.h>
#include <stdlib.h>  // rand 함수를 사용하기 위한 헤더파일 선언
#include <time.h>    // time 함수를 사용하기 위한 헤더파일 선언

int main() {
  int a;
  int i;
  
  srand(time(NULL));     // seed값을 현재시간으로 주어 rand함수가 랜덤한 값을 가져오도록 선언
  for(i=0; i<6; i++) {   // 6번 반복
    a = rand()%45+1;     // a에 랜덤 정수값을 45로 나눈 나머지에 +1을 연산하여 저장
// rand()%45를 하면 0 ~ 44의 숫자가 나오는데 +1을 하여 1 ~ 45의 랜덤 숫자가 나오도록 설정
    printf("%d ", a);    // a의 값을 출력
  }
  
  return 0;
}
  • atoi(ASCII to Integer) 함수 : 문자열을 정수형으로 변환하는 함수
  • atof(ASCII to Floating Point) 함수 : 문자열을 실수형으로 변환하는 함수
  • itoa(Integer to ASCII) 함수 : 정수형을 문자열로 변환하는 함수
atoi(str); 문자열(str)을 정수(int)형으로 변환
atof(str); 문자열을 실수(float)형으로 변환
itoa(value, str, radix) value를 변환하여 str에 radix 진수로 저장
문자열을 저장하기 위해서 일반적으로 배열을 사용하지만 문자형 포인터를 생성하면서 문자열을 대입할 수도 있음
변수 선언시 *가 붙어있으면 포인터 변수, char* a라고하면 a는 문자형 변수가 아닌 문자형 포인터 변수임