본문 바로가기
카테고리 없음

임베디드 프로그래밍을 고려한 C강의 -3

by 팁텍북 2018. 7. 4.

임베디드 프로그래밍을 고려한 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; //포인터 변수



댓글