본문 바로가기
Language/C언어

C015_함수에 대해

by OdOp 관리자 2023. 9. 17.
SMALL

기본적인 함수 틀

반환값자료형 함수이름()
{
    코드;
    return 반환값;
}

기본적인 틀은 위와 같다. 

반환값 자료형은 함수의 결과물이 어떤 자료형이 되는 것인지 지정해 줍니다.  예를 들어 int라면 정수형을 return 할 것이고 void라면 return을 사용하지 않아도 된다. 

크게 말하면 'int main()'도 정수형 main함수이다. 

 

기본적인 함수의 예

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>  
#include <stdbool.h>  //bool, true, false 함수가 정의된 헤더 파일

int one()
{
    return 1;
}

float realNumber()
{
    return 1.234567f;
}

bool truth()
{
    return true;
}

int main()
{
    int num1;
    float num2;
    bool b1;

    num1 = one();  //int형을 반환했으므로 int형 변수에 저장합니다. 
    num2 = realNumber();  //float형을 반환했으므로 float형 변수에 저장합니다. 
    b1 = truth();  //bool형을 반환했으므로 bool형 변수에 저장합니다. 
    printf("%d\n", num1);
    printf("%d\n", one());  //one 함수의 반환값을 바로 사용합니다.
    printf("%f\n", num2);
    printf("%f\n", realNumber());
    printf("%d\n", b1);
    return 0;
}

int형, float형, bool형 함수를 만들어서 각각 실행하는 모습입니다. 

 

 

이번에는 위의 예제를 포인터로 바꾸어서 포인터 함수를 만들어 보겠습니다. 

포인터 함수

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>  
#include <stdbool.h>  //bool, true, false 함수가 정의된 헤더 파일 
#include <stdlib.h>  //malloc, free 함수가 선언된 헤더 파일 
#include <string.h>

int* one()
{
    int* numPtr = malloc(sizeof(int));  //int 크기만큼 동적 메모리 할당합니다. 
    *numPtr = 10;  //역참조로 10저장합니다. 
    return numPtr;  //포인터 반환하고 malloc으로 메모리를 할당하면 함수가 끝나도 사라지지 않습니다. 
}

float* realNumber()
{
    float* realnumber = malloc(sizeof(float));
    *realnumber = 1.234567f;
    return realnumber;
}

bool* truth()
{
    bool* truth = malloc(sizeof(bool));
    *truth = true;
    return truth;
}

char* helloLiteral()  //char 포인터르 반환하는 helloLiteral 함수 정의
{
    char* s1 = "Hello, world!";
    return s1;  //문자열 Hello, world!는 메모리에 저장되어 있으므로 사라지지 않습니다. 문자열 포인터 리턴해줍니다. 
}

char* helloDynamicMemory()  //char 포인터를 반환하는 helloDynamicMemory 함수 정의
{
    char* s1 = malloc(sizeof(char) * 20);  //char 20개 크기만큼 동적 메모리 할당합니다. 
    strcpy(s1, "Hello, world!");  //"Hello, world!"를 s1에 복사해줍니다. 
    return s1;  //문자열 포인터 리턴합니다. 
}

//자료형에 상관없이 값을 꺼내오고 싶다면?
void* allocMemory()  //void 포인터를 반환하는 allocMemory 함수 정의 
{
    void* ptr = malloc(100);  //100바이트만큼 동적 메모리 할당합니다. 
    return ptr;  //void 포인터 반환합니다. 
    //return malloc(100);
}

int main()
{
    int* num1;
    float* num2;
    bool* b1;
    char* s1;
    char* s2;
    char* s3;
    int* numPtr1;

    num1 = one();  //int형 포이터를 반환했으므로 int형 포인터 변수에 저장합니다. 
    num2 = realNumber();  //float형 포인터를 반환했으므로 float형 포인터 변수에 저장합니다. 
    b1 = truth();  //bool형을 포인터를 반환했으므로 bool형 포이인터 변수에 저장합니다. 
    s1 = helloLiteral();
    s2 = helloDynamicMemory();
    s3 = allocMemory();  //void 포인터를 char 포인터에 넣어서 문자열처럼 사용합니다.
    strcpy(s3, "Hello, world!");
    numPtr1 = allocMemory();  //void 포인터를 int 포인터에 넣어서 정수 배열 처럼 사용합니다. 
    numPtr1[0] = 10;
    numPtr1[1] = 20;

    printf("%d\n", *num1);
    printf("%d\n", *one());
    printf("%f\n", *num2);
    printf("%f\n", *realNumber());
    printf("%d\n", *b1);
    printf("%d\n", *truth());
    printf("%s\n", s1);
    printf("%s\n", s2);
    printf("%s\n", s3);
    printf("%d %d\n", numPtr1[0], numPtr1[1]);
    //동적 메모리는 함수를 벗어나도 계속 유지되므로 메모리를 해제하지 않으며 그대로 메모리 누수가 발생하게 됩니다. 
    free(s2);
    free(s3);
    free(numPtr1);
    return 0;
}

