[C] C언어 스터디 3주차
Review
- printf, scanf
- 변수
- 연산자
- 조건문
- 반복문
함수
함수란?
- function : 기능 / 이공계쪽에서는 ‘함수’…
- 수학에서의 함수? f(x), g(x) … 다를 것 없음!
- x에 어떤 자료가 특정 자료형으로 들어갈 수도 안들어갈 수도 있으며, 특정한 기능을 수행하는 코드의 묶음!
- 사용자가 직접 정의해서 사용할 수도 있고, 라이브러리를 참조하여 이미 정의된 함수들을 가져다 쓸 수 있다.
- printf, scanf // stdio.h, rand() -> stdlib.h,
기본 정의
함수를 정의하는 형식
// c에서
반환타입 함수이름(매개변수) {
수행코드;
[return 반환값;]
}
int getNum() {
return 10;
}
// 파이썬에서
def 함수이름():
들여쓰기로 구분
반환타입 없음
[return 반환값]
반환 타입
// 함수를 호출한 곳에 값을 반환한다.
// 이 때 반환하는 값의 타입을 결정하는 것.
int sumOfOneAndTwo() {
//return 1+2; // 함수를 호출한 곳에다 반환해주는 것
return 1+2;
// 반환하는 값은, 코딩하는 사람이 결정하는것!
}
double averageOfScore() {
return (99+97)/2
/* or
double avg = (99+97)/2
return avg;
*/
}
char returnRandomAlpha(){
return rand()%26+65
}
// 반환 타입으로 모든 자료형이 될 수 있다. 구조체, 포인터도 마친가지..
int main() {
int sum;
if (sumOfOneAndTwo() == 1)
잘 수행되었음;
sum = sumOfOneAndTwo();
printf("%d", sum);
}
// 메인함수의 반환 타입
int main() {
...
return 0;
}
void main() {
...
}
// printf 함수의 반환 타입
int printf(const char* format, ...); // 출력된 전체 문자의 개수를 반환한다.
main() {
int num;
num = printf("");
}
// scanf ... 등등 만들어진 함수들 모두 '반환 타입'을 가지고 있다. 우리가 반환 값을 사용하지 않을 뿐.
- printf()의 반환값
- 함수 reference를 확인하는 습관
매개 변수(Parameter), 함수의 인자(Argument)
- 인자는 전달된 값 자체
- 매개 변수는 전달된 인자를 받는 변수
int main() {
int sum = addNumbers(10, 20); // 인자
printf("%d\n", sum); // 30
return 0;
}
int addNumbers(int num1, int num2) { // 임시변수, 매개변수 2개
return num1 + num2; // 전달받은 두 수를 더해서 반환
}
- 굳이 따지고 보면 함수가 호출될 때, 전달받은 값을 저장할 매개변수를 할당하여 저장하는 것!
- 메모리적인 관점에서 생각 필요… 지역 변수, 전역 변수 등 개념!!
함수의 선언부
‘함수 원형’ 이라고 불리는 함수의 선언을 왜 해줄까?
- 기본적으로 C는 ‘절차지향적인 언어’, 반드시 호출 전에 먼저 선언 되어있어야 함.
- 함수 선언을 해줌으로 컴파일러에게 알려주어 에러 검출에 도움!
- 함수 리턴 값 바르게 처리
- 함수 인자 개수 확인
- 전달 인자의 데이터 타입 확인
- 아래의 경우, 에러 발생!
#include <stdio.h>
int main() {
int sum = addNumbers(10, 20); // 인자
printf("%d\n", sum);
return 0;
}
int addNumbers(int num1, int num2) { // 매개변수
test(); // test() 가 정의되지 않았습니다.
return num1 + num2;
}
void test() {
printf("hello");
}
- ‘이런 함수가 정의 되어있어’ 하고 미리 알려주는 역할
#include <stdio.h>
int addNumbers(int, int); // 선언 형식, 매개변수 '이름'은 생략 가능하다.
void test(); // 함수 원형
int main() {
int sum = addNumbers(10, 20);
printf("%d\n", sum);
return 0;
}
int addNumbers(int num1, int num2) { // 함수 정의
test();
return num1 + num2;
}
void test() {
printf("hello");
}
- 또, 코드가 길어지면… 함수 찾기도 힘듦…
- 또, 함수의 정의를 먼저 하다보니 정작 메인인 main() 함수가 맨 아래로 가게 된다.
호출 과정
- 하나의 프로그램(프로세스)에는 하나의 main() 함수!!
- main() 이 실행되다가 함수를 호출하면 main() 의 일은 잠시 멈추고 호출 함수로 가서 수행한다.
- 수행을 마치고 다시 호출한 main() 으로 돌아가 일을 계속한다.
- 이후에 스택 개념..!!
#include <stdio.h>
int addNumbers(int, int); // 선언 형식, 매개변수 '이름'은 생략 가능하다.
void test(); // 함수 원형
int main() {
int sum = addNumbers(10, 20);
printf("%d\n", sum);
return 0;
}
int addNumbers(int num1, int num2) { // 함수 정의
test();
return num1 + num2;
}
void test() {
printf("answer : ");
}
answer : 30
메모리 할당 개념
- 지역변수, 전역변수, 정적변수 등 메모리적인 관점 필요!!
- 변수든 함수든 사용하기 위해서는 메모리가 할당 되어야
- 정적 변수 c 코딩 도장
- 개념 참고!!
지역변수
- { } 괄호(블록) 안에서만 쓸 수 있는게 지역변수
- main { } / function { } / for { } / while { }
- 블록을 벗어나면 메모리 할당 해제
- 컴퓨터 메모리 ‘어딘가에’ 알아서 할당해주는 것.
void func(){
int localValue = 10;
}
int main() {
int num = 10;
printf("%d", localValue); // 사용 불가!
}
전역변수
- 전 지역에서 쓸 수 있는 변수
- 기본적으로 하나의 프로그램에서는 어디서든 쓸 수 있다.
- 외부 파일의 전역 변수 등을 extern 키워드를 이용해 참조할 수 있다.
#include <stdio.h>
// 헤더파일, .c 파일 등 외부파일 만들어서 참조
extern 외부 라이브러리, API, 전역변수 등을 참조해 사용 가능
int global_value; // 전역변수. 다만, 스파게티 코드 라고 해서 전역변수를 많이 쓰면 안좋다.
// 프로그램 내에 어디서든 사용 가능
void show();
int main(){
global_value = 10; // 사용 가능
show();
}
void show() {
printf("%d\n", global_value); // 사용 가능
}
정적변수 static
- 지역변수로 선언했어도, 프로그램이 끝날 때까지 메모리를 계속 유지하는 변수
- 값을 처음에 한 번 초기화 하면, 다시 초기화 할 수 없다.
- 즉, 지역변수이면서 정적변수일 수 있다.
void plusNum() {
static int num = 0; // 함수가 처음 호출될 때 수행, 두 번째부터는 무시!
num++; // 4
}
stdio.h
static int printf
int main() {
plusNum()
plusNum()
plusNum()
plusNum()
}
- 전역변수이면서 정적변수일 수도 있는데, 이 경우에는 전역변수를 외부에서는 참조할 수 없다.
//****** file.c ******//
#include <stdio.h>
int num1 = 100; // file의 전역변수. 외부에서 extern 으로 참조 가능
//****** main.c ******//
#include <stdio.h>
extern int num1; // file.c의 전역변수 num1을 참조 (가능)
int main() {
printf("%d\n", num1);
return 0;
}
//****** file.c ******//
#include <stdio.h>
static int num1 = 100; // file의 정적 전역변수. file.c 안에서만 사용 가능
//****** main.c ******//
#include <stdio.h>
extern int num1; // file.c의 전역변수 num1을 참조 (불가능. 컴파일에러!!)
int main() {
printf("%d\n", num1);
return 0;
}
/////////////////////////
- 즉, 해당 프로그램(.c 파일) 안에서만 사용하도록 제한할 때 전역변수에 static을 붙인다.
- 다시 정리하면 정적 전역 변수는, 선언한 .c 파일 내에서 어디서든 사용할 수 있다.
메모리
(꼭 시간내서 읽어보는 것 추천)
code
- 실행할 프로그램의 코드가 들어가는 부분
- 작성한 소스 코드가 저장되는 영역이다.
data
- 프로그램이 시작과 동시에 할당 되고, 종료될 때 사라지는 영역
그렇기 때문에 한번 초기화 하면 다시 초기화 할 수 없다
- 정적변수(static), 전역변수
heap
- 프로그래머가 관리할 수 있는 유일한 영역
- 프로그래머에 의해 메모리를 할당 / 해제 할 수 있는 메모리 공간이다.
- 동적 메모리 할당 (Dynamic Memory Allocation)
- malloc(), realloc(), … free() 등…
stack
- 프로그램 수행 도중 호출될 때 할당 / 수행 끝나면 사라지는 영역
- 함수, 매개변수, 지역변수 등…
- Last In First Out 형태의 자료구조 의미도 가지고 있다.
함수 종료 조건
함수가 호출이 되고 종료하게 되는 조건은?
- 수행이 완료가 되면 자동으로 종료
- return
- void 일 때는 함수 내부 코드의 수행이 끝나면 자동 종료
- void 일 때도 return ; 하면 함수를 종료한다.
- 반환값이 있을경우도 return __; 해도 함수를 종료한다.
- Error 때문에 아예 프로그램이 종료되는 경우
- exit()
- main() 함수 자체를, 즉 프로그램 자체를 종료하는 함수
- while, for 조건문 등은 break;
재귀 호출?
- 함수 안에서 함수 자기 자신을 호출하는 것
- 팩토리얼 (!) 구현할 때 / 정렬 알고리즘 사용할 때 (Quick sort) 등의 예시
- 효율적인 경우에만 사용하는 것이 좋다.
// 1부터 입력한 숫자까지 모두 더하는 함수 (num + num-1 + ... 2+1) - 재귀함수
int sumOfoneToNum(int num) {
if(num > 1)
return num + sumOfoneToNum(num-1);
else
return 1;
}
명령행 인자
- 메인 함수에도 매개변수를 넣어서, 프로그램을 실행할 때 인자를 넣어주는 것
- int main(int argc, char *argv);
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("입력한 인자의 개수를 나타내는 argc값은 %d입니다.", argc);
for(int i=0; i<argc; i++)
printf("%s\n", argv[i]);
}
- 한번 찾아서 자율적으로 공부해보기. 처음엔 이해 안되고 좀 어려울 듯.
- 포인터, 배열부분 공부한 후 보면 그나마 이해 될 듯.
- 개발환경에서도 main()에 매개변수를 줄 수 있다!! 참고
함수를 공부할 때 생각하며 볼 부분
- 어떤 기능을 수행하나?
- 매개변수로 주는 인자가 무엇인가?
- 타입은 뭔지
- 개수는 몇개인지
- 반환값은 있는가?
- 타입은 뭔지
- 어떤 원리인가?
- 나중에 문자열 -> 정의된 함수들 많음. strlen(), strcpy(), strcat, …..
- 그 외에도 printf(), fprintf(), scanf(), fscanf(), . gets(), puts(), getch(), getcha(), getchar()… 무지하게 많음
과제1 (함수 이전)
반복문을 자유자재로 능숙하게 사용하기 위한 프로그래밍 연습을 하시오.
- 다음 출력 결과가 나오게 구현하시오.
- for문으로 구현하고 while 문으로도 구현해보시오.
// 반 다이아몬드
입력 : 3
*
**
***
**
*
입력 : 5
*
**
***
****
*****
****
***
**
*
// 우측 직각 삼각형
입력 : 3
*
**
***
입력 : 5
*
**
***
****
*****
// 우측 역 직각삼각형
입력 : 3
***
**
*
입력 : 5
*****
****
***
**
*
// 피라미드
입력 : 5
*
***
*****
*******
*********
// 역 피라미드
입력 : 5
*********
*******
*****
***
*
// 다이아몬드
입력 : 5
*
***
*****
*******
*********
*******
*****
***
*
// 반 모래시계
입력 : 5
*****
****
***
**
*
**
***
****
*****
// 모래시계
입력 : 5
*********
*******
*****
***
*
***
*****
*******
*********
// 알파벳 순차찍기
a
ab
abc
abcd
abcde
abcdef
// 역 알파벳 순차찍기
f
ef
def
cdef
bcdef
abcdef
과제2 (함수)
세 정수를 입력받아 가장 큰 수를 찾는 프로그램
- 정수를 입력받아 반환하는 inputNumber() 함수를 구현하시오.
- 정수 세 개를 인자로 넘겨 Max 값을 반환하는 findMax( ) 함수를 구현하시오.
- 함수 응용
두 정수 a, b를 입력 받아 a의 b제곱을 구하는 프로그램
- 정수를 입력받아 반환하는 inputNumber() 함수를 구현하시오.
- a, b 값을 인자로 넘겨 a^b를 계산해 반환하는 power( ) 함수를 구현하시오.
- 함수, 반복문 응용
정수를 입력 받아 해당 숫자까지의 덧셈 과정과 결과를 출력하는 프로그램
- 정수를 입력 받아, 과정을 출력하는 함수 addingProcess(__) 를 구현하시오.
- 함수, 반복문 응용
정수를 입력 받아 해당 숫자까지의 짝수, 홀수를 각각 더하는 프로그램
- 입력받은 숫자 이하의 모든 짝수를 더해 반환하는 sumOfEven(__)를 구현하시오.
- 입력받은 숫자 이하의 모든 홀수를 더해 반환하는 sumOfOdd(__)를 구현하시오.
- 결과는 main()에서 출력하시오.
- 함수, 반복문 응용
두 정수 a, b를 입력 받아 두 수 사이의 2, 7의 배수를 각각 출력 및 합 구하기
- 입력받은 두 정수 사이에 존재하는 모든 2의 배수와 7의 배수를 출력하고, 그 합을 출력하시오.
- 인자로 두 정수를 넘겨 각 숫자를 출력하고, 합을 반환하는 printBetweenNums(__, __) 를 구현하시오.
- 한 줄에 숫자는 4개씩 나오도록 출력하시오.
- 함수, 반복문 응용
- 한 줄에 숫자는 4개씩 나오도록 출력하시오.
계산기 프로그램
- 두 정수의 사칙연산을 수행하는 계산기 프로그램을 작성하시오.
- 덧셈, 뺄셈, 곱셈, 나눗셈을 수행해 반환하는 plus, minus, mult, division 함수를 각각 구현하시오.
- 반복문을 이용해 다음 기능들이 무한 반복 되도록 구현하시오. (ctrl + c 입력시 종료)
- [숫자 문자 숫자] 를 입력받아 정수와 연산자를 변수에 입력받으시오.
- 연산자의 종류에 따라 사칙연산 함수를 호출하여, 몇 번 호출 되었는지를 출력하시오.
- 연산의 결과를 출력하시오.
- 조건문(switch), 반복문, 함수 응용
ATM 프로그램
- 사용자가 메뉴를 선택해 저축과 인출을 할 수 있는 ATM 프로그램을 구현하시오.
- 잔액에 대한 변수는 전역 변수로 선언하시오.
- 저축을 수행하는 함수 save()와 인출을 수행할 함수 draw()를 구현하시오.
- 조건문, 반복문, 함수, 전역변수 응용
int main() {
...
--- 반복 ---
// if 1 선택시
저축할 금액 입력
save 함수 호출
// else if 2 선택시
인출할 금액 입력
draw 함수 호출
// 1, 2를 제외한 숫자 입력시
에러 메시지 출력
계속 하시겠습니까?
--- 반복 ---
}
입력한 숫자 팩토리얼의 값을 구하는 프로그램
- 정수 n을 입력 받아, n! 의 값을 구하는 아래 경우의 프로그램을 구현하시오.
- 반복문을 이용해 구현하는 경우
- 재귀함수를 이용해 구현하는 경우
- 5! = 5 x 4 x 3 x 2 x 1