[c 언어] main 매개변수(파라미터)를 이용한 간단한 프로그래밍

2020. 10. 9. 19:17W.IT/W.C언어

앞에서 main 함수의 구조를 나타내 보았습니다. 

그중 main 함수의 매개변수(파라미터)에 대해선 따로 언급을 하지 않아 이번에 언급하려고 합니다.

 

main 함수의 매개변수란, 쉽게 말해 프로그램을 실행할 때 받아오는 값이라고 생각하시면 됩니다.


처음 c언어를 배울 때는 함수 안에 매개변수(파라미터) 값을 설정하지 않고 그냥 선언을 합니다.

 

int main()
{
	return 0;
}

 

 이렇게 배우는 것은 전 별로 좋다고 생각되지 않습니다.

이 방법이

                                    "프로그램 실행할 때 매개변수(파라미터)를 안 주면 되지 않아요?"

 라고 생각하실 수도 있으시겠지만, 실제로 문제가 없더라도 매개변수(파라미터)를 안 받아와서 문제가 없는 것이 아닙니다.

 프로그램을 실행할 때 무조건 매개변수(파라미터)를 건네받아 실행됩니다. 바로 실행 프로그램의 경로와 이름 그리고 개수입니다. 이것에 대해선 밑에 더 자세히 설명드리겠습니다.

 또한, 일반적으로 해당 프로그램에 대한 도움말이나 예시, 옵션을 실행할 때 매개변수(파라미터)로 받아옵니다.

            ex) -h(도움말 옵션)

 그러므로 매개변수(파라미터)가 없더라도 main 함수를 작성할 때 꼭 매개변수(파라미터)를 작성하는 습관을 들이시면 좋겠습니다.

 

정석적인 main 함수의 선언은 아래와 같습니다.

 

int main(int argc, char *argv[])
{
	return 0;
}

 

 프로그램을 실행 시 넣는 문자열(옵션)은 argv 포인터 배열에 들어가고 그 개수가 argc에 저장됩니다.
 기본적으로는 argc는 1이란 숫자를 가지고 들어오며, 1개의 해당되는 문자열(옵션) 값도 argv 0번째 포인터에 값이 들어갑니다.
이 값은 프로그램 명이라고 생각하시면 편합니다. 이 프로그램 명에는 프로그램 경로까지 포함될 수 있습니다.

 

 예를 들어보겠습니다.

test라는 프로그램을 실행하려고 합니다. 만약 현재 경로의 test라는 프로그램이 있다면, 또는 bash_profile에 해당 실행파일 경로가 저장되어 있다면, 

[won@localhost ~]$ test

라고 치셔서 실행시킬 것입니다. 그렇다면 test라는 문자열이 argv[0]에 저장되고 argc는 1이 저장되어 프로그램이 실행될 것입니다.

 

만약 다른 경로(./dir)의 해당 실행파일이 존재한다면

[won@localhost ~]$ ./dir/test

 라고 치시며 실행시킬 것입니다. 이때는 ./dir/test라는 문자열이 argv[0]에 저장됩니다.


 

 main 매개변수를 활용한 간단한 프로그램 예제를 통해 더 자세히 설명해드리겠습니다.

 

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

char    time_unit[2] = {0,};
int     t_value = 0;

int title()
{
    printf("====================================================\n");
    printf("        START TIMER\n");
    printf("    TIME UNIT : %c  TIME VALUE : %d\n", time_unit[0], t_value);
    printf("        made by won\n");
    printf("====================================================\n");

    return 1;
}


