임베디드 프로그래밍을 고려한 C강의 -3
ㅇ 다양한 연산자
- 비교(관계)연산자(>,<,>=,<=,==,!=) //참, 거짓 반환
- 비트 연산자(&|,^,<<,>>,~) //특정값 연산
- 논리연산자 (&&, ||, !) //참, 거짓 반환
- 사칙연산자(*, /, -, +, %-나머지)
원형 큐 설명(출처: 네이버 블로그)
https://m.blog.naver.com/PostView.nhn?blogId=soxoo&logNo=110122586459&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F
-기타대입연산(+= 등)
-sizeof(int) 메모리의 수를 반환한다.
-Cast연산, Casting, 변수 앞에
-괄호연산자-우선순위가 가장 높다.
-콤마연산자-제어문에서 조건식을 쓰는 괄호처럼, 세미콜론 사용할 수 없을 때 사용한다.
-삼항연산자-간단한 조건문을 쓸 때 사용한다. 구문이 길어지면 가독성이 떨어질 수 있다. 이때는 if~else문 등을 이용한다.
-조건문
ㅇ단순 if문
if(조건)
{
수행문1;
}
===================
ㅇif~else문
if(조건)
{
수행문1;
}
else
{
수행문2;
}
====================
ㅇif(조건)
{
}
elseif(조건)
{
}
Switch Case
기본형은 아래와 같다.
Switch Case(변수)
{
Case 0:
수행문1
Break; //switch-case구문을 탈출함.
Default://조건을 만족하지 않을 때 Default이하의 구문이 수행된다. If~else문에서 else의 역할을 함.
수행문2
break;
}
주의해야 할 것은 Case와 Default 뒤에는 :(콜론)을 넣어준다.
참고]
인터럽트 (출처:위키백과)
https://ko.wikipedia.org/wiki/%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8
폴링방법. 주기적으로 왕복하는 것.
인터럽트. 이벤트가 발생했을 때 어떻게 할 것인가. 처리하고 작업으로 돌아오는 것.
리셋방법. 이벤트가 발생했을 때 처음으로 돌아가서 시작함. 컴퓨터 리셋을 생각하면 된다.
Switch Case에서 범위지정의 예
(출처:http://gentooboy.tistory.com/142)
예제]
대소문자 관계없이 a에서 e까지 입력하면 반응하는 프로그램.
#include<stdio.h>
int main(void)
{
char ch;
printf("알파벳 a~e(대소문자구분없음) 중에 하나를 입력하세요.:\n");
while(1) //여러번 반복 수행을 위해 반복문을 사용하고, 빠져나오기 위해서는 Control+C키를 누르면 된다.
{
fflush(stdin); //scanf는 버퍼를 거침. Scanf를 반복하면 쓰레기값이 남음. 이것을 제거하는 것.
scanf("%c", &ch); //scanf함수를 이용하여 ch에 입력받은 값을 대입한다.
if(ch=='q') break; //while반복문을 탈출하는 break이다. 아래의 switch case문이 실행되지 않고 종료된다.
switch(ch)
{
case 'a':
case 'A':
printf("a(A)입력됨.\n");
break;
case 'b':
case 'B':
printf("b(B)입력됨.\n");
break;
case 'c':
case 'C':
printf("c(C)입력됨.\n");
break;
case 'd':
case 'D':
printf("d(D)입력됨.\n");
break;
case 'e':
case 'E':
printf("e(E)입력됨.\n");
break;
default:
printf("범위를 벗어난 값이 입력되었습니다.\n");
break;
}
}
return 0;
}
Break를 사용하지 않는 방법을 이용하여 해결하였다.
반복문
무한루프
while(조건)
{
}
조건에 1을 넣어보자.
while(1)
{
}
0이 아닌 정수가 조건에 들어가면 참이 되어 무한루프에 빠진다.
탈출조건을 넣어주는 것이 좋다.
OS가 없는 가전전자제품들의 경우에는 전원을 인가하는 동안에는 계속 가동되어야 한다.
기존 작성한 프로그램들 처럼, Return 0;을 만나서 프로그램이 종료되는 것이 아니라, Polling 방식, 즉 주기적으로 동작하는 프로그램의 형태로 구현해주어야 한다. 이를 Firm Ware프로그램이라고도 부른다.
While문에 탈출조건을 주자.
Break;문을 만나면 탈출할 수 있다. 원래 break는 감싸고 있는 가장 가까운 반복문을 탈출한다.
사용자가 원하지 않는 무한루프의 경우는 Bug이니 유의해야한다.
아래의 구문을 보자. Main문 내부의 변수선언과 while문이다.
Int temp=0;
while(temp<=5)
{
printf(“temp: %d”)
}
비교해서 5를 초과하면 종료되길 기대했는데 의도하지 않은 무한루프가 되었다. 이는 bug이다.
Bug를 수정해보자. 역시 Main문 내부의 변수선언과 while문이다.
Int temp=0;
while(temp<=5)
{
printf(“temp: %d\n”, temp);
temp++;
}
temp가 탈출역할을 해주어 6회 반복 후 while문을 탈출한다.
0,1,2,3,4,5 이렇게 temp가 변하는 동안 6회 반복이 된다.
While. ~동안이라는 뜻이 있다. 참일 동안 구문을 수행한다.
-for문
for(초기문;조건문;증감문)
{
}
초창기의 C, Ansi-C C89~90의 시기에서는 for문의 변수선언은 for문 내에서 할 수 없도록 하였는데, C99에서는 for문 내에서도 가능하도록 되었다.
For문의 무한루프 형태이다.
for(;;)
{
}
초기값도 없고, 탈출조건, 증감문도 없다.
Do~while문. While문에서 Do구문이 붙은 형태이다.
일단 구문을 한 번 실행한 뒤 반복하는 형태이다.
Do
{
}while(조건);
While뒤에 조건, 그리고 ;(세미콜론)이 붙는 것을 유의해야한다.
문제]
Printf문을 몇 번 수행할까?
1)
Int num = 0;
While (num<5);
{
printf(“Hello, world!\n”);
num++;
}
2)
for(num=0;num<5;num++);
{
printf(“Hello world\n”);
}
Sol]
1)0회, 무한루프에 걸림
While (num<5) 뒤에 의도하지 않은 세미콜론을 작성하여 생긴 문제이다.
위 문장 뒤에 ;(세미콜론) 앞 까지 반복한다.
그 틈에는 아무것도 없어서 non-operation, 수행문이 없다고 말한다.
하지만 그 틈을 num<5의 조건을 갖고 반복을 하게 되는데, 이는 무한히 반복하게 된다.
아래의
{
printf(“Hello world\n”);
}
문장에는 진입해보지 못하고 무한루프에 걸리기때문에 0회 출력된다.
2)1회
for(num=0;num<5;num++) 뒤에 의도하지 않은 세미콜론을 작성하여 생긴 문제이다.
위 문장 에서 ; 전까지를 0,1,2,3,4까지 5회 반복한뒤 아래의 구문을 1번 수행한다.
{
printf(“Hello world\n”);
}
#include<stdio.h>
int main(void)
{
int a = 1;
while(a<10)
{
a*=3; //a=a*3;
printf("a: %d\n",a); //변화값을 확인하기 위해서. 디버깅코드라고 한다.
}
printf("a :%d\n",a);
return 0;
}
같은 내용을 for문으로 바꾸어보자.
#include<stdio.h>
int main(void)
{
int a = 1;
for(a=1;a<10;a*=2)
{
printf("a: %d\n",a);
}
printf("a :%d\n",a);
return 0;
}
예제)
1~100까지 합을 구하는 코드
#include<stdio.h>
int main(void)
{
int i,sum=0;
for(i=1;i<=100;i++)
{
sum+=i;
}
printf("%d",sum);
return 0;
}
1. for문을 이용해 구구단을 계산하여 출력하세요.
예시)
printf("계산할 구구단의 단을 입력 : ");
scanf("%d", &num);
#include<stdio.h>
int main(void)
{
int inputNUM=0,iteration;
while(1){
printf("계산할 구구단의 단을 입력하세요=>(종료하려면 0)");
scanf("%d",&inputNUM);
if(inputNUM==0) break;
for(iteration=1;iteration<=9;iteration=iteration+1)
{
printf("%d X %d = %d\n",inputNUM,iteration,inputNUM*iteration);
}
}
return 0;
}
2. 두 정수를 입력받고 두 정수 사이의 모든 정수 데이터 합을 계산하세요.
예시)
#include<stdio.h>
int main(void)
{
int small_num, large_num, sum;
while(1){
sum=0;
printf("두 정수를 입력받고 두 정수 사이의 모든 정수 데이터 합을 계산(종료하려면 Control+C)\n");
printf("작은 수 와 큰 수를 차례대로 입력 : (작은 수입력/press spacebar/큰 수입력)=>\n");
scanf("%d %d", &small_num, &large_num);
while(small_num<=large_num)
{
sum+=small_num;
small_num++;
}
printf("결과는 다음과 같습니다.> %d\n",sum);
}
return 0;
}
3. 중첩 for문을 활용해 구구단 전체를 계산하여 출력하세요.
#include<stdio.h>
int main(void)
{
int MultipleLevel,iteration;
for(MultipleLevel=2;MultipleLevel<=9;MultipleLevel++)
{
for(iteration=1;iteration<=9;iteration=iteration+1)
{
printf("%dX%d=%d ",MultipleLevel,iteration,MultipleLevel*iteration);
}
printf("\n");
}
return 0;
}
-배열
배열을 사용하면 한 번에 많은 변수를 선언할 수 있다. 초기화는 중괄호를 사용하고 배열크기를 sizeof로 구할 수 있다.
Int val1;
Int val2;
Int val3;
Int val[3]; //배열은 이렇게 선언한다.
Int는 각 요소의 자료형, Arr은 배열명, [ ] 내의 값은 각 요소의 길이, 갯 수를 의미한다.
sizeof(ARR)
[배열의index] | [0] | [1] | [2] |
값 | 50 | 80 | 70 |
자료형 | int | int | int |
변수명 | ARR | ARR | ARR |
배열은 부족한 요소 값, 할당되지 않은 값은 0으로 자동으로 초기화시켜준다. 이 점이 일반 변수가 초기화하지 않으면 쓰레기값이 들어있는 것과 다르다.
Int Arr[ ]={1,2,3,4,5,6};
가능하다. 컴파일러가 초기화 값의 갯 수를 파악한다.
Int Arr[ ];
이것은 불가능하다. 길이를 알아야 메모리를 얼마나 할당해야할지 알 수 있기 때문에 오류가 난다.
for(index=0;index<3;index++)
scanf(“%d”, &Arr[index]);
아래는 Sizeof연산으로 자동으로 배열의 요소수를 구하여 처리하는 코드이다.
for(index=0;index<sizeof(arr)/sizeof(int);index++)
scanf(“%d”, &Arr[index]);
중요. 배열명은 배열의 시작주소이다.
Char Str[100] = {‘A’,’B’,’C’,’\0’};
printf(“Str:%s\n”,&Str[0]);
==>ABC가 출력된다.
Char Str[100] = “ABC”;
printf(“Str:%s\n”,Str);
==>위와 같은 결과를 출력한다.
배열의 초기화.
이것은 가능하나
Int arr[3] = {3,4,5};
이것은 불가능하다.
arr={3,4,5};
arr, 배열명은 배열의 시작주소이기 때문이다. 중요한 내용이니 꼭 기억하자.
배열의 주소는 바꿀 수 없다. 예를들어 arr의 시작주소가 0x2000일 때, 이것을 다른 값을 대입하여 바꿀 수 없다.
#include<stdio.h>
int main(void)
{
int score[5];
int i, tot=0;
double avg;
for(i=0;i<5;i++)
scanf("%d", &score[i]);
for(i=0;i<5;i++)
tot += score[i];
avg = tot/5.0;
for(i=0;i<5;i++)
printf("%5d",score[i]); /*콘솔창에 보기 좋게 출력하기 위해서 5칸을 차지하는 방식이다. %-5d도 있다. -가 붙으면 왼쪽정렬이다.*/
printf("\n");
printf("평균: %.11f\n",avg);
return 0;
}
출력결과는 다음과 같다.
널문자는 ‘\0’로 표현한다.
문자열은 배열에서 널문자까지를 출력한다.
#include<stdio.h>
int main(void)
{
char src[100]="Embedded"; // = {'E','m','b' ... }
char dest[100];
printf("src : %s \n", src);
printf("dest : %s \n", dest);
return 0;
}
아래 출력결과를 보면 dest에 쓰레기 값이 나타난다.
#include<stdio.h>
int main(void)
{
char src[100]="Embedded"; // = {'E','m','b' ... }
char dest[100];
int iteration;
printf("src : %s \n", src);
/*src배열의 내용을 dest배열로 복사*/
for(iteration=0;iteration<100;iteration++)
{
dest[iteration]=src[iteration];
}
printf("dest : %s \n", dest);
return 0;
}
출력결과
위의 코드는 100번을 반복하는데, 아래의 코드에서는 문자만큼만 반복하여 복사하는 보다 효율적인 코드이다.
#include<stdio.h>
int main(void)
{
char src[100]="Embedded"; // = {'E','m','b' ... }
char dest[100]={0};
int idx=0;
printf("src : %s \n", src);
/*src배열의 내용을 dest배열로 복사*/
while(src[idx]!='\0')
{
dest[idx] = src[idx];
idx++;
}
printf("dest : %s \n", dest);
return 0;
}
예제) 입력받은 문자열 중에 영문 알파벳 개수만 파악해서 출력
#include<stdio.h>
int main(void)
{
char src[100];
char temp;
int idx = 0, num=0;
printf("src 배열에 문자열을 입력: ");
//입력
scanf("%s",&src);
for(idx=0;src[idx];idx++)
{
temp=src[idx];
if((temp>='a'&&temp<='z')||(temp>='A'&&temp<='Z'))
{
num++;
}
}
printf("src : %s\n", src);
//입력받은 문자열 중에 영문 알파벳 개수만 파악해서 출력
printf("num : %d\n", num);
return 0;
}
예제) #3ef8cdA&r의 값을 담은 배열에서 영어 대소문자만 뽑아서 desc배열에 저장하기.
#include<stdio.h>
int main(void)
{
char src[100]="#3ef8cdA&r";
char dest[100]={0};
int iteration; //for문 내 반복을 하기 위해 사용하는 반복(iteration)변수
int count=0; //for문 내에서 desc의 배열값을 하나씩 할당하기 위해서,
//조건에 해당할 때마다 1씩 추가하여 배열공간을 지정하기 위한 변수
char temp; //수식이 길어지는 것을 막기위해 반복문 내에서 치환용으로 사용할 변수
//src배열의 내용을 검사해서 영문 알파벳에 해당한 문자만 dest배열에 저장
for(iteration=0;src[iteration]!='\0';iteration++)
{
temp=src[iteration];
if((temp>='a'&&temp<='z')||(temp>='A'&&temp<='Z')){
dest[count]=src[iteration];
count++;
}
}
printf("dest : %s\n", dest); //efcdAr처럼 영문 알파벳만 출력
return 0;
}
배열의 단점은 중간에 빠지는 경우가 생기면 일일이 다 당겨주어야한다.
이러한 단점을 보완하기 위해 linked list를 이용한다. 동적할당방법으로, 포인터로 특정 빠진 메모리 전과 후의 연결을 새롭게 해주는 방법을 한다.
#include<stdio.h>
int main(void)
{
int buff[5] = { 7, 2, 9, 3, 8 };
int idx = 0;
int cnt = 0;
int tmp = 0;
int len = 0;
len = sizeof(buff) / sizeof(int);
printf("----정렬 전 데이터 출력----\n");
for (idx = 0; idx < 5; idx++)
{
printf("%3d ", buff[idx]);
}
printf("\n\n");
//#1
for(idx=0;idx<len-1;idx++)
{
if(buff[idx]>buff[idx+1])
{
tmp=buff[idx];
buff[idx]=buff[idx+1];
buff[idx+1]=tmp;
}
}
for(idx=0;idx<len-1;idx++)
{
if(buff[idx]>buff[idx+1])
{
tmp=buff[idx];
buff[idx]=buff[idx+1];
buff[idx+1]=tmp;
}
}
printf("----오름차순으로 정렬 후 데이터 출력----\n");
for (idx = 0; idx < 5; idx++)
{
printf("%3d ", buff[idx]);
}
printf("\n");
return 0;
}
정적할당과 동적할당의 설명
char src[100]; //컴파일 타임 때 100byte확보. 정적할당이라고 함. 인덱스. 다량의 데이터를 사용할 때 접근속도가 빠르다.
//프로그램 실행 타임 때 메모리 확보. 동적할당이라고 함. 필요한 만큼만 쓸 수 있다. 코드의 유지보수가 용이하다.
//중간 삭제와 삽입이 편리함.
int idx = 0, num=0;
printf("src 배열에 문자열을 입력 : ");
//입력
scanf("%s",src);
//문자열 입력 받을 떄는 메모리 공간이 확보. 정적 할당, 동적 할당.
Srcpy로직
- 변수와 배열, 그리고 포인터변수의 형태
Char ch; //변수
Char buff[30]; //배열
Char *str; //포인터 변수
댓글