본문 바로가기
# Semiconductor/- Semicon Academy

[Harman 세미콘 아카데미] 13일차 - C언어 문법(조건문, 반복문, 함수)

by Graffitio 2023. 7. 5.
[Harman 세미콘 아카데미] 13일차 - C언어 문법(조건문, 반복문, 함수)
728x90
반응형
[조건문]

 

if / else

 

int main() 
{ 
	if (조건식1) 
	{ 
		// 조건식1의 결과가 참일 때 실행되는 명령문; 
	else if (조건식2) 
		// 조건식2의 결과가 참일 때 실행되는 명령문; 
	else  
		// 조건식1,2의 결과가 거짓일 때 실행되는 명령문; 
	} 
	return 0;
}

 

<예시>

 

int main()
{
    int num = 0;
	printf("숫자를 입력하세요.\n");
	scanf("%d", &num);

	if (num < 5)
	{
		printf("입력하신 숫자는 5보다 작습니다. \n");
	}
	else if (num == 5)
	{
		printf("입력하신 숫자는 5입니다.\n");
	}
	else
	{
		printf("입력하신 숫자는 5보다 큽니다\n");
	}
}

 

switch

 

// switch 문 //

int main()
{
	switch (정수식) // 값이 정수가 되어야 한다.
	{
	case 정수값1:  // 콜론
	     문장1;    // 실행될 문장
	     break;
	case 정수값2;  // 콜론
	     문장2;    // 실행될 문장
	     break;
	default: // default 생략 가능
	     break; // break를 만나면, switch문 전체를 빠져나간다.
	}
	return 0;
}

 

default는 생략 가능

단, case에서 확인하지 못한 결과 값이 들어오면

아무것도 발생하지 않기 때문에 적어 주는 것이 좋다.

 

<예시>

int main()
{
	int num; // 변수만 선언!, 현재 변수가 가지는 값은 쓰레기값

	printf("미세먼지 농도 선택 \n");
	printf("1 : 좋음\n");
	printf("2 : 보통\n");
	printf("3 : 나쁨\n");
	printf("4 : 매우 나쁨\n");
	scanf("%d", &num);
    
	// switch문 시작
	switch (num)
	{
	case 1:
		printf("미세먼지 좋음\n");
		break;
	case 2:
		printf("미세먼지 보통\n");
		break;
	case 3:
		printf("미세먼지 나쁨\n");
		break;
	case 4:
		printf("미세먼지 매우 나쁨\n");
		break;
	default: // 예외 처리
		printf("잘못 누르셨습니다. 다시 입력해주세요.");
		break; /// 지금은 예외처리 누르면, 프로그램이 종료되어 버린다. ---> 반복문 사용해보자.
	}
	return 0;
}

 

<switch문의 정수식에 문자 대입>

사칙연산자(+, -, *, /)도 문자로 취급됨.

int main() {

	int a, b;
	char c;
	int res = 0;

	printf("수식 입력 : \n");
	scanf("%d%c%d", &a, &c, &b);

	switch (c) {
		case '+':
			res = a + b;
			break;
		case '-':
			res = a - b;
			break;
		case '*':
			res = a * b;
			break;
		case '/':
			res = a / b;
			break;
	}
	
	printf("result : %d %c %d = %d", a, c, b, res);
	return 0;
}

 

[반복문]

 

while

 

// while 문 //

int main()
{
	while (조건식) // 조건식이 참이면, 무한 루프에 빠진다.
	{
		// 반복문
		// 변화식
	}
	return 0;
}

 

<예시>

int main()
{
	int weight = 80;
	int count = 0;

	while (weight > 50) // 무한 루프에 걸리면, 컴퓨터 꺼질 때까지 돈다. 잘 설계해라.
	{
		printf("매일 빡시게 운동해서 1kg을 뺀다. \n");
		weight--;
		count++;
	}

	printf("축하합니다, 운동 안하셔도 됩니다.\n");
	printf("%d 일 운동하셨습니다. \n", count);
	return 0;
}

 

