상세 컨텐츠

본문 제목

7일차 학습내용 C언어 함수 파일

풀스텍과정

by 정태웅 2024. 5. 20. 09:20

본문

함수

함수는 자주 사용되는 코드를 한 곳에 모아놓은 것을 뜻합니다.

함수를 호출할 때 함수 안에 전달하는 값을 인수라고 하며 함수가 호출 된 뒤 함수 안에서 나오는 값을 반환값이라고 합니다. 반환값이 없는 함수는 반환값 자료형에 void를 지정합니다.

// 반환값과 매개변수가 없는 함수 정의
void 함수이름()
{
    코드;
}

함수();    // 함수 호출

반환값은 함수 안에서 return으로 반환합니다. 이때 반환값 자료형과 반환하는 값(변수)은 자료형이 같아야 합니다.

// 반환값이 있는 함수 정의
반환값자료형 함수이름()    // 반환값 자료형과 반환하는 값은 자료형이 같아야 함
{
    return 반환값;
}

변수 = 함수();      // 함수를 호출한 뒤 반환값을 변수에 저장

함수가 호출될 때 전달받은 값은 매개변수를 통해서 사용할 수 있습니다.

// 매개변수가 있는 함수 정의
반환값자료형 함수이름(자료형 매개변수1, 자료형 매개변수2)
{
}

함수(값1, 값2);    // 함수를 호출하면서 인수 전달

매개변수와 인수

함수 바깥에서 전달된 값이 저장되는 변수를 매개변수라 부릅니다.

int add(int a, int b)     // a와 b가 매개변수
{
    return a + b;
}

함수를 호출할 때 전달하는 값이나 변수를 인수라 부릅니다.

add(10 , 20);    // 10과 20이 인수

함수에서 포인터 매개변수와 반환값 사용하기

함수에서는 일반적인 값뿐만 아니라 포인터(메모리 주소)도 반환할 수 있습니다. 포인터를 반환하는 함수를 만들려면 반환값 자료형과 함수 사이에 * (애스터리스크)를 붙이면 됩니다.

// 포인터를 반환하는 함수 정의
반환값자료형 *함수이름()    // 반환값 자료형과 반환하는 값은 자료형이 같아야 함
{
    return 반환값;
}

단, 함수 안에서 & 연산자로 변수의 메모리 주소를 반환하면 안 됩니다. 매개변수와 함수 안에서 선언한 변수는 함수가 끝날 때 모두 사라집니다. 그러므로 함수 안에서만 쓸 수 있는 변수의 주소를 반환하면 안 됩니다.

함수에서 구조체 반환값 사용하기

함수에서 구조체를 반환할 때는 반환값 자료형에 struct 키워드와 구조체 이름을 지정한 뒤 return으로 구조체 변수를 반환합니다.

struct 구조체이름 함수이름()
{
    return 구조체변수;
}

구조체 포인터를 반환할 때는 반환값 자료형에서 구조체 이름과 함수 사이에 *를 붙인 뒤 return으로 구조체 포인터를 반환합니다.

struct 구조체이름 *함수이름()
{
    return 구조체포인터;
}

함수에서 구조체 반환값의 복사

함수에서 구조체 변수를 반환한 뒤 다른 변수에 저장하면 구조체의 내용을 모두 복사하게 됩니다. 구조체의 크기가 커지면 그만큼 공간이 더 필요하게 되므로 비효율적입니다.

struct 구조체이름 함수이름()
{
    return 구조체변수;
}

구조체변수 = 함수();     // 반환된 구조체의 내용이 모두 구조체 변수에 복사됨

malloc 함수로 구조체 포인터에 동적 메모리를 할당한 뒤 반환하면 구조체 복사가 일어나지 않아서 효율적입니다.

struct 구조체이름 *함수이름()
{
    // malloc 함수로 구조체 포인터에 메모리를 할당
    return 구조체포인터;    // 구조체 포인터 반환
}

포인터 = 함수();    // 포인터(메모리 주소)만 반환됨

free(포인터);       // 동적 메모리 해제

함수에서 포인터 매개변수 사용하기

함수에서 포인터를 매개변수로 지정하면 역참조로 값을 가져올 수 있습니다.

