처음 시작하는 C언어 02

yeonk·2021년 8월 24일
0

C

목록 보기
2/4
post-thumbnail

기초 문법

C언어의 토큰

  • 토큰: 문법적으로 더 이상 나눌 수 없는 기본적인 언어 요소
  • C언어는 다양한 토큰으로 구성 (키워드, 식별자, 상수, 문자열 리터럴, 기호)
  • 키워드, 식별자, 상수, 문자열 리터럴, 기호



세미콜론

  • C언어에서 모든 문장의 끝은 세미콜론(;)으로 끝나야 함.
  • 라인 구분



주석

작성된 코드 중에 컴파일러에 의해 무시되는 부분.
필요한 설명이나 메모를 작성하거나 실행되면 안되는 코드를 주석으로 설정.

  • 실행파일 코드에 불포함
  • //: 한 줄 주석
  • /**/ : 여러줄 주석



식별자

개발자가 만들어주는 이름으로 변수, 함수 등을 구분하기 위해 사용

  • 알파벳 A~Z, a~z, 숫자, _ 을 사용할 수 있음
  • 첫 글자는 숫자로 시작할 수 없음
  • _외 특수문자 사용 불가
  • 대소문자 구분
  • 키워드 사용 불가



키워드

c언어 자체에서 미리 사용하기위해 정해놓은 단어들 (용도가 고정)

  • C언어에서 사용하고 있는 미리 정의한 단어
  • 식별자로 사용할 수 없음





자료형

  • C 언어에서 사용할 수 있는 데이터 타입
  • 개발자가 OS에게 사용할 값의 타입을 전달하는 목적
  • 기본자료형: 정수, 실수
  • 열거형: 연속적으로 나열된 값을 단어로 정의하여 사용
  • Void: 아무 의미가 없는 값
  • 참조형: 기본 자료형은 값을 의미하지만 참조형은 메모리의 주소값을 의미



기억공간

  • 컴퓨터에 설치되어 있는 메모리는 OS에 의해 byte 라는 단위로 구분
    (bit 는 0이나 1을 기억할 수 있는 기억공간. 8bit = 1byte)
  • 이렇게 구분되는 공간을 기억장소로 부르며 기억장소는 0부터 시작하는 인덱스 번호를 가짐
  • OS에 의해 구분되어 있는 byte 단위의 기억공간은 C언어에 의해 여러 공간을 하나로 묶어 사용하기도 함

  • Byte 단위의 기억공간 하나는 숫자를 총 256개를 관리 가능

  • 2개의 공간을 묶어 하나라로 사용하면 총 65536개를 관리할 수 있음

  • 1~4개의 기억공간을 하나로 묶어서 사용



기본자료형

정수 자료형

정수 값을 표현하기 위한 자료형

  • Char(1byte): 문자 1개를 위한 값. 컴퓨터는 모든 글자를 숫자로 기억 / 문자 코드 값을 관리

  • Unsigned char(1byte): 부호가 없는 char

    • Signed char (1byte): 부호가 있는 char

    • Int (2 or 4 byte): 정수. -32768~32767 or -2147483648~214748364
      cf. 보통 개발할 때 int(인티저)를 가장 많이 사용

    • Unsighned int: 부호가 없는 정수 0~65535, 0~4294967295

    • Short(2byte)

    • Unsigned short(2byte)

    • Logn(4byte)

    • Unsigned long(4byte)

  printf("char : %d \n", sizeof(char));
  printf("unsigned char : %d \n", sizeof(unsigned char));
  printf("signed char : %d \n", sizeof(signed char));
  printf("int:%d\n", sizeof(int));
  printf("unsigned int:%d\n", sizeof(unsigned int));
  printf("short:%d\n", sizeof(short));
  printf("unsigned short:%d\n", sizeof(unsigned short));
  printf("long:%d\n", sizeof(long));
  printf("unsigned long:%d\n", sizeof(unsigned long));

실수 자료형

실수 값을 표현하기위한 자료형

  • Float (4byte)
  • Double (8byte)
  • Long double (16 byte)
    printf("float:%d\n", sizeof(float));
    printf("double:%d\n", sizeof(double));
    printf("long double:%d\n", sizeof(long double));

열거형

  • 연속된 값을 의미하는 단어
  • Ex. 요일의 경우 첫 번째 요일은 일요일, 두 번째는 월요일, 세 번째는 화요일 등의 문자열로 표현
  • 이렇게 순서를 가지고 있는 단어를 만들어 사용하는 것이 열거형