<무한반복>

while(1){
	실행문
}

 

do-while 문

 

int main()
{
	int weight = 80;
	int count = 0;
	int select;

	do
	{
		printf("빡시게 운동해서 1kg 뺸다.\n"); // 반복코드
		weight--;
		count++; // 변화식

		printf("운동을 더 하시겠습니까? \n");
		printf("  1. yes\n");
		printf("  2. no\n");
		printf("  숫자를 입력하시오. \n");
		scanf("%d", &select);

		if (select == 2) break; // 여기까지는 일단 한 번 실행함.
		                        // 그 이후는 while 조건이 참이 될 때까지 무한반복
	} while (weight > 50);
	printf("축하합니다. 운동 종료 \n");
	printf("%d 일 운동하셨습니다.\n", count);
	return 0;
}

 

do-while문

    : 일단 무조건 반복문과 변화식1회 실행한다.

 

while문

    : 조건식부터 검사하고 실행한다.

 

for 문

 

int main()
{
	for ( 초기식 ; 조건문 ; 할당문)
	{
	    // 반복문 실행(위 조건문 참일 때,)
	}   // 반복문 먼저 실행하고, 할당문 실행(순서 잘 봐라)
	return 0;
}

 

<for문 sequence>

   i) 초기식 실행

   ii) 조건문이 참이면, 반복문 실행

   iii) 할당문 실행

   iv) 조건문 확인

   v) ii~iv 반복

 

int main()
{
	int weight = 80;
	int count = 0;
    
	for (weight = 80; weight > 50; weight--)
	{
		printf("  빡시게 운동해서 1kg 뺀다. \n");
		count++;
	}
	printf("  축하합니다. 운동 종료! \n");
	printf("  %d 일 운동하셨습니다. \n", count);
    
	return 0;
}

 

<조건식 변형>

int main()
{
	int sum;
	for ( unsigned i = 0; i < 100 && sum < 2000 ; i++ )
        // 조건식이 참인지 거짓인지 판별만 가능하다면, 어떤 조건식이든지 사용 가능 
	{
		sum += i;
	}
	return 0;
}

 

<무한 루프>

int main()
{
	for ( ; ; )
	{
		// 반복문
	}
	return 0;
}

 

<Break>

break는 자신이 속한 반복문 하나만 빠져나올 수 있다.

int main(){
	
    for(int i=0 ; i<50 ; i++) {
    	sum += i;
        if(sum>40) break;
    }
	return 0;
}

 

<Continue>

continue는 반복문의 일부를 건너 뛴다.

건너뛴 후에는 블록의 처음부터 다시 반복됨.(즉, 블록의 끝으로 건너 뜀)

int main() {

	int sum;
	
    for( int i = 0 ; i < 100 ; i++) {
    	if((i%3)==0) {
        continue;
        }
        sum += i;
    }
	return 0;
}

 

<반복문의 중첩>

// 반복문의 중첩 //
int main()
{
	int i = 0;
	int j = 0;

	for  (i = 0 ; i < 5 ; i++)
	{
		printf("  외부시작 %d \n", i);
		for (j = 0; j < 3 ; j++)
		{
			printf("  내부 수행 %d \n", j);
            // 지역변수(j)들은 자신이 속한 함수블럭을 벗어나면, 메모리를 반환하고 초기화된다.
		}
		printf("  외부 끝 %d \n\n", i);
	}
	return 0;
}

int main()
{
	int i, j;
	for ( i = 0; i < 5; i++)
	{
		for ( j = 0; j <= i ; j++)
		{
			printf("  *");
		}
		printf("\n");
	}
	for (i = 4; i > 0; i--)
	{
		for (j = 0; j < i; j++)
		{
			printf("  *");
		}
		printf("\n");
	}
	return 0;
}      // AVR 사용 시, LED 왔다갔다하는 구문 만들 때 활용할 예정

 

<할당문 변형>