int timer_func()
{
    int     i;
    char    time_string[10];
    int     t_value_r = 0;

    memset(time_string, 0x00, sizeof(time_string));

    if(!strcasecmp(time_unit, "s"))
    {
        t_value_r = t_value;
        memcpy(time_string, "SECOND", 6);
    }
    else if(!strcasecmp(time_unit, "m"))
    {
        t_value_r = t_value * 60;
        memcpy(time_string, "MINUTE", 6);
    }
    else if(!strcasecmp(time_unit, "h"))
    {
        t_value_r = t_value * 60 * 60;
        memcpy(time_string, "HOUR", 4);
    }
    else
    {
        return 0;
    }

    for(i = 0; i < t_value_r; i++)
    {
        printf("\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
        printf("    set time :  %d %s (%d)\n", t_value, time_string, t_value_r);
        printf("    cuurent time :  %d SECOND\n", i);
        printf("    Achievement rate :  %.2f %%\n", (i/(double)t_value_r) * 100);
        printf("\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");

        sleep(1);
    }

}
int end()
{
    printf("\n====================================================\n");
    printf("        END TIMER\n");
    printf("    TIME UNIT : %c  TIME VALUE : %d\n", time_unit[0], t_value);
    printf("        made by won\n");
    printf("====================================================\n");

    return 1;
}

int main(int argc, char *argv[])
{
    if(argc == 3)
    {
        if(!strcasecmp(argv[1], "s") || !strcasecmp(argv[1], "m") || !strcasecmp(argv[1], "h"))
        {
            strcpy(time_unit, argv[1]);
            t_value = atoi(argv[2]);
        }
        else
        {
            printf("invalid second opt (%s)\n", argv[1]);
            printf("possible opt s,m,h\n");
            return -1;
        }
    }
    else
    {
        printf("===================================\n");
        printf("\t%s unit time \n",argv[0]);
        printf("\tunit : time unit \n");
        printf("\t\t s : second\n");
        printf("\t\t m : minute\n");
        printf("\t\t h : hour\n");
        printf("\ttime : it is time that you want\n");
        printf("ex) %s s 60\n",argv[0]);
        printf("it's mean 60초\n");
        printf("===================================\n");
        return -1;
    }


    title();

    timer_func();

    end();

    return 0;

}

 

위 프로그램은 간단한 타이머 프로그램입니다.

 

메인 함수를 살펴보자면 아래와 같습니다.

int main(int argc, char *argv[]) 
{
    if(argc == 3) /* argc 매개변수 체크 */
    {
        if(!strcasecmp(argv[1], "s") || !strcasecmp(argv[1], "m") || !strcasecmp(argv[1], "h"))
        {
            strcpy(time_unit, argv[1]);
            t_value = atoi(argv[2]);
        }
        else
        {
            printf("invalid second opt (%s)\n", argv[1]);
            printf("possible opt s,m,h\n");
            return -1;
        }
    }
    else /* argc 매개변수가 3이 아닐때 도움말 출력후 return */
    {
        printf("===================================\n");
        printf("\t%s unit time \n",argv[0]);
        printf("\tunit : time unit \n");
        printf("\t\t s : second\n");
        printf("\t\t m : minute\n");
        printf("\t\t h : hour\n");
        printf("\ttime : it is time that you want\n");
        printf("ex) %s s 60\n",argv[0]);
        printf("it's mean 60초\n");
        printf("===================================\n");
        return -1;
    }


    title(); /* 처음 들어온 매개변수 정보 출력 */

    timer_func(); /* 실질적으로 타이머 루프 */

    end(); /* 종료 출력 */

    return 0;

}

 

여기서 중요한 부분은 프로그램을 실행시키기 위한 도움말입니다. 

아무 옵션을 주지 않고 그냥 프로그램을 실행시켜 보겠습니다.

[won@localhost timer]$ ./timer 
===================================
        ./timer unit time 
        unit : time unit 
                 s : second
                 m : minute
                 h : hour
        time : it is time that you want
ex) ./timer s 60
it's mean 60초
===================================

 

위에서 argv[0]은 프로그램 명이 들어간다고 했습니다.

 그러므로 printf("\t%s unit time \n",argv[0]); 이라고 출력을 준 부분에는 ./timer unit time이라고 출력이 됩니다.

 

이것을 도움말에 맡게 옵션을 줘서 처리를 한다면, 

[won@localhost timer]$ ./timer  s  60

 

아래 로직으로 들어가게 됩니다.

 

if(!strcasecmp(argv[1], "s") || !strcasecmp(argv[1], "m") || !strcasecmp(argv[1], "h")) 
{ 
    strcpy(time_unit, argv[1]); 
    t_value = atoi(argv[2]); 
}

이 if문은 들어온 argv[1]의 값이 s, m, h인지 체크하며 맞다면 argv[1]과 argv[2]의 값을 전역 변수에 저장합니다.

 

strcasecmp 함수는 대소문자 구별 없이 매개변수(파라미터)로 준 앞의 문자열과 뒤의 문자열을 비교하여 맞으면 0을 앞 문자열이 크면 양수를 뒷 문자열이 크면 음수를 리턴해 주는 함수입니다.

 

그럼 뒤로 다양한 문자열(옵션)을 주면 어떻게 될까요? 

 argv[3] , argv[4] ... 형식으로 해당 argv 배열 값에 순차적으로 문자열이 저장됩니다.

 

보통 문자열(옵션) 값을 구분하는 건 공백입니다. 만약 문자열 안에 공백을 넣으시고 싶으시다면 문자열을 ""로 감싸시면 됩니다.

 

[won@localhost timer]$ ./timer  s  60    3(argc) 개의 옵션
(argv[0] == "./timer" , argv[1] == "s", argv [2] == 60)

[won@localhost timer]$ ./timer  "s  60"  2(argc)개의 옵션
(argv[0] == "./timer" , argv[1] == "s 60")

 

매개변수를 받아와 조건문을 통해 코딩하실 때도 마찬가지지만, 꼭 에러 처리! 필수입니다.

또한 받아올 argc값과 argv값을 잘 체크하셔야 합니다.


※ 제 글에서 부족하거나 잘못된 부분이 있다면 댓글로 남겨주시길 부탁드립니다.

※ 제 글은 제가 코딩하면서 지속해서 확인하기 위한 히스토리 성 정보들이자 회사 생활 중 실제 프로그램을 코딩하며 중요하거나 필요했던 정보들을 공유하기 위해 적은 글입니다.