ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C 언어 기초#6 함수와 변수, 가변매개변수함수, 순환함수
    Programming 기초/C Language 2023. 4. 11. 23:27

    *함수

    -> 반환형 함수이름 (매개변수1, 매개변수2) e.g) int add (int x, int y) { 함수 몸체 }

    c.f.) 타입이 동일한 두 개의 매개 변수를 선언할 때 변수를 정의하듯이 하면 오류가 발생한다. 즉 float형의 두 개의 매개 변수 x, y를 선언할 때 float x, y라고 하면 x는 float 타입으로 선언되지만 y는 타입이 없는 것으로 간주되어 int형으로 된다.

    -> 매개변수는 외부에서 전달되는 데이터가 저장되는 변수이다.

     

    *함수원형(function prototype)

    int compute_sum(매개변수1, 매개변수2);

    함수 원형은 컴파일러에게 미리 함수에 대한 정보를 주어서 함수의 매개 변수 검사, 반환형 검사 등을 하게 하기 위한 것. 

    //소수체크 프로그램
    
    #define _CRT_SECURE_NO_WARNINGS		//scanf error를 무시하고 사용하기 위한 정의.
    #include<stdio.h>
    
    int is_prime(int);
    int get_integer(void);
    
    main()
    {
    	int n, result;
    
    	n = get_integer();
    	result = is_prime(n);
    
    	if (result == 1)
    		printf("%d은 소수입니다.\n", n);
    	else
    		printf("%d은 소수가 아닙니다.\n", n);
    	return 0;
    }
    int get_integer(void)
    {
    	int n;
    
    	printf("정수를 입력하시오:");
    	scanf("%d", &n);
    	return n;
    }
    int is_prime(int n)
    {
    	int divisors = 0, i;
    	for (i = 1; i <= n; i++)
    	{
    		if (n % i == 0)
    			divisors++;
    	}
    	return (divisors == 2);
    }

    *라이브러리함수

    1.난수발생기(다음 링크 참고)

    http://aispiration.com/statistics/stat-random-number-generator.html

     

    #include <stdlib.h> // rand();

    rand()는 의사 난수(pseudo random number)를 생성하는 함수. 초기값에 따라서 나오는 순서가 어느 정도 결정되어 있는 난수.

    0부터 RAND_MAX까지 정수 생성. 비주얼 C++에서는 0x7fff(32767)으로 정의됨.

    srand() : srand()는 난수 발생기의 시드(seed)를 설정한다. 시드는 난수 발생기에서 다음 난수를 계산하기 위하여 사용하는 변수이다. 시드가 달라지면 전체 난수 수열이 변경된다. 시드를 설정하는 가장 일반적인 방법은 현재의 시각을 시드로 사용하는 것이다. 현재 시각은 실행할 때마다 달라지기 때문.

    [a, b] 구간에서의 난수 생선법 : a+rand()%(b-a+1)

     

    2. 현재 시각

    #include <time.h>

    time()

    1970년 1월 1일로부터 현재까지 경과된 시간을 초 단위로 반환한다.

    > (unsigned)time(NULL) -> ‘명시적인 형변환’ 참고.

     

    예제) 난수 발생기를 활용한 자동차 경주 게임.

    #include<stdlib.h>	// rand()원형 정의
    #include<stdio.h>	
    #include<time.h>	// time()원형 정의
    #include<conio.h>	// 콘솔입력함수_getch
    
    void disp_car(int car_number, int distance);
    
    int main(void)
    {
    	int i;
    	int car1_dist = 0, car2_dist = 0;
    
    	srand((unsigned)time(NULL));	// srand()는 난수 발생기의 시드를 설정한다. 일반적으로 현재 시각을 시드로 사용.
    
    	for (i = 0; i < 6; i++)
    	{
    		car1_dist += rand() % 100;	//rand()를 이용해서 난수 발생. %를 이용하여 0~99로 제한.
    		printf("%d\n", car1_dist);
    		car2_dist += rand() % 100;
    		disp_car(1, car1_dist);
    		disp_car(2, car2_dist);
    		printf("----------------------------\n");
    		_getch();		// getch()는 stido.h에서 제외됨. 이름만 다른 _getch()를 써야함.
    				// 사용자가 아무키나 누르기를 기다림.
    	}
    	return 0;
    
    }
    void disp_car(int car_number, int distance)	//주행거리만큼 *로 표시.10당 *하나
    {
    	int i;
    
    	printf("CAR #%d:", car_number);
    	for (i = 0; i < distance / 10; i++)
    	{
    		printf("*");
    	}
    	printf("\n");
    }

    *유틸리티 함수

    exit(int status) : exit()를 호출하면 호출 프로세스를 종료. 종료에 앞서 모든 버퍼들은 비워짐. 보통 1을 인수로 주어서 호출하면 오류가 발생했다는 것을 의미

    int system(const char *command) : system()은 문자열 인수를 운영 체제의 명령어 셀에게 전달하여서 실행시키는 함수. 외부 실행시킬 수 있는 프로그램이 존재하는 경우에 사용할 수 있다. 예를 들어서 DOS 명령어인 DIR이나 TYPE, CLS, DEL, MKDIR와 같은 명령어들을 실행시킬 수 있따. 이 함수는 운영체제에 의존적이다.

     

    *수학 함수 math.h

    수학 함수는 double형의 매개 변수와 반환값을 가진다.

     

     

     

    *범위(scope)= 가시성(visibility)

    : 변수가 어떤 범위에서 사용이 가능한가이다.

    지역 변수(local variable) : 함수 또는 블록 안에서 정의되는 변수. 지역 변수는 해당 블록이나 함수 안에서만 사용 가능.

    전역 변수(global variable) :함수의 외부에서 선언되는 변수. 전역 변수는 소스 파일의 어느 곳에서도 사용이 가능.

     

    *생존시간(life time)

    1. 정적 할당(static allocation) ; 프로그램이 실행되는 동안에는 계속하여서 변수에 저장 공간이 할당되어 있는 방법이다. -> 전역 변수 -> 전역 변수는 자동으로 0으로 초기화된다.

    2. 자동 할당(automatic allocation) : 블록이 시작되면서 변수에 저장 공간이 할당되고 블록이 종료되면 저장 공간이 회수되는 방법이다. -> 지역 변수

    - 지역 변수 앞에 저장 유형 지정자를 붙이면 정적 할당으로도 변경할 수 있다.

    - 저장 유형 지정자(storage class specifier) : auto, register, static, extern등 있다.

     

    auto 지정자 : 함수나 블록 내에 선언되는 지역 변수는 기본적으로 자동 할당이 된다. 이러한 지역 변수를 자동 변수(automatic variable)라고도 한다. “자동”이라고 하는 이유는 변수를 선언한 위치에서 자동으로 만들어지고 블록을 벗어나게 되며 자동으로 소멸되기 때문이다. 변수는 자신이 선언된 블록에서 사용이 끝나면 자동으로 메모리에서 제거되므로 메모리를 효율적으로 사용하게 된다. 함수나 블록 안에 선언된 변수는 auto 생략되어도 모두 자동 변수로 취급

    static 지정자 : 정적 변수는 전역 변수와 같이 프로그램이 시작할 때 메모리에 생성되고 프로그램이 실행을 종료하면 메모리에서 제거된다.

    register 지정자 : 변수를 메모리가 아닌 레지스터에 저장. 레지스터란 cpu만 사용하고 cpu의 일부분으로, 데이터를 읽고 쓰는 속도가 아주 빠르다. 특히 루프를 제어하는 변수는 레지스터로 하면 많은 성능의 향상을 가져올 수 있다. 최근의 컴파일러는 향상된 최적화 과정을 통해 이미 cpu의 레지스터를 적절하게 사용하고 있다. 주소를 추출하는 연산자 &을 적용하면 컴파일 오류가 발생한다. 레지스터는 주소가 없다.

    extren 지정자 : 외부 소스파일에 있는 전역변수를 참조하고자 할 때 사용. 하나의 전역 변수를 모든 소스 파일에서 공유하려면 보통 extern 파일 선언을 하나의 헤더 파일에 두고 이 헤더 파일을 모든 소스파일에서 포함시키게 된다.

    *연결(linkage)

    : 다른 범위에 속하는 변수들을 서로 연결하는 것을 의미.

     

    1. 무연결(no linkage): 지역 변수로서 외부와 연결을 가지지 않는다.

    2. 외부연결(external linkage): 전역 변수로서 여러 개의 소스 파일에 걸쳐서 사용된다.

    - 하나의 전역 변수를 선언하고 다른 파일에서는 extern 지정자를 사용하여 이 변수를 참조. extern을 붙여야 만이 컴파일러가 변수의 타입을 살 수 있기 때문에 컴파일이 가능. 이 키워드를 사용하지 않으면 전역 변수가 외부 연결 가능하다고 해도 다른 소스 파일에서 참조할 수 없음. (저장 공간 할당 x, 다만 외부에서 선언된 변수 사용 의미)

    -함수도 static, extern을 사용함.

     

    3. 내부 연결(internal linkage): 전역 변수로서 하나의 소스 파일에서만 사용이 가능하다.

    - 전역 변수가 내부 연결인지, 외부 연결인지를 지정하려면 저장 유형 지정자인 static을 사용하면 된다. 전역 변수 앞에 static이 붙으면 내부 연결이 된다. 즉 하나의 소스 파일 안에서만 사용이 가능하다. 전역 변수 앞에 static이 붙지 않으면 다른 소스 파일에서도 이 전역 변수를 사용할 수 있다.

    변수나 함수 이름은 모두 식별자고 같이 취급됨. 따라서 함수 이름 앞에도 static을 붙일 수 있고 그 의미도 변수와 비슷. 만약 특정 소스 파일에 있는 함수 이름 앞에 static이 붙어 있는 경우, 이 함수는 그 소스 파일 안에서만 사용이 가능. 즉 내부 연결이 되는 것. 이러한 함수를 정적 함수라고 한다. 함수 이름 앞에 static이 없으면 변수와 마찬가지로 다른 소스 파일에서 extern으로 선언하여 사용할 수 있다.

     

    *가변 매개 변수 함수

    가변 매개 변수 함수의 원형은 ...을 이용하여서 선언

    • va_list : 가변 인자 목록으로 가변 인자의 메모리 주소를 저장하는 포인터
    • va_start : 가변 인자를 가져올 수 있도록 설정
    • va_arg : 가변 인자 포인터에서 특정 자료형의 크기만큼 값을 꺼냄
    • va_end : 가변 인자 처리가 끝났을 때 포인터를 NULL로 초기화해준다.

    다음 블로그 참고.

    https://blog-of-gon.tistory.com/137

    #include<stdio.h>
    #include<stdarg.h>	//가변인자들을 제어하기 위한 라이브러리 헤더 파일
    
    int sum(int, ...);	// sum(인수 개수 지정, 인수1, 인수2 , ...)
    int main(void)
    {
    	int answer = sum(4, 40, 30, 20, 10); // 인수 개수는 4개, 인수로 40~10을 갖음.
    	printf("합은 %d입니다.\n", answer);
    
    	return(0);
    }
    
    int sum(int num, ...)		// num= 가변 매개변수 개수 
    {
    	int answer = 0;
    	va_list argptr;		//va_list 자료형타입 argptr 변수선언
    
    	va_start(argptr, num);		// 가변 매개 변수 기능 시작. 가변 매개 변수 
        					// 함수의 첫 번째 인수(num)는 매개 변수의 개수를 나타냄.
    	for (; num > 0; num--)		// 인수 개수만큼 va_arg()호출.
    		answer += va_arg(argptr, int);	// var_arg(포인터, int)가변 인자를 담은 목록 포인터에서 
            					// int크기만큼 값을 꺼내서 확인. 
    
    	va_end(argptr);	// 가변 매개 변수 기능 종료.
    	return(answer);
    }
    ---------------------------------------------------------------------------------
    실행 결과 
    합은 100입니다.
    ---------------------------------------------------------------------------------

     

    * 순환(recursion)

    자기 자신을 호출하는 함수.

    정수의 팩토리얼을 예로 들면,

    팩토리의 정의는 다음과 같다. 

    long factorial (int n)
    {
    	printf("factorial (%d)\n", n);
        
        if(n <= 1) return 1;
        else return n * factorial(n-1);
    }

    팩토리얼 함수의 순환 호출의 순서는 다음과 같다.

    순환 알고리즘은 자기 자신을 순환적으로 호출하는 부분과 순환 호출을 멈추는 부분으로 구성되어 있다.

     

    출처 : 쉽게 풀어쓴 C언어 Express

    댓글

Designed by Tistory.