int main()
{
	int i, j;
	for (i = 0; i < 5; printf("%d",i++)){}
	return 0;
}

 

<팩토리얼 함수>

// 팩토리얼 함수 //
int main()
{
	long fac = 1;
	int i, n;
	printf("정수를 입력하세요. : ");
	scanf("%d", &n);

	for (i = 1 ; i <= n ; i++)
	{
		fac = fac * i;
	}
	printf("%d ! 는 %d 입니다.\n", n, fac);
	return 0;
}

[함수]
함수의 형태

 

 

함수를 정의하는 이유

   - 모듈화에 의한 프로그램의 질 향상이 가능 

   - 유지 보수 및 확장의 용이성

   - 문제 해결의 용이성 : "Divide and Conquer"

 

함수의 매개변수

매개 변수(parameter)

 ▶ 함수를 호출한 곳에서 함수 안으로 전달되는 값을 보관하기 위한 변수

 

인자, 인수(argument)

 ▶ 함수를 호출할 때, 실제로 전달되는 값

 

사용자 정의 함수

 

// 사용자 정의 함수 //

int sum(x, y) // 매개변수 : x, y(매개변수 없이도 가능)
{
	// 함수 몸체
	return 0;
}

 

① void sum() : 반환할 게 없음
      int sum() : 반환할 값의 자료형이 int

 

② 반드시 main함수보다 위에 있어야 한다.
      visual studio는 아래 있어도 가능한데, atmege studio 등 다른 곳에서는 안 됨.
      근데, 그렇게 하면 main함수가 맨 아래로 가므로 함수의 원형만 윗쪽에 선언해준다.

print_hello(); // 함수 원형 선언

int main()
{
	printf("함수를 호출합니다.\n : ");
	print_hello();

	printf("함수를 또 호출합니다.\n : ");
	print_hello();

	return 0;
}

int print_hello()
{
	printf("Hello world. \n");
	return 0;
}

int add();

int main()
{
	int a, b, sum;
	a = 3;
	b = 5;
	sum = add(a, b);
	printf("  a와 b의 합은 : %d \n", sum);
	printf("  a와 10의 합은 : %d \n", add(a, 10)); // printf문 내에서도 사용 가능
	return 0;
}

int add(int x, int y)
{
	//int ret;
	//ret = x + y;
	//return ret; // 식을 간소화하면, 아래와 같다.

	return x+y; 
}

 

<함수 사용 시, 주의사항>

    - 함수의 작성은 함수의 리턴값, 함수의 인자, 내용이 필요!!
    - 함수의 인자는 반드시 갯수와 자료형에 맞게 넣어서 호출!!
    - 함수의 이름은 중복되면 골치 아파진다.(중복 금지!)
    - 함수명은 변수의 이름 생성 규칙과 동일

 

 

변수의 유효 범위

 

지역 변수(local variable)

의미

: 블록{} 내에서 선언된 변수


특징

① 블록 내에서만 유효하며, 블록이 종료되면 메모리를 반환하고 초기화됨.
② 지역 변수는 stack 영역에 저장됨
③ 초기화하지 않으면, 쓰레기 값으로 초기화된다.
함수의 매개변수지역 변수로 취급됨

 

void local(void); // 함수 원형 선언

int main()
{
	int i = 5;
	int var = 10;
	
	printf(" main()함수 내의 지역 변수 var의 값은 : %d \n", var);
	if (i < 10)
	{
		local();
		int var = 30;
		printf(" if문 내의 지역변수 var의 값은 : %d\n", var);
	}
	printf(" 현재 지역변수 var의 값은 : %d\n", var);
                  /// local()의 지역변수는 초기화되었으므로 var = 10이 출력
	return 0;
}

void local()
{
	int var = 20;
	printf(" local()함수 내의 지역변수 var의 값 : %d\n", var);
	return 0;
}

 

전역변수(global variable)

의미

: 함수 외부에서 선언된 변수

 

특징