참조 자료형

  • 기본 자료형은 정수, 실수를 의미하지만 참조 자료형은 메모리의 주소 값을 의미

  • 메모리의 주소 값은 기억장소의 위치를 의미. c 언어는 기억장소의 위치를 기억했다가 필요할 때 접근하여 원하는 작업 가능





리터럴 & 변수

리터럴

  • 개발자가 코드에 직접 작성하는 값.

  • 종류: 정수 리터럴, 실수 리터럴, 문자열 리터럴, 문자 리터럴

printf("정수 리터럴 : %d\n ", 100);
printf("실수 리터럴 : %f\n ", 11.11);
printf("문자 리터럴 : %c\n ", 'c');
printf("문자열 리터럴 : %s\n ", "안녕하세요");



변수

  • 어떠한 값을 저장 및 사용하기 위해서는 변수를 사용해야 함

  • 메모리에 기억공간을 마련하면 값을 저장하고 불러오는 것이 가능

  • 변수: 개발자가 자유롭게 사용할 수 있는 기억 공간. 개발자가 이름 부여

  • 변수를 사용하기 위해서는 변수를 먼저 선언해야함
    (변수는 선언과 동시에 생성)

  • 자료형 변수명;

  • 자료형 변수명 = 값; (초기화)

  • 자료형 변수명, 변수명, 변수명; (같은 타입의 변수 여러 개 선언)





상수

프로그램 실행 중에 변하지 않음.

  • Const 키워드를 사용하면 상수를 정의 가능
    (const를 사용하면 변수 값 변경 불가)
  • 변수의 값을 변경하지 못하므로 변수 선언 시 값을 초기화 해야 함
const int a1 = 1000;
printf("a1 : %d\n", a1);



#define

  • 전처리 명령어 #define을 사용하면 상수를 정의 가능

  • 코드 상단 부분에 #define 으로 상수를 정의

  • 전처리 명령어 #define 으로 정의된 상수를 사용하게 되면 컴파일 전에 전처리기에 의해 정의된 값으로 코드가 변경됨

  • 컴파일 시에는 변경된 값으로 컴파일 됨

  • #define은 변수를 선언하지 않기 때문에 기억공간이 마련되지 않아 메모리를 사용하지 않음

#define DATA1 100
#define DATA2 11.11
#define DATA3 'a'
#define DATA4 "안녕하세요"

int main()
{
	printf("DATA1 : %d\n", DATA1);
	printf("DATA2 : %f\n", DATA2);
	printf("DATA3 : %c\n", DATA3);
	printf("DATA4 : %s\n", DATA4);

}





연산자

  • 산술 연산자: 더하기, 빼기 등 일반적인 산수에서 사용하는 연산자

  • 관계 연산자: 같다, 다르다 등의 관계를 계산하는 연산자, 참은 1, 거짓은 0을 반환

  • 논리 연산자: 연산자 좌우의 관계 연산자 값에 따라 0이나 1을 반환하는 연산자

  • 비트 연산자: 2진수로 숫자에 대한 연산자

  • 대입 연산자: 우측에서 연산된 수식의 값을 좌측의 변수에 저장하는 연산자

  • 기타 연산자: sizeof, &, *, ? :



산술 연산자

+, -, *, /, % (나머지)
++ (변수에 들어가는 값 하나 증가)
-- (변수에 들어가는 값 하나 감소)

int d = 10;
int e = 10;
int f = 10;
int g = 10;

c = d;
d = d + 1;
printf("c, d : %d, %d\n", c, d);

d = 10;
c = d++;
printf("c, d : %d, %d\n", c, d);

c = ++e;
printf("c, e : %d, %d\n", c, e);

c = f--;
printf("c, f : %d, %d\n", c, f);

c = --g;
printf("c, f : %d, %d\n", c, g);



관계 연산자

==, !=, >, <, >=, <=

    int a = 21;
    int b = 10;
    int c;

    c = a == b;
    printf("a == b :%d\n", c);

    c = a != b;
    printf("a != b :%d\n", c);

    c = a < b;
    printf("a < b :%d\n", c);

    c = a > b;
    printf("a > b :%d\n", c);

    c = a <= b;
    printf("a <= b :%d\n", c);

    c = a >= b;
    printf("a >= b :%d\n", c);



논리 연산자

두 관계식의 논리 값

&&(and), ||(or), !(not)
*참고: |는 shift+\

int a = 10 > 2; //1
    int b = 10 > 20; //0
    int c = 10 > 3; //1
    int d = 10 > 30; //0

    int e;

    e = a && b;
    printf("a && b : %d\n", e);

    e = a && c;
    printf("a && c : %d\n", e);

    e = b || c;
    printf("a || c : %d\n", e);

    e = b || d;
    printf("b || d : %d\n", e);

    e = !a;
    printf("!a : %d\n", e);

    e = !b;
    printf("!a : %d\n", e);

    int f = 10;
    
    e = f >= 5 && f <= 20;

    printf("e : %d\n", e);