이번 코드는 많이 기네요.....

위의 함수를 포인터로 사용한 것입니다. malloc을 사용하여 동적할당을 합니다. 즉, 변수의 내용물이 들어갈 공간을 만듭니다. 그 후 역참조해서 넣어주면 됩니다. 

완전히 새롭게 보이는 함수가 char형 포인터 함수와 void형 포인터 함수가 있습니다. 

helloLiteral은 메모리 주소에 바로 할당을 해주는 모습이고, 

helloDynamicMemory는 동적할당을 진행한 후에 할당해 주는 모습입니다. 

void형 포인터 함수는 함수를 정의한 후에 나중에 자료형을 정할 수 있는 장점이 있습니다. 위의 예제에서는 메모리를 넉넉하게 할당을 해준 후에 int배열과 문자열로 할당을 해준 모습입니다.

 

구조체 함수

#include <stdio.h>
#include <stdlib.h>  //malloc, free 함수가 선언된 헤더 파일 
#include <string.h>  //strcpy 함수가 선언된 헤더 파일

struct Person {
	char name[20];
	int age;
	char address[100];
};

//여러개의 반환값을 얻고 싶을 때
struct Person getPerson()  //Person 구조체를 반환하는 getPerson 함수 정의 
{
	struct Person p;
	strcpy(p.name, "홍길동");
	p.age = 30;
	strcpy(p.address, "서울시 용산구 한남동");
	return p;  //구조체 변수 반환
}

struct Person* allocPerson()  //Person 구조체 포인터를 반나하는 allocPerson 함수 정의
{
	struct Person* p = malloc(sizeof(struct Person));  //구조체 포인터에 동적 메모리 할당
	strcpy(p->name, "홍길동");
	p->age = 30;
	strcpy(p->address, "서울시 용산구 한남동");
	return p;
}

int main()
{
	struct Person p1;
	struct Person* p2;

	p1 = getPerson();  //반환된 구조체 변수의 내용이 p1로 모두 복사됨
	p2 = allocPerson();  //포인터를 반환하여 p2에 메모리 주소 저장

	//getPerson에서 저장한 값이 출력됨
	printf("이름: %s\n", p1.name);
	printf("나이: %d\n", p1.age);
	printf("주소: %s\n", p1.address);
	//allocPerson에서 저장한 값이 출력됨
	printf("이름: %s\n", p2->name);
	printf("나이: %d\n", p2->age);
	printf("주소: %s\n", p2->address);
	free(p2);
	return 0;
}

구조체 함수는 여러개의 반환값을 얻고 싶을 때 사용합니다. 

구조체 함수의 원형은 아래와 같습니다. 

//구조체룰 반환하는 함수
struct 구조체이름 함수이름()
{
	return 구조체변수;
}

//구조체 포인터를 반환하는 함수
struct 구조체이름 *함수이름()
{
	return 구조체 포인터;
}

저희는 구조체를 반환하는 함수로 getPerson을 사용했고, 구조체 포인터를 반환하는 함수로 allocPerson을 사용했습니다. 

getPerson함수는 구조체를 선언한고 구조체의 변수에 값을 할당해 주었습니다. 

allocPerson함수는 구조체 포인터를 선언하고 malloc을 통해 동적 메모리를 할당했습니다. 그 후에는 똑같이 구조체의 변수에 값을 할당해 주었습니다. 

LIST

'Language > C언어' 카테고리의 다른 글

C017_함수, 가변인자 사용하기  (0) 2023.09.19
C016_함수, 매개변수 사용  (0) 2023.09.18
C014_구조체 정렬하기  (0) 2023.09.16
C013_구조체 포인터 사용하기  (0) 2023.09.15
C012_struct, 구조체에 대해  (0) 2023.09.14