// 포인터를 매개변수로 사용하는 함수 정의
반환값자료형 함수이름(자료형 *매개변수1, 자료형 *매개변수2)
{
    *매개변수1 = 값;    // 역참조로 값 저장
}

함수(&변수);     // 함수를 호출하면서 변수의 메모리 주소(포인터) 전달
                // 함수에서 역참조로 저장한 값이 변수에 저장됨

함수에서 배열 매개변수 사용하기

함수에서 배열을 매개변수로 사용하려면 매개변수 이름 뒤에 [ ] (대괄호)를 붙이거나 포인터로 지정해줍니다.

// 배열을 매개변수로 사용하는 함수 정의
반환값자료형 함수이름(자료형 매개변수[])
{
}

// 매개변수를 포인터로 지정해도 배열을 받을 수 있음
반환값자료형 함수이름(자료형 *매개변수)
{
}

함수에서 2차원 배열 매개변수 사용하기

매개변수로 2차원 배열을 사용하려면 [ ] (대괄호)를 두 개 붙인 뒤 가로 크기를 지정합니다. 또는 매개변수 앞에 * (애스터리스크)를 붙이고 괄호로 묶은 뒤 대괄호에 가로크기를 지정하면 됩니다.

// 2차원 배열을 매개변수로 사용하는 함수 정의
반환값자료형 함수이름(자료형 매개변수[][가로크기])
{
}

// 2차원 배열을 매개변수로 사용하는 함수 정의
반환값자료형 함수이름(자료형 (*매개변수)[가로크기])
{
}

함수에서 구조체 매개변수 사용하기

매개변수로 구조체를 사용하려면 struct 키워드와 구조체 이름을 지정합니다. 구조체 포인터를 사용할 때는 구조체 이름 뒤에 *를 붙입니다.

반환값자료형 함수이름(struct 구조체이름 매개변수)
{
}

반환값자료형 함수이름(struct 구조체이름 *매개변수)
{
}

함수에서 가변 인자 사용하기

함수의 매개변수 개수가 정해지지 않은 방식을 가변 인자(가변 인수)라고 합니다. 단, 고정 매개변수는 1개 이상 있어야 합니다.

반환값자료형 함수이름(자료형 고정매개변수, ...)
{
}

가변 인자는 stdarg.h 헤더 파일에 정의된 va_list, va_start, va_arg, va_end로 사용합니다(그림 65-1, 그림 65-2 참조).

  • va_list: 가변 인자 목록. 가변 인자의 메모리 주소를 저장하는 포인터입니다.
  • va_start: 가변 인자를 가져올 수 있도록 포인터를 설정합니다.
  • va_arg: 가변 인자 목록 포인터에서 지정된 자료형만큼 값을 가져온 뒤 포인터를 순방향으로 이동시킵니다(다음 인자의 위치로 이동).
  • va_end: 가변 인자 처리가 끝났을 때 포인터를 NULL로 초기화합니다.
// 가변 인자 함수 선언 및 정의
void printNumbers(int args, ...)    // 가변 인자의 개수를 받음, ...로 가변 인자 설정
{
    va_list ap;    // 가변 인자 목록 포인터

    va_start(ap, args);    // 가변 인자 목록 포인터 설정
    for (int i = 0; i < args; i++)    // 가변 인자 개수만큼 반복
    {
        int num = va_arg(ap, int);   // int 크기만큼 가변 인자 목록 포인터에서 값을 가져옴
                                     // ap를 int 크기만큼 순방향으로 이동
        printf("%d ", num);          // 가변 인자 값 출력
    }

    va_end(ap);    // 가변 인자 목록 포인터를 NULL로 초기화
}

// 가변 인자 함수 호출
printNumbers(1, 10);
printNumbers(2, 10, 20);
printNumbers(3, 10, 20, 30);
printNumbers(4, 10, 20, 30, 40);

함수의 재귀호출

함수 안에서 함수 자기자신을 호출하는 방식을 재귀호출이라 합니다. 재귀호출은 알고리즘을 구현할 때 자주 사용합니다.

// 재귀호출로 팩토리얼을 구하는 함수
int factorial(int n)
{
    if (n == 1)      // n이 1일 때
        return 1;    // 1을 반환하고 재귀호출을 끝냄

    return n * factorial(n - 1);    // n과 factorial 함수에 n - 1을 넣어서 반환된 값을 곱함
}

