티스토리 뷰

C언어

C언어 함수/표준출력함수

블로그 강승 2021. 3. 11. 14:29

C언어 함수/표준출력함수

C언어 함수/표준출력 함수에 대해 요약했다. Do it! C언어 입문(저자:김성엽) 이란 책을 통해 공부했으며, 책의 카테고리를 바탕으로 필자가 이해한 내용을 요약하는 글이다. 내용이 궁금하거나 찾아야 할 내용이 있으면, 필자가 정리한 글을 다시 보면서 복습하기위해 작성했다. 바로 아래에서 글을 확인하도록 하자.

 

함수

프로그램을 만들 때 명령을 그냥 계속 쭈욱 나열하면 지금 당장엔 문제가 없을지 모르지만,
오류를 찾거나 품질 개선을 할 때 다시 보게 될 텐데 코드를 분석하기가 굉장히 어려워진다.
그래서 특정한 목적을 위한 소스코드의 모음을 함수로 이름 짓고 그룹화한다.

 

특별한 기능을 가진 main 함수

main 함수는 모든 함수들보다 먼저 실행되는 '시작' 하는 함수임.

함수의 형태

1. 반환형

반환형이란 함수의 반환값의 자료형이다.

 

2. 함수이름

함수의 이름이다. 여기선 'Sum' 이다.

 

3. 매개변수(Parameter)

value1, value2가 매개변수인데, 함수가 호출될 때 필요한 정보를 호출자에서 sum이란 함수로 넘겨주는 역할을 한다.
작업내용에서 그대로 사용할 수 있다.
※호출자(Caller) : 함수를 호출하는 함수, 피호출자(Callee) : 호출되는 함수

/* 매개변수가 없는 함수*/
int Sum()
int Sum(void)
/*파라미터 들어가는 공간에 아무것도 안넣거나 void를 쓰면됨*/

 

4. 반환값

함수가 끝날 때 원래 함수로 가기 전에 반환 값을 가지고 갈 수 있다.
반환 값이 없을 때는 return 뒤에 바로 세미콜론이 오면 되고,
반환형 int 자리에 void(반환 값 형태가 없음을 뜻함)를 입력하면 된다.

 

5. 작업내용

함수 Sum에서 실행하는 작업을 {} 안에 넣어준다.

 

return의 또 다른 역할

void text(int value1, int value2)
{
int a=5;
return; /*return은 함수 종료를 뜻하기도함.*/
a = a+1; /* return;에서 함수가 종료됐기때문에 a=a+1은 실행되지 않음. */
}

 

함수 이름 짓는 방법

변수 이름 짓는 방법이랑 똑같음.

 

main 함수 정리하기

mian 함수는 최소 1개 있어야 하고 2개 이상 있으면 안 됨.
그리고 기본적으로 반환형이나 매개변수를 사용자가 별도로 정할 수 없음.
하지만 몇 가지 정해진 형식을 사용할 순 있음.

 

1. main 함수의 반환값

프로그램은 많은 함수들로 이루어 저 있음. 하다 보면 프로그램 A가 프로그램 B를 열 수 도 있는데,
프로그램 B가 잘 완료됐다는 걸 프로그램 A로 보낼 때,
main함수의 자료형을 int로 하고 return 1;을하면 1이 프로그램 A로 가고,
그로 인해 프로그램 B가 잘 완료됐다는 걸 알 수 있음.

/*반환이 필요한경우 :int 사용*/
int main()
{
return 1;
} /*return 값으로 꼭 1을 보내야하는건 아님. 프로그래머 마음임*/

 

2. main 함수의 매개변수

명령 프롬프트(cmd)에서 C 프로그램을 실행할 수도 있음.
이때 실행 파일 이름을 포함해서 실행 인자가 들어가는데, 이걸 매개변수로 받게 된다면 이렇게 받을 수 있음.

void main(int argc, char *argv[])
{
/* argc에는 실행인자의 개수, argv에는 실행 인자인 실행파일 이름을 포함해서 실행인자가 들어감 */
}

 

함수 원형

int Sum(int value1, int value2);

이런 식으로 함수 이름, 매개변수, 반환 자료형을 포함하는 표현식임.
컴파일러의 번역 순서는 위에서 아래로 번역한다.

void main()
{
int s;
s=Sum(2,3);
}

int Sum(int value1, int value2)
{
int result = value1 + value2;
}

위와 같이 프로그램을 짠다면 오류가 난다. 왜냐하면 위에서 아래로 번역을 시작했을 때
s=Sum(2,3);을 컴파일러가 본 순간, Sum이란 함수를 본 적이 없기 때문에 어떻게 할지를 모른다.
따라서 함수 원형이 없이 쓰려면