비트 연산자

  • &(and), |(or), ^(exist or), ~(not), <<(left shift), >>(right shift)
  • 일반적인 프로그램에서 거의 사용하지 않음
    ^는 같을 때 0, 다를 때 1 출력
    int a = 60; // 0011 1100
    int b = 13; // 0000 1101
    int c;

    c = a & b; // 0000 1100
    printf("a & b : %d\n", c);


    c = a | b; // 0011 1101
    printf("a | b : %d\n", c);

    c = a ^ b; // 0011 0001
    printf("a ^ b : %d\n", c);

    c = ~a; // 1100 0011
    printf("~a : %d\n", c);

    c = a << 2; // 1111 0000
    printf("a << 2 : % d\n", c);

    c = a >> 2; //0000 1111
    printf("a >> 2 : % d\n", c);



대입 연산자

=: 오른쪽 값을 왼쪽에 대입
+=: ex. C+ = A → C = C+A
-=: ex. C- = A → C = C-A
=: ex. C = A → C = C*A
/=: ex. C/ = A → C = C/A
%=: ex. C% = A → C = C%A
<<=: ex. C<<=2 → C=C<<2
>>=: ex. C>>=2 → C=C>>2
^=: ex. C^=2 → C=C^2
|=: ex. C|=2 → C=C|2



기타 연산자

  • Sizeof(): 괄호 안 변수나 자료형의 바이트 수 확인
  • &: 변수 앞에 붙을 경우 해당 메모리 상 주소값 확인
  • *: 포인터 변수
  • ?: : 좌측 수식 값이 참이면 좌측 값이, 거짓이면 우측 값이 최종 결과 값이 됨





분기문

  • 조건에 따라 코드 수행 여부를 결정하는 구문
  • 위에서 아래로 흐르는 코드의 수행을 변경하고자 할 때 사용
  • 주로 주어지는 조건식의 결과에 따라 어느 부분을 수행할지 결정하는데 사용
  • If문과 switch 문 사용



If 문

  • If 문은 조건에 만족하는 곳이 수행되는 분기문

  • 주어지는 조건식이 0이 아니면 구문이 수행되고, 0(거짓)이면 수행되지 않음