재귀호출은 반드시 정지 조건을 만들어주어야 합니다. 정지 조건이 없으면 함수가 계속 호출되다가 스택 오버플로우 에러가 발생합니다.

함수 포인터 사용하기

함수 포인터는 함수를 저장하는 포인터를 뜻합니다. 함수 포인터를 활용하면 함수를 자유롭게 주고 받거나 함수 호출을 자동화 할 수 있습니다.

// 함수 포인터 선언
반환값자료형 (*함수포인터이름)();
int (*fp)();

// 매개변수가 두 개인 함수 포인터 선언
반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);
int (*fp)(int, int);

// 함수 포인터 배열 선언
반환값자료형 (*함수포인터이름[크기])(매개변수자료형1, 매개변수자료형2);
int (*fp[10])(int, int);

// 함수 포인터를 구조체 멤버로 사용
struct 구조체이름 {
    반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);
};
struct Calc {
    int (*fp)(int, int);
};

// 함수 포인터를 함수의 매개변수로 사용
반환값자료형 함수이름(함수포인터반환값자료형 (*함수포인터이름)(함수포인터매개변수자료형1, 함수포인터매개변수자료형2)) { }
void executer(int (*fp)(int, int)) { }

// 함수 포인터를 함수의 반환값으로 사용
함수포인터반환값자료형 (*함수이름(매개변수자료형 매개변수))(함수포인터매개변수자료형1, 함수포인터매개변수자료형2) { }
int (*getAdd())(int, int) { }

// typedef로 함수 포인터 별칭 정의
typedef 반환값자료형 (*함수포인터별칭)(매개변수자료형1, 매개변수자료형2);
typedef int (*FP)(int, int);

// 함수 포인터 별칭으로 함수 포인터 선언
함수포인터별칭 함수포인터변수;
FP fp;

파일 열기

파일 읽기/쓰기를 하기 전에는 fopen 함수로 파일을 열어야 합니다. 파일 열기에 성공하면 파일 포인터(FILE *)를 반환하고, 실패하면 NULL을 반환합니다.

FILE *fp = fopen(파일명, 파일모드);    // 파일 열기

파일 닫기

파일 읽기/쓰기 작업이 끝났다면 반드시 fclose 함수로 파일 포인터를 닫아줍니다. 파일 포인터를 닫지 않으면 메모리 누수 현상이 발생합니다.

fclose(파일포인터);    // 파일 포인터 닫기

파일 모드

파일을 열 때는 용도에 따라 다양한 파일 모드를 지정해야 합니다.

  파일 모드
파일 모드기능설명
"r" 읽기 전용 파일을 읽기 전용으로 엽니다. 단, 파일이 반드시 있어야 합니다.
"w" 쓰기 전용 새 파일을 생성합니다. 만약 파일이 있으면 내용을 덮어씁니다.
"a" 추가 파일을 열어 파일 끝에 값을 이어 씁니다. 만약 파일이 없으면 파일을 생성합니다.
"r+" 읽기/쓰기 파일을 읽기/쓰기용으로 엽니다. 단, 파일이 반드시 있어야 하며 파일이 없으면 NULL을 반환합니다.
"w+" 읽기/쓰기 파일을 읽기/쓰기용으로 엽니다. 파일이 없으면 파일을 생성하고, 파일이 있으면 내용을 덮어씁니다.
"a+" 추가(읽기/쓰기) 파일을 열어 파일 끝에 값을 이어 씁니다. 만약 파일이 없으면 파일을 생성합니다. 읽기는 파일의 모든 구간에서 가능하지만, 쓰기는 파일의 끝에서만 가능합니다.
t 텍스트 모드 파일을 읽거나 쓸 때 개행문자 \n \r\n을 서로 변환합니다. ^Z를 파일의 끝으로 인식하므로 ^Z까지만 파일을 읽습니다(^Z는 Ctrl+Z 입력을 뜻합니다).
b 바이너리 모드 파일의 내용을 그대로 읽고, 값을 그대로 씁니다.

서식을 지정하여 파일에 문자열 쓰기

fprintf 함수를 사용하면 서식을 지정하여 파일에 문자열을 쓸 수 있습니다.

// 서식을 지정하여 파일에 문자열 쓰기
fprintf(파일포인터, 서식, 값1, 값2, ...);