int Sum(int value1, int value2)
{
int result = value1+value2;
return result;
}

void main()
{
int s;
s=Sum(2,3);
}

이런 식으로 위에 Sum 이란 함수를 컴파일러가 미리 보게 하고 main 함수에서 Sum 이란 함수를 쓰면 오류가 없다.
하지만 함수 원형을 쓰면 main 함수가 가장 위에 위치해있을 수 도 있다.

int Sum(int value1, int value2);

void main()
{
int s;
s=Sum(2,3);
}

int Sum(int value1, int value2)
{
int result = value1+value2;
return result;
}

 int Sum(int value1, int value2);라는 모양으로 함수 원형을 선언해 놓으면,
컴파일러가 위에서 아래로 해석하면서 main 함수에 Sum(2,3);이 선언되기 전에
Sum이란 함수가 선언될 수 있겠구나 하고 참조할 수 있기 때문에 오류가 안 난다.

 

라이브러리의 필요성

소스파일(*. c)을 컴파일하면 목적파일(*.obj)가 만들어지고 링크를 하면 실행파일이 만들어진다.
목적 파일의 필요성은 앞서 확인한 바가 있다. 하지만 프로그램을 하다 보면 모든 소스파일을 컴파일해야 할 때가 있다고 한다. 그럴 때, 소스파일 중에 절. 대. 변경할 일 없는 소스파일은 목적 파일 형태로 가지고 있다면 모든 소스파일을 컴파일할 때, 없으니 컴파일 소요시간이나 작업량을 확실히 줄일 수 있다. 하지만 목적 파일을 가지고 있는 것도 비효율 적인 면이 있다. 목적파일에 만약 100개의 함수가 정의돼 있다고 가정하자, 그중에 1개의 함수를 사용했는데 그러면 실행파일에 1개의 함수만 적용되는 게 아니라 나머지 99개의 함수가 적용된다.
그래서 라이브러리가 필요하다. 라이브러리는 목적파일을 변형한 건데, 거기에 100개의 함수가 선언돼 있다고 해서 모든게 실행파일로 적용되지 않고, 사용한 함수만 실행파일로 적용된다.
그리고 한 가지 더, 라이브러리랑 목적 파일은 이미 컴파일된 파일이라 기계어기 때문에  다른 사람들이 보면 무슨 말인지 못 알아먹는다. 그래서 보안적으로도 좋다(같이 사용해야 할 때).

 

헤더 파일의 필요성

라이브러리의 필요성은 잘 알아봤다. 회사 동료에게 라이브러리를 공유했다고 치자. 회사 동료는 라이브러리에 있는 함수를 이용하려면 함수 원형을 선언해야 한다. 하지만 라이브러리는 기계어로 선언돼 있어서 그 안에 있는 함수와 함수 내용을 전혀 확인할 수 가없다. 그래서 헤더 파일에서 함수 원형 선언을 하고 그걸 참조하면, 라이브러리 안에 있는 함수를 사용할 수 있게 된다. 물론 헤더파일 없이 함수 원형을 선언해도 되지만, 라이브러리 안에 함수가 100개가 있다면 100개를 선언해야 하는데, 언제 함수원형을 100개를 타자 치고 있을 건가? 그래서 미리 헤더파일에 100개를 선언해놓고 그걸 참조해버리면 모든 게 해결된다.

 

전처리기

프로그래머가 원하는 사항을 컴파일러에 직접 지시하는 문법을 전처리기(Preprocessor) 라고함.
전처리기 문법은 # 기호로 시작하고 기계어로 번역되는 명령문이 아니어서 ;(세미콜론)을 사용하지 않음.

 

#include 전처리기

보통 헤더파일(*.h)을 참조할 때 씀. 미리 맨 위에 선언하면 컴파일할 때 라이브러리 안의 함수를 써도 오류가 안남.
파일 이름을 " " 안에 선언하면 소스파일과 같은 경로상에 있을 때 라이브러리를 찾을 수 있음.

#include "Mylib.h"

소스파일과 같은 경로에 없을 경우엔, 직접 경로를 써야 함.

#include "C:\download\Mylib.h"

 Visual Studio에서 프로그래머의 편의를 위해 제공하는 헤더 파일과 라이브러리 파일이 있음.
따라서 C언어는 이러한 헤더파일과, 라이브러리 파일의 위치를 알고 있음. 이러한 헤더파일과 라이브러리는
" " 대신에 < >를 사용함.

#include <stdio.h>

