#함수와 변수 마무리 및 배열
함수와 변수
0.전역변수와 지역변수를 불가피하게 동일명으로 써야할 때, 전역변수는 대문자로하고 지역변수는 소문자로 쓰자.
1.저장 유형 지정자 static
static = 전역 변수로 이 코드를 변수 선언문 앞에 붙혀주면 중괄호 안 지역변수일지라도 전역 변수로 고정되어 활용할 수 있다.이걸 정적지역 변수라고도 한다.
(지역변수 = 로컬변수)
2.저장 유형 지정자 extern
변수 중에 다른 파일에서 가져온 것들을 구분할 때(실제로 한 프로젝트 내에선 여러파일을 쓴다.) 쓰는 지정자로서 앞에 변수 선언문 앞에 'extern'을 붙힌다.
= 컴파일러한테 이 변수는 외부에서 온 변수임을 알려주는 것
3.순환/재귀(recursion)이란?
순환호출 혹은 재귀호출로 부르며(순환은 빙글빙글 도는 것 그리고 재귀는 자기자신을 불러오는 것), 계속 나 자신을 불러오는 형태를 뜻한다.
예시로 펙토리얼 프로그램 코드를 보면 순환/재귀 호출의 구조로 되어있는데(코드 안에 있는 함수이름이 동일명일수도 유사명일수도 있음 그러나 기능은 비슷함) 여기에 메인함수에서 매게변수 인수로 3을 넣어 호출한다고 가정하면 아래와 같아진다.
int factorial(int n)
{
if( n==1 ) return 1;
else return(n * factorial(n-1));
}
// 3 factorial(2)
// 3 2 factorial(1)
// 3 2 * 1
int main()
{
factorial(3)
}
3이 들어가서 else에서 리턴하기 전에 또 다른 함수를 호출함(다른 함수호출이 있으면 메인함수 호출은 끝나지않는다.동일명이여도 호출되는 시점이 다르면 다른 함수다.factorial(2)와 factorial(1)은 다른 함수란 소리임) 순환을 멈추는 부분의 조건까지 계속 호출하고 종료가 됨.
순환/재귀 함수에는 무조건 순환을 멈추는 부분이 먼저 들어가고 순환호출을 하는 부분이 들어간다.이때 중요한 주의사항이 있는데 순환을 멈추는 부분이 없으면 시스템 오류가 발생할 때까지 무한정 호출하게 된다.
if( n==1 ) return 1;
얘가 리턴해야
else return(n * factorial(n-1));
그제서야 얘가 가지고있던 값들이 한번에 리턴되는것
함수는 붕어빵틀이라고 생각하면된다.모양은 같지만 팥이나 슈크림 등 매게변수가 여러가지 들어가고 같은 매게변수라할지라도 팥 붕어빵을 2개 만들었을때 엄연히 다른 붕어빵의 존재처럼 함수는 호출될때마다 다른 함수다.새 함수로 생각해야된다.재귀 함수도 나 자신을 다시 호출한다지만 동일 붕어빵틀을 쓰는것뿐 다른 존재다.
그럼 순환/재귀함수는 왜 쓰냐?
순환(recursion)은 순환 호출을 이용하는 것
반복(iteration)은 for나 while을 이용한 반복하는 것인데
반복문은 코드의 비효율성이 있다.실무에서 보는 반복문은 많은 줄의 코드가 있기때문이다.근데 재귀 호출은 비교적 간단해지기에 쓰는 것이다.이 용도와 취지가 익숙하진않지만 알고리즘(로직을 어떻게 효율적으로 짜야되는지) 예제들을 짜면서 익숙해져야된다.
4.거듭제곱 구하기의 반복문과 순환호출문 비교
//반복문 ver.
double slow_power(double x, int n)
{
int i;
double r = 1.0;
for (i = 0; i < n; i++)
r = r * x;
return(r);
}
//순환호출문 ver.
double power(double x, int n)
{
if (n == 0)return 1;
else if ((n % 2) == 0)
return power(x x, n / 2);
else return x power(x * x, (n - 1) / 2);
}
0승일때 1이 되는 수식을 이용하여 순환 호출 정지문으로 이용하고 2를 나눴을때 나머지가 0인 걸 이용해 n이 짝수일때 거듭제곱 결과값을 반출하는 로직으로 작성하였는데
x x, n / 2 인 이유는 예시로 들어 이해해야한다.x x를 2 * 2로 생각해야지 그나마 이해됨
n이 4라면
2 2, 4/2(=2) 이건 곧 (2 2)^2하란 소리다.이건 사실 2^4과 같은 값이다.근데 2가 아닌 x * x를 기준으로 생각하니 n에서 2로 나눈것
n이 6이라면
2가 6번 거듭제곱하는거니깐 2 * 2가 3번 거듭제곱되는 것 과 같다 그래서 6에서 2를 나누면 3이됨
즉 n/2가 뜻하는건 x * x에 n/2만큼 밑수를 거듭제곱하란 뜻임
그렇다면 n이 짝수가 아닌 홀수일때는?
else return x power(x x, (n - 1) / 2);를 타는데 3을 넣는다하면 (n - 1) / 2에서 1이니깐 x x 에 3일땐 1을 곱하는데(5일땐 2를 곱하고 7일땐 3을 곱하고인데) 그럼 2 두번밖에 안되나싶지만 코드 앞에 x를 한번 더 곱해준다.결국은 x x에 거듭제곱을 하고 부족한 x 하나를 앞에서 곱해줌으로써 x^n과 (x x)^n x 가 같게되는것임
재귀함수 자체가 너무 어려운거여서 이해하는데 어렵긴하다.그래서 일상코드에서 쓰긴 애매하다.남들도 코드를 보고 해석해야되기때문
배열
1.배열
= 동일한 타입(자료형)의 데이터가 여러 개 저장되어 있는 데이터 저장 장소
(자료형 타입이 같아야한다.)
= 변수를 일렬로 도열해놓은 것
배열을 왜 쓰는가? 우리가 뭔가를 관리할 때 관리할 대상이 많아질 때가 있는데,보통은 변수를 개별로 선언할 때가 있지만 간단한 코드에서는 변수를 일일히 선언하고 그 중 빠진 변수도 찾아서 다시 선언을 해주면되지만, 변수가 몇백개일때는 일일히 선언하기엔 너무 노가다고, 하나 빠트리거나 일부 몇개가 사라지면 찾기도힘듬.
그래서 많은 변수를 통째로 관리하기위해 배열이란걸 만들어낸 것이다.동일 기능 목적의 변수들을 묶어서 번호를 부여해서 한번에 관리하는 방식(학생들의 정보를 학생증 몇백개로 관리할바에 종이한장에 학번 적어서 관리하는게 당연히 더 효율적)
세상이 발전하면서 프로그램에 여러가지 기능들이 추가되면서 관리해야될 데이터의 양도 기하급수적으로 많아짐 그래서 이걸 배열을 통해 관리를 한다.
배열의구조
자료형 + 배열 이름(=배열을 사용할 때 사용하는 이름=변수명,변수명은 동일해야됨) + 대괄호([ ]) + ;
예) int speed[10];
"10개의 int로 관리를 하겠다"
"int 10개로 묶어서 컨트롤하겠다"
대괄호 안 숫자의의미? ------- '배열 크기'라고 한다.
관리할 변수의 갯수 = 배열의 원소의 갯수
데이터가 변경된 만큼만 증감해서 적어주면됨.
2.인덱스(index) (원소와 인덱스는 다르다!!!!!!!!!!)
= 배열 원소의 번호
-> 대량의 데이터를 한번에 처리할 수 있는 이유
여태까지는 선언한 변수의 이름을 가지고 사용해서 컨트롤했다.근데 지금은 하나의 변수명밖에 없는데 어떻게 관리할거냐? (데이터 중 일부 몇 개를 고르고싶을때)
배열의 원소가 각각 인덱스를 가지고있다.즉,얘가 몇 번째 순서인가를 표시해주는데
배열은 이 인덱스를 가지고 컨트롤하는 것이다.(이때 순서대로 숫자를 부여하며, 무조건 인덱스는 0부터 시작한다.)
Q.배열의 첫번째 원소가 뭡니까?
A.0번째 인덱스가 해당 하는곳의 원소
Q.0번째 원소의 이름은 뭡니까?
A.변수[0]
실무에선 사람이다보니 인덱스 0번이라고 말안하고 배열의 0번째 원소 혹은 배열의 첫번째 원소라고 많이들함 -> 배열의 첫번째 원소라고 하면 인덱스 0번으로 알아듣자 아니면 되묻자 인덱스의 0번인지 1번인지
3.배열 원소 접근
변수에 접근한다 = 변수의 값을 대입한다
우리가 변수를 쓸 때 값을 대입하는 식으로 쓰는 것처럼 배열에서 인덱스에 원하는 원소(값)을 넣고싶을때는 아래와 같이 표현한다.
ex) 5번째 인덱스의 원소에 80이란 데이터값을 넣고싶을때
grade[5] = 80; 이런식으로 쓰면된다.
4.배열에서 변수들을 초기화 하는 방법
배열도 선언하면서 초기화할 수 있다.다만 변수와는 다르게 묶어줄애가 필요해서 중괄호를 같이 써준다.
ex)
int grade[5] = {10,20,30,40,50};
인덱스 수 만큼 차례대로 초기화가 된다.
int grade[5] = {10,20,30};
인덱스는 5개인데 초기화를 일부만 한다면 나머지는 자동으로 0으로 초기화가 된다.
=배열의길이만큼 초기화하지않으면 나머지는 다 0으로 초기화된다.
-단 한개라도 초기화 해줘야 0으로 적용되는것임
배열도 초기화안하면 각각에 다 쓰레기값 들어있음 그래서 보통 배열 = {0};하면
컴파일러가 알아서 자동으로 초기화 시켜줌
5.배열의 크기(대괄호 안에 있는 숫자)가 공란인 경우
대괄호 안을 공란으로 할 수 있는 가능한 경우는 초기화를 동시에 해줄때이다.
int grade[ ] = {10,20,30,40,50,60};
배열의 크기가 주어지지 않으면 자동적으로 컴파일러가 초기값의 개수만큼이 배열의 크기로 잡아준다.
초기화 갯수가 8인데 인덱스를 10이라고 잘못쓰면 크러시가 일어난다.변수 선언시 운영체제로부터 메모리를 빌려오는데 내가 빌려온 메모리가 아닌 오버된 메모리에 접근할려고하는건(예로 들어 [10]인데 초기화할때 [13]을 입력하는 상황) 컴퓨터 입장에서 빌려준적도 없기에 막아야되는 입장이여서 중지시키는 것이다.
그런고로 인덱스를 넘어가지않도록 하는 것이 중요하다.
그리고 굳이 이렇게 쓰는 이유는?
문자열 쓸 때 이렇게 쓰곤하는데, 채팅같이 문자열을 쓰는것은 사용자 입장에서 얼마나 입력할지 모르기때문에, 이런 크기를 정해놓기 애매한 경우에 이런 배열 구조를 쓰곤한다.