서식을 지정하여 파일에서 문자열 읽기

fscanf 함수를 사용하면 서식을 지정하여 파일에서 문자열을 읽을 수 있습니다.

// 서식을 지정하여 파일에서 문자열 읽기
fscanf(파일포인터, 서식, 변수의주소1, 변수의주소2, ...);

파일에 데이터 쓰기

fwrite 함수를 사용하면 파일에 데이터를 쓸 수 있습니다. 버퍼는 파일에 쓸 내용을 뜻하며 포인터(메모리 주소)를 넣어줍니다. fwrite 함수는 쓰기에 성공하면 성공한 쓰기 횟수가 반환됩니다. 여기서 성공은 쓰기 크기에 지정한 크기만큼 썼느냐를 기준으로 합니다.

// 파일에 데이터 쓰기
fwrite(버퍼, 쓰기크기, 쓰기횟수, 파일포인터);

파일에서 데이터 읽기

fread 함수를 사용하면 파일에서 데이터를 읽을 수 있습니다. 버퍼는 파일의 내용을 읽어서 저장할 공간을 뜻하며 포인터를 넣어줍니다. fread 함수는 읽기에 성공하면 성공한 읽기 횟수가 반환됩니다. 여기서 성공은 읽기 크기에 지정한 크기만큼 읽었느냐를 기준으로 합니다.

// 파일에서 데이터 읽기
fread(버퍼, 읽기크기, 읽기횟수, 파일포인터);

fread 함수로 파일에서 문자열이나 구조체를 읽을 때 반드시 버퍼를 0으로 초기화 해줍니다. 버퍼를 초기화하지 않으면 이전에 메모리에서 사용하던 값이 남아있게 됩니다. 따라서 NULL이 없어서 문자열의 끝을 찾을 수 없거나 구조체의 멤버에 의도치 않은 값이 들어갈 수 있으므로 주의해야 합니다.

파일에 문자열 쓰기

fputs, fwrite 함수를 사용하면 파일에 문자열을 쓸 수 있습니다. fwrite 함수를 사용하여 파일에 문자열을 쓸 때는 쓰기 크기에 문자열의 길이를 구해서 넣어줍니다.

// 파일에서 문자열 쓰기
fputs(문자배열, 파일포인터);
fputs(문자열포인터, 파일포인터);
fwrite(문자배열, strlen(문자배열), 1, 파일포인터);
fwrite(문자열포인터, strlen(문자열포인터), 1, 파일포인터);

파일에서 문자열 읽기

fgets, fread 함수를 사용하면 파일에서 문자열을 읽을 수 있습니다. fgets 함수는 지정된 버퍼 크기만큼 문자열을 읽습니다. 만약 파일에 \n이 있으면 \n까지 문자열을 읽습니다(\n도 포함).

// 파일에서 문자열 읽기
fgets(문자배열, 읽기크기, 파일포인터);
fgets(문자열포인터, 읽기크기, 파일포인터);
fread(문자배열, 읽기크기, 1, 파일포인터);
fread(문자열포인터, 읽기크기, 1, 파일포인터);

variable_file_read_01.c
0.00MB
variable_file_write_01.c
0.00MB
variable_function_01.c
0.00MB
variable_function_02.c
0.00MB
variable_function_03.c
0.00MB
variable_function_04.c
0.00MB
variable_function_05.c
0.00MB
variable_function_06.c
0.00MB
variable_function_parameter_01.c
0.00MB
variable_function_parameter_02.c
0.00MB
variable_function_parameter_array_set_eelemeent.c
0.00MB
variable_function_parameter_char_array_01.c
0.00MB
variable_function_parameter_char_point_01.c
0.00MB
variable_function_parameter_struct_01.c
0.00MB
variable_function_pointer_01.c
0.00MB
variable_function_pointer_02.c
0.00MB
variable_function_pointer_03.c
0.00MB
variable_function_pointer_04.c
0.00MB
variable_function_pointer_array_01.c
0.00MB
variable_function_recursive_01.c
0.00MB
variable_function_struct_01.c
0.00MB
variable_function_struct_point_01.c
0.00MB
variable_function_struct_point_02.c
0.00MB
c언어문제_240520.hwp
0.05MB

관련글 더보기