① 전역변수는 프로그램의 어디서나 접근이 가능
프로그램이 종료되어야 메모리에서 삭제
③ 전역변수는 data 영역에 저장됨
④ 직접 초기화하지 않아도 0으로 초기화됨!!!

⑤ 지역변수로 같은 변수를 선언하면, 더이상 전역변수에 접근 불가

    같은 이름의 지역 변수에 가려진다는 의미 → 굳이 같은 문자 쓰지 마라, 중복 금지!

    tip) 전역 변수명을 길고 확실한 이름으로 쓰면 됨.

 

void local(void); // 함수 원형 선언

int var; // 전역 변수 선언

int main()
{
	printf(" 전역변수 var의 초기값 %d\n", var); // 자동으로 0으로 초기화됨

	int i = 5;
	int var = 10; // 지역변수 var

	printf(" main()함수내의 지역변수 var의 값은 : %d\n", var);
	if (i < 10)
	{
		local();
		printf(" if문 내의 지역변수 var의 값은 : %d\n", var);
	}
	printf(" 더 이상 main()함수에서는 전역변수 var에 접근 불가 : %d\n", var);
	return 0;
}

void local()
{
	int var = 20;
	printf(" local()함수 내의 지역변수 var의 값 : %d\n", var);
	return 0;
}

전역변수로 선언했지만, 지역변수 선언 후 전역변수에 접근 불가

 

정적변수(static varible)

의미

: C언어에서 정적변수란, static으로 선언된 변수


특징

① 지역변수와 전역변수의 특징을 모두 가진다
② 함수 내에서 선언된 정적 변수는 전역변수처럼 단 한 번만 초기화되며
③ 프로그램 종료 시, 메모리에서 삭제
④ 정적변수는 지역변수처럼 해당 함수 내에서만 접근 가능

⑤ 함수 내부에서 선언하는 정적변수는 결국 프로그램을 헷갈리게 만든다.

     → 전역 변수로 선언하는 것을 권고함.

 

void local(void);
void staticVar();

int main()
{
	int i;
	for ( i = 0; i < 3; i++)
	{
		local();
		staticVar();
	}
	return 0;
}

void local(void)
{
	int count = 1;
	printf("local()함수가 %d번째 호출됨\n", count); // 블록 탈출 후, 메모리 반환
	count++;
}

void staticVar()
{
	static int static_count = 1;
	printf("staticVar()함수가 %d번째 호출됨\n\n", static_count); // 블록 탈출해도 계속 결과가 누적
	static_count++;
}

stack 영역의 지역변수는 휘발성
heap - stack은 free store를 각각의 크기에 따라 점유하면서 범위를 조절한다.

변수 종류 키워드 선언 위치 유효 범위 메모리
소멸 시기
초기값 저장 장소
지역 변수 auto 함수/블록의
내부
함수/블록의
내부
함수 종료 시 초기화 안 됨 stack 영역
전역 변수 extern 함수의 외부 프로그램 전체 프로그램
종료 시
0으로 초기화 data 영역
정적 변수 static 함수/블록의
내부
함수/블록의
내부
프로그램
종료 시
0으로 초기화 data 영역
레지스터 변수 register 함수/블록의
내부
함수/블록의
내부
함수 종료 시 초기화 안 됨 CPU의
레지스터
(register)

포인터의 주소값을 레지스터 변수에 저장함

 

 

재귀함수

 

재귀 함수의 기본적 이해

: 자기 자신을 다시 호출하는 형태의 함수

 

탈출 조건의 필요성

재귀호출 잘못 하면,

무한 재귀 호출 되므로 자원을 상당히 낭비할 수 있다

stack overflow를 야기할 수 있다는 의미.

가급적 쓰지 않는 것이 좋다.

 

void Recursive()

{
    printf("recursive call!\n" )
    Recursive();
}

int main()
{
    Recursive();
    return 0;
} // 무한 재귀 호출의 굴레에 빠진다.

 

728x90
반응형