하지만 " "를 사용해도 괜찮긴 함. " "를 쓰고 소스파일 경로상에 없다고 판단이 되더라도, 비주얼 스튜디오가 설치한 헤더 파일 경로에서 파일을 찾기 때문임. 그래도 관습적으로 <>는 비주얼 스튜디오에서 제공하는 헤더파일.
" " 는 프로그래머가 정의해 사용하는 헤더파일을 쓸 때 사용함.

 

#define 전처리기

#define 전처리기는 상수나 명령문을 치환하는 문법임.

 

상수 치환

#define MAX_COUNT 3

이라고 선언하면 앞으로 MAX_COUNT를 쓸 때마다 컴파일러는 얘를 3으로 인식하고 번역함.
코드를 이해하는데도 도움이 되고, MAX_COUNT를 수정할 때 일일이 3을 수정하는 게 아니라 맨 위에 define문을 수정하면 되기 때문에 간편함.

 

명령 치환

#define POW_VALUE(a) (a*a)
int data = POW_VALUE(3); /*data 변수에 3*3을 실행한 9가 들어가게됨.*/

이렇게 명령된 함수를 매크로 함수라고 이야기함. 여기서 매크로란 '자주 사용하는 명령을 묶어서 하나의 명령으로 사용한다'는 뜻임.

 

표준 라이브러리의 필요성

운영체제별로 화면 출력을 위한 코드는 다를 수밖에 없음. 그리고 새로운 운영체제가 나올 때마다 그러한 코드를 다시 짜는 것도 일임. 표준 라이브러리에 존재한 '표준 출력 함수'로 출력 함수를 만들었다면 말이 달라짐. 그냥 다른 운영체제에서 컴파일만 다시 하면 그대로 사용할 수 있음. 표준 라이브러리는 이렇게 모든 운영체제에서 사용이 가능함.

 

표준 출력 함수

stdio.h(Standard Input Output Header) 파일에 정의되어 있음.

 

단일 문자 출력 함수 putchar, putc

putchar(65); /*아스키 값 65에 해당하는 문자 A가 출력됨*/
putchar('A'); /*문자 A가 출력됨*/

putchar 함수가 성공적으로 문자를 출력하면 출력된 문자의 아스키 값을 반환하고, 오류가 발생하면 EOF(End Of file,-1) 값을 반환함.
putchar 함수는 1바이트를 기준으로 출력하기 때문에 한글은 출력 못함.(한글은 한 글자에 2바이트임)

#define putchar(c) putc((c),stdout)

stdio.h 헤더파일에 이런 식으로 #define 처리기가 명령돼 있음.
매번 putc를 선언하기 힘들기 때문에 putchar라는 매크로 함수를 선언해놓은 거임.

putc('A',stdout);

stdout은 표준 출력을 의미함.

 

문자열 출력 함수 puts

string은 문자열을 의미함.

puts("Hi~"); /* "Hi~" 출력 후에 줄 바꿈이 일어남.*/

puts를 이용하면 캐럿(Caret)이 자동을 다음 줄로 이동함.(깜빡깜빡하는 글이 처지는 위치를 표시해주는거)( _ 이모양임)

 

문자열 출력 함수 printf

표준 출력 함수 중에 가장 많이 사용함. printf 함수는 줄 바꿈이 일어나지 않음.

 

printf 함수를 사용하는 방법

키워드 %d %f %c %s
출력 형식 정수(10진수) 실수 문자 문자열
int data = 5;
printf("%d",data); /*출력하려는 형식과 일치하는 키워드를 사용해야함*/
int data1 = 3;
int data2 = 5;
printf("%d%d",data1,data2);
/* 출력결과 : 35 이므로 떨어저 써야하면 %d를 한칸 띄어야함*/

 

%c는 변수가 가지고 있는 값을 아스키 표에 대응하는 문자로 출력함

#include <stdio.h>

void main()
{
printf("65의 ASCII 값은 %c 입니다.", 65); /* %c 자리에 'A'가 출력됨*/
}
#include <stdio.h>

void main()
{
char data =65;
/*첫 번째 data는 %c와 짝이 되고 두 번째 data는 %d와 짝을 이룸*/
printf("%c의 ASCII 값은 %d 입니다.",data,data);
}

 

실수와 정수는 숫자를 표현하는 방식이 다르다

include <stdio.h>

void main()
{
float value = 2.1f;
printf("%f",value);
}
/*결과값 : 2.100000 */

2.1f라고 사용하는 이유는 실수라는 상수를 쓰면 double로 처리하려고 함. float이라는 4바이트에 8 바이트 값을 집어넣으려 하니, 데이터가 손실될 수 있다고 경고가 발생함.
그래서 2.1을 float에 넣을 땐 뒤에 f를 넣어야 함.
float은 소수점 6자리까지 나와서 결과값에 2.100000이 나옴.
※실수를 %d,%c로 출력하거나 정수를 %f로 출력하면 정상적인 결과값을 못 얻음.

 