If else 문

  • 주어지는 조건식이 0이 아니면 if 부분이 수행되고, 0이면 else 부분이 수행
{
  int a =30;
  int b = 20;

  if(a > b){
	  printf("a는 b보다 큽니다\n");
  }
  else {
	  printf("a는 b보다 크지 않습니다\n");
  }



If else if 문

  • 주어지는 조건식 중 0이 아닌 부분이 수행
  int a = 100;

    if (a < 0) {
        printf("a는 0보다 작습니다\n");
    }
    else if (a < 5) {
        printf("a는 0보다 작습니다\n");
    }
    else if (a < 10) {
        printf("a는 10보다 작습니다\n");
    }
    else if (a < 20) {
        printf("a는 20보다 작습니다\n");
    }
    else {
        printf("a는 0, 5, 10, 20보다 작지 않습니다\n");
    }



Switch

  • 주어진 수식이나 변수의 값에 해당하는 부분이 수행

  • Break 문을 생략하면 하단 코드가 모두 수행됨

  • Break가 있다면 아웃, 없다면 하단 부분 모두 실행, 일치하는 부분이 없으면 디폴트 실행

 int a = 100;

    switch (a) {
    case 0:
        printf("a는 0입니다\n");
    case 5:
        printf("a는 5입니다\n");
    case 10:
        printf("a는 10입니다\n");
    case 20:
        printf("a는 20입니다\n");
    default :
        printf("a는 0, 5, 10, 20이 아닙니다\n");
    }
 int b = 10;

        switch (b) {
        case 0:
            printf("b는 0입니다\n");
            break;
        case 5:
            printf("b는 5입니다\n");
            break;
        case 10:
            printf("b는 10입니다\n");
            break;
        case 20:
            printf("b는 20입니다\n");
            break;
    }





반복문

  • 코드의 일부분을 필요한 만큼 반복하는데 사용
  • 개발자가 원하는 만큼, 혹은 반복할 조건이 있을 때 원하는 코드를 반복시킬 수 있음
  • For, while, do~while 3가지 구문 제공



While 문

  • 주어진 조건식이 거짓이 될 때까지 반복

  • 반복횟수를 결정하지 못하지만 반복한 조건이 있을 경우 사용

  • 조건식이 처음부터 거짓이면 한번도 수행되지 않음

  • While(조건식){
    코드
    }

int a = 10;
    while (a < 20) {
        printf("a : %d\n", a);
        a++;
    }

   printf("while 문 종료\n");



For 문

  • 주어진 조건이 만족하는 동안 반복하는 반복문

  • 반복 횟수가 결정 되어 있을 때 사용

  • 초기식은 최초에 한 번만 수행되고 조건식을 검사한 후 참이면 구문을 실행하고 증감식을 실행한다. 그 후 다시 조건식을 검사하고 참이면 구문을 실행하고 증감식을 실행한다. 조건식이 거짓이 될 때 까지 이 과정을 반복한다.

  • For(초기식; 조건식; 증감식){
    구문
    }

    int i;
    for (i = 0; i < 10; i++){
    printf("%d\n", i);
    }
    printf("for문 종료\n");



Do while 문

  • 주어진 조건식이 거짓이 될 때 까지 반복

  • 반복횟수를 결정하지 못하지만 반복한 조건이 있을 경우 사용

  • 조건식이 처음부터 거짓이라도 한번은 수행 (조건 검사가 하단에 위치하기 때문에)

  • Do{
    코드
    } while (조건식);

   int a = 10;

    do {
        printf("a : %d\n", a);
        a++;
    } while (a < 20);






함수

  • 프로그램 작성 시 자주 사용하는 코드가 있다면 함수로 만들어 사용하는 것이 편리함
  • 함수는 하나의 작업을 위해 필요한 코드들을 그룹화 시켜놓은 것으로써 함수를 만들어 코드를 작성한 후에 작성 코드의 동작이 필요할 때 함수 내부의 코드를 동작시켜 필요한 결과를 얻을 수 있도록 함
  • 함수 내부의 코드를 동작시키기 위해 함수를 지정하는 것을 '함수를 호출한다'라고 부름
  • 함수를 호출하게 되면 코드의 흐름은 함수 쪽으로 이동하고 함수의 코드가 모두 수행이 되면 다시 함수를 호출한 쪽으로 돌아감
  • Main도 함수이며 이 함수는 프로그램이 시작되면 OS가 자동으로 호출하는 함수이며, 개발자는 main 함수에서부터 코드를 작성하게 됨
  • 반복해서 사용하는 코드가 있다면 함수로 만들어서 사용하면 생산성 향상에 도움이 됨



함수 작성

  • 함수를 호출 할 때 값을 전달할 수 있으며, 이는 매개변수로 받음

  • 반환값 함수이름 (매개변수){
    코드
    }

  • 반환값: 함수의 수행이 모두 완료되면 함수를 호출한 곳으로 되돌아가는데 이 때 값 하나를 전달할 수 있음.
    함수의 수행이 끝난 후 전달값이 있다면 그 값의 자료형을 작성함. 만약 없다면 void를 작성

  • 함수 이름: 식별자 규칙에 맞게 함수를 구분할 수 있는 이름을 작성

  • 매개 변수: 함수를 호출하여 함수 내부의 코드가 수행될 때 필요한 데이터가 있다면 매개 변수를 통해 받을 수 있음



함수 선언

  • 만약 작성된 함수가 호출하는 코드보다 아래에 있다면 경고가 나타나거나 C언어의 종류에 다라서 오류가 발생할 수 있음

  • 함수가 호출하는 코드보다 아래에 있다면 함수의 존재를 알려주기 위해 함수를 선언해줘야 함
    - 반환타입 함수명(매개변수);

void test1() {
    printf("test1 함수가 호출되었습니다\n");
}

void test2();

int test3(){
    return 100;
}

int test4(int v1, int v2) {
    int v3 = v1 + v2;
    return v3;
}

int main()
{
    test1();
    test2();

    int a1 = test3();
    printf("a1 : %d\n", a1);

    int a2 = test4(100, 200);
    printf("a2 : %d\n", a2);
}

void test2() {
    printf("test2 함수가 호출되었습니다\n");
}






변수의 사용

  • 개발자가 변수를 선언할 때 선언한 위치에 따라 변수를 사용할 수 있는 범위가 결정됨
  • 변수를 사용할 수 있는 범위라면 자유롭게 사용이 가능하지만 그렇지 않다면 변수를 사용할 수 없음
  • 변수의 사용 범위가 같은 변수 끼리는 동일 이름을 가질 수 없으며 사용 범위가 다르면 변수 이름이 동일해도 됨



지역 변수

  • 특정 영역 내부에서만 사용할 수 있는 변수
    - 함수 내부에서 선언한 변수

  • 매개 변수

  • 분기문, 반복문 내에서 선언한 변수



전역 변수

  • 어느 영역에 포함되어 있지 않는 변수

  • 어디서든 사용이 가능

  • 만약 전역 변수와 지역 변수명이 동일할 경우 지역 변수를 사용






포인터

본자료형 변수와 참조 자료형 변수

  • 기본 자료형 변수: 기본 자료형 값을 담는 변수 (일반 변수)

  • 참조 자료형 변수: 참조 자료형 값을 담는 변수 (포인터 변수)

  • 포인터 변수에 담을 기억공간의 주소 값은 & 연산자로 알아올 수 있음

  • 포인터 변수는 *(애스터리스크)를 붙혀서 선언



포인터 변수의 사용

  • 일반 변수에는 실제로 사용할 값들이 들어있으므로 변수를 사용하면 값이 나옴

  • 포인터 변수는 기억공간의 주소 값이 들어 있으므로 변수를 사용하면 기억 공간의 주소 값이 나옴

  • 포인터 변수를 사용할 때 *연산자를 사용하면 포인터 변수에 들어 있는 주소 값을 가져오고 주소 값을 통해 기억장소에 접근하여 해당 변수를 사용할 수 있음



NULL

  • 포인터 변수를 선언하고 기억공간의 주소 값을 넣지 않을 때는 NULL 값을 넣어준다. 포인터 변수 선언 후 주소 값을 넣지 않으면 예상하지 못한 값들이 들어 있을 수도 있기 때문이다.

  • NULL은 의미가 없는 값을 의미

  • 기본 자료형에서는 void, 참조 자료형에서는 NULL을 사용



다중 포인터

  • 포인터 변수는 특정 기억공간의 주소 값을 가지고 있는 변수

  • 만약 포인터 변수가 가지고 있는 주소에 해당하는 기억공간이 포인터 변수라면 그 포인터 변수도 다른 기억공간의 주소값을 가지고 있게 된다. 이 때 최종 기억 공간이 접근할 경우 다중 포인터를 사용한다.

 int a1 = 100;
    int *a2 = &a1;
    int a3 = a1;

    printf("a1 : %d\n", a1);
    printf("a2 : %d\n", a2);
    printf("*a2 : %d\n", *a2);

    a3 = 1000;
    printf("a1 : %d\n", a1);
    printf("a3 : %d\n", a3);


    *a2 = 2000;
    printf("a1 : %d\n", a1);
    printf("*a2 : %d\n", *a2);

    int *pt = NULL;
    printf("pt :%d\n", pt);

    if (pt) {
        printf("포인터 변수 pt에는 주소 값이 설정되어 있습니다\n");
    }

    int a10 = 100;
    int *a20 = &a10;
    int**a30 = &a20;

    printf("a10 : %d\n", a10);
    printf("*a20 : %d\n", *a20);
    printf("**a30 : %d\n", **a30);



함수 포인터

  • 개발자가 만든 함수의 주소 값을 가지고 있는 포인터를 함수 포인터라고 함

  • 개발자가 만든 함수들도 메모리의 기억공간에 저장되는데 함수가 저장된 기억공간의 주소 값을 포인터 변수에 담아놓고 이를 이용해 함수를 호출할 수 있는 개념임

int test1() {
    return 100;
}

void test2(int *v1) {
    *v1 = 100;
}

void test3(int *v1, int *v2) {
    *v1 = 1000;
    *v2 = 2000;
}

int main()
{
    int a1 = test1();
    printf("a1 : %d\n", a1);

    int a2;
    test2(&a2);
    printf("a2 : %d\n", a2);

    int a3;
    int a4;

    test3(&a3, &a4);
    printf("a3 : %d\n", a3);
    printf("a4 : %d\n", a4);

}
void test1(int a, int b) {
    printf("a : %d\n", a);
    printf("b : %d\n", b);
}

void add(int a, int b) {
    printf("add: %d\n", a + b);
}

void minus(int a, int b) {
    printf("add: %d\n", a - b);
}

void process(void (*fn)(int, int), int a, int b) {
    fn(a, b);
}

int main()
{
    void (*pt)(int, int); //pt: 포인터 변수의 이름, 매개변수는 int와 같이 타입만 작성해주면 함수 포인터 선언 가능
    pt = test1;
    pt(10, 20);

    process(add, 100, 200);
    process(minus, 100, 200);

}

reference

소프트캠퍼스, 처음 시작하는 C언어, 구름EDU, URL, 2021년 8월 23일 수강

0개의 댓글