%u는 변수 값을 부호를 고려하지 않는 10진 정수 형태로 출력함

#include <stdio.h>

void main()
{
int data = -1;
unsigned int data2 = 4294967295;
printf("%d, %u, %d, %u",data1,data1,data2,data2);
}
/*출력화면 : -1, 4294967295, -1, 4294967295 */

 

%d와 %u는 변수 크기를 4바이트 값으로 변환해서 출력함

#include <stdio.h>

void main()
{
cahr data = -1;
printf("%d,%u", data, data);
/* 1바이트 크기의 -1값이 4바이트 크기의 -1로 변경되고 출력함 */
}
/* 출력값 : -1, 4294967295 */

 

%o는 8진수, %x는 16진수 정수를 출력한다

#include <stdio.h>

void main()
{
int data1 = 10; /*10진수로 10 */
int data2 = 010; /*10진수로 8 */
int data2 = 0x10; /* 10진수로 16*/

printf("%x, %d, %o", data1, data2, data3);
}
/* 출력값 : a, 8, 20 */

 

%e는 실수를 지수 형태로 출력

#include <stdio.h>

void main()
{
float data = 12.34f;
printf("%f, %e, %E, data, data, data);
}
/* 출력값 : 12.340000, 1.234000e+01, 1.234000E+01 */

 

출력 문자열 정렬

%출력 칸의수d

#include <stdio.h>

void main()
{
int data = 7;
printf("[%d] [%5d]", data, data);
}
/* 출력화면 : [7] [ 7] */

 

오른쪽 정렬, 왼쪽 정렬, 빈칸 0 채우기

%5d라고 적었을 때 %+5d의 +가 생략된 거임. 왼쪽으로 정렬시키려면 +자리에 -를 넣으면 됨.
빈칸에 0을 채우려면 %05d라고 하면 됨.

#include <stdio.h>

void main()
{
int data = 7;
printf("[%5d] [%05d] [%-5d]", data, data, data);
}
/* 출력화면 : [ 7] [00007] [7 ] */

 

실수의 소수점 자릿수 지정

%+전체 칸수+.+소수점 자릿수+f
출력할 때.(마침표)도 출력 칸수에 포함됨.

#include <stdio.h>

void main()
{
double data = 3.141592;
printf("[%f] [%.4f] [%8.4f] [%-8.4f]", data, data, data, data);
}
/* 출력화면 : [3.141592] [3.1416] [ 3.1416] [3.1516 ] */

※소수점 자릿수가 변경될 때, 반올림이 적용됨. %자체를 출력하고 싶으면 %%를 두 번 쓰면 됨.

pirntf("95%%");

 

제어코드

제어 코드는 모든 표준 출력 함수에서 사용 가능.

제어코드 기능
\n 캐럿을 다음 줄로 이동(Line Feed)
\r 캐럿을 해당 줄의 처음으로 이동(Carriage Return)
\t 캐럿을 한 탭만큼 이동
\b 캐럿을 바로 앞 칸으로 이동
\a 시스템 스피커로 경고음 발생
\" 큰따옴표 출력
\' 작은따옴표 출력

 

 

\r 제어코드 : 캐럿을 해당 줄의 처음으로 이동

\r 사용 후, 문자를 출력하면 해당 위치에 출력된 문자를 덮어쓰게 됨.

printf("Hello~ Tipssoft.com\rHi~~~~");
/* 출력화면 : Hi~~~~ Tipssoft.com */

 

\t 제어코드 : 캐럿을 한 탭만큼 이동

캐럿이 8칸씩 이동됨. 하지만 무조건 8칸 이동하는 건 아니고,
해당 줄에서 8의 배수에 해당하는 가장 가까운 위치로 이동함.

#include <stdio.h>

void main()
{
printf("12345678123456781234567812345678\n");
printf("a\tbc\tdef\tg");
}
/* 출력화면 : 12345678123456781234567812345678
              a       bc      def     g          /*

 

" " 도 출력하고 싶을 때

printf("\"Hello\""); /* \를 사용하면 단순 문자로 의미를 변경가능 */
/* \를 출력하고 싶을때도 \\를 사용하면됨. */

 

 

글을 마음대로 배포하셔도 되지만, 출처(링크)는 반드시 남겨주시기 바랍니다.

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

C언어 지역 변수/전역 변수  (0) 2021.03.12
C언어 반복문/시프트 연산자/비트 연산자  (0) 2021.03.11
C언어 연산자/조건문  (0) 2021.03.11
C언어 자료형/상수  (0) 2021.03.10
C언어와 프로그램  (0) 2021.03.10
댓글