별의 공부 블로그 🧑🏻‍💻
728x90
728x170

1) 변수

- 변수선언 : 자료형 + 변수명    예) int a;

- 대입 연산 : 변수에 값 저장

- 정수형 자료형 : char, short, int, long, long long 

- 양수 전용 자료형 : unsigned 사용.    예) unsigned int ua;

- 실수형 자료형 : float, double, long double

- 문자열 저장 : char 배열

- const를 사용한 변수 -> 변수의 상수화

- 식별자 : 필요에 따라 만들어 쓰는 단어

 

 

2) 상수와 데이터 표현 방법

- 상수 : 프로그램 실행 중에 바뀌지 않는 값

  정수 표현 - 12(10진수), 014(8진수), 0xc(16진수)

  실수 표현 - 0.0000315(소수점 표기), 3.14e-5(지수 표기)

  문자와 문자열 표현 - 'A'(문자), "A"(문자열)

- 정수가 컴파일 되면

   양수 → 4바이트 2진수, 음수 → 4바이트 2의 보수.

- 실수가 컴파일 되면

   실수 → IEEE 754 표준

- 실수는 오차가 있다!

 

 

3) C 프로그램의 기본 형태와 데이터 출력 방법

- 프로그램의 기본 형태

  main함수는 머리 + 몸체

  몸체 안에 내용은 들여 쓰기

  문장의 끝은 세미콜론을 표시

  소스코드를 설명하는 주석문은 // 와 /*  */를 사용

- printf함수로 화면 출력

  기본은 문자열 출력

   제어 문자 출력('\n', '\r', '\t', '\b', '\a' 등)

   정수는 %d, 실수는 %lf로 출력

 

4) 프로그램과 C언어 / 컴파일러 사용법

- 프로그래밍의 기본 절차

  : 저장공간 확보 → 입력 → 처리 → 출력

- C의 특징

   C는 이식성이 좋음, 함수 사용, 시스템 프로그래밍 가능

- 표준화 과정

  : K&R → ANSI C(1989) → C99(1999) → C11(2011)

- 프로그램 작성 순서

  : 소스파일 작성 → 컴파일 → 실행

- 소스파일

  : 아스키 코드(ASCII code)에 따라 저장된 파일

- 실행파일

  : 컴퓨터가 이해할 수 있는 기계어 형태의 파일

- VC++ 컴파일러 사용법

  : 프로젝트 생성 → 소스파일 추가 → 빌드 → 실행

 

 

5) 데이터 입력

- scanf 함수로 데이터 입력 : 변수 앞에 &를 붙인다!

- 자료형에 따른 변환문자 사용

정수 : short(%hd), int(%d), long(%ld), long long(%lld)

실수 : float(%f), double(%lf), long double(%Lf)
문자와 문자열 : char(%c), char 배열(%s)

- 여러 개의 변수 동시 입력 : scanf("%d %lf", &a, &b);

*화이트 스페이스(white space) : Space/Tab/Enter 키

- 문자열 입력할 때 변수 앞에 &를 붙이지 않는다.

 

 

6) 산술, 관계, 논리연산자

- 피연산자는 상수, 변수, 수식 가능

- 피연산자의 수에 따라 단항(1걔), 이항(2개), 삼항(3개)

- 대입 연산 : 오른쪽의 값을 왼쪽 변수에 저장

- / 연산자는 피연산자가 모두 정수일 때 몫 계산

- ++, --의 후위형은 값을 연산에 사용하고 변수 증감


 

ex)

       int a = 5;

       int b;

      

      b = ++a * 3;

        printf("%d, %d", a, b);       // 6, 18


        그런데

       int a = 5;

       int b;

      

      b = a++ * 3;

        printf("%d, %d", a, b);       // 6, 15

 


- >, >=, <, <=, ==, != 의 연산 결과는 1 또는 0이다.

- &&와 ||는 숏 서킷 롤(short circuit rule)이 있다.


 

ex1) [&&(AND) 연산자]

       int a = 5;

       int b = 0;

       if( (a > 0) && (++b > 0) ) {         // 두 항의 연산 결과가 모두 1이므로 "OK" 출력.

             printf("OK"); }

       else {

             printf("Cancel"); }

       printf("%d, %d", a, b);  //  5, 1


   그런데


     int a = 5;

     int b = 0;

     if( (a < 0) && (++b > 0) ) {             // a < 0 에서 연산 결과가 0이 나오므로, 오른쪽 항의 연산(++b)을 무시하고 "Cancel" 출력.  (서킷 )

            printf("OK"); }

     else {

            printf("Cancel"); }

    printf("%d, %d", a, b);  //  5, 0

ex2) [||(OR) 연산자]

       int a = 5;

       int b = 0;

       if( (a > 0) || (++b > 0) ) {         // a > 0 에서 연산 결과가 1이 나오므로, 오른쪽 항의 연산(++b)을 무시하고 "OK" 출력.  (서킷 )

             printf("OK"); }

       else {

             printf("Cancel"); }

       printf("%d, %d", a, b);  //  5, 0

       int a = 5;

       int b = 0;

       if( (a < 0) || (++b > 0) ) {         // ++b > 0 에서 연산 결과가 1이 나오므로, "OK" 출력. 

             printf("OK"); }

       else {

             printf("Cancel"); }

       printf("%d, %d", a, b);  //  5, 1


 



*변수가 공간으로 쓰일때 l-value, 값으로 쓰일 때 r-value

ex) a = 10 // a : l-value

      b = a  // a : r-value

 

 

7) 비트 연산자와 그 외의 멋진 연산자

- 형변환 연산자는 피연산자의 값의 형태를 바꾼다.

- sizeof 연산자는 피연산자의 크기를 알려준다.

- 복합대입 연산자 : +=, -=, *=, /=, %=

- 콤마 연산자 : 연산자 우선순위가 가장 낮다.

- 조건 연산자( ? : )는 조건을 판단해서 결과를 구한다.

- 비트 논리 연산자 : 비트별 and (&), or(|), 오른쪽 이동(>>), 왼쪽 이동(<<)

- 연산자는 우선 순위가 같을 때 연산 방향을 따진다.


*비트 복합대입 연산자 : a &= b, a |= b, a ^= b, a <<= n, a >>= n (n:임의의 수)

 

 

8) if문

- if문은 조건식이 참일 때 문장을 실행한다.

- 실행문이 두 문장 이상이면 반드시 중괄호 사용

- if ~ else문은 두 개중에 하나 선택

- if문을 두 번 사용한 것 보다 if ~ else문을 사용

- if ~ else if ~ else문은 3개 이상에서 하나 선택 조건을 차례로 검사하므로 이전 조건의 결과 반영

 

 

9) if문의 활용과 switch~case문

 

- if문의 실행문으로 if문 사용하면 중첩이다. 선행조건이 있는 경우 사용.

- if ~ else if ~ else문도 중첩된 if문이다.


 ex)

int a = 10;

if ( a > 0 )

     printf("양수");

else if ( a == 0 )

     printf("0");

else

     printf("음수");


위의 소스코드는 아래의 소스코드와 같다.


int a = 10;

if ( a > 0 )

     printf("양수");

else

     if ( a == 0 )

           printf("0");

    else

           printf("음수");}

}



- else는 가장 가까운 if와 쌍을 이룬다.

- swtich ~ case는 break로 다중선택 구문을 만든다.

  조건식과 일치하는 case가 없으면 default로 간다.

 

 

10) while, for, do~while

- 반복문은 조건식이 참인 동안 실행문을 반복한다.

- while문은 조건을 먼저 검사한다.

- for문은 반복 횟수를 알 때 사용한다.  

  초기식, 조건식, 증감식이 반복 횟수를 결정한다. (for ( 초기식; 조건식; 증감식)) 

  ex) for ( i = 0; i < 3; i++ )

  반복문 안에서 반복 횟수를 세는 변수를 바꾸지 않는다.

- do ~ while문은 일단 수행한 후에 조건을 검사한다.

  조건과 관계없이 최소 한번은 실행된다.


*while문은 do ~ while문을 전부 대체할 수 있다.

 

 

11) 반복문 활용

- 반복문의 실행문으로 반복문이 쓰이면 중첩 반복문이다.

   반복문이 중첩되면 서로 다른 제어 변수를 사용한다.

- 중첩 반복문 구현 방법

  기본 문장 구현 -> 반복 횟수 결정 -> 반복 규칙 적용

- break는 자신을 감싸고 있는 가장 가까운 반복문 탈출

- continue는 조건에 따라 실행문의 일부를 건너뛴다.

- 무한 반복문 : while(1), for(;;)

 

12) 함수의 작성과 사용

- 함수의 머리(head)에는 반환형, 함수명, 매개변수가 있다.

ex) int sum(int a, int b      : 반환형,       : 함수명,       : 매개변수 

- 함수가 다르면 같은 이름의 변수를 선언할 수 있다.

- 함수를 호출할 때는 매개변수에 인수를 복사한다.

- 함수는 return문으로 호출한 곳으로 값을 반환한다.

- ​함수 선언을 통해 매개변수와 반환값의 정보를 확인한다.

- 함수는 원형에 세미콜론을 붙여서 선언한다.

 

 

13) 여러 가지 함수 유형

- 함수는 기능에 따라 매개변수나 반환값이 없을 수 있다.

- 매개변수가 없는 함수는 매개변수 자리에 void를 사용한다.

- 함수를 호출할 때 인수가 없어도 괄호는 사용한다.

- 반환값이 없는 함수는 반환형으로 void를 사용한다.

- 재귀호출 함수는 함수 안에서 자신을 다시 호출한다.

- 재귀호출 함수는 바로 직전에 호출한 곳으로 반환한다.

 

 

14) 배열의 선언과 사용

- 배열은 같은 형의 변수를 연속된 메모리 공간에 할당한다.

- 배열의 첨자는 0부터 배열 요수 수 -1까지만 사용한다.

- 배열은 중괄호로 묶어서 초기화한다.

- 배열요소의 수보다 초기화 값이 적으면 남는 요소는 0으로 자동 초기화한다.

- 배열의 데이터는 반복문으로 처리한다.

- 배열 요소의 수는 sizeof(배열명) / sizeof(배열 요소)로 구한다.

ex) sizeof(ary) / sizeof(ary[0])

 

 

15) 문자를 저장하는 배열

- char 배열은 문자열을 저장하는 용도로 사용한다.

- char 배열은 널(NULL) 문자(\0)를 저장할 공간도 있어야 한다.

- 중괄호 없이 문자열상수로 직접 초기화 할 수 있다.

ex) char ary[10];

      char ary[0] = 'L';

      char ary[1] = 'O';

      char ary[2] = 'V';

      char ary[3] = 'E';

      char ary[4] = '\0';

- char 배열에 문자열을 대입할 때는 strcpy 함수를 쓴다.

ex) strcpy(str, "apple"); : str 배열에 "apple' 문자열 대입.

- gets 함수는 빈 칸을 포함하여 한 줄을 입력한다.


*배열에서 gets 함수와 scanf 함수의 차이점.

gets 함수 : 띄어쓰기까지 포함함. (↔puts 함수), 전처리기 #include <string.h> 필요.

         ex) gets(str)에 "Love is"를 입력하면 배열에 Love is 모두 저장됨. 

scanf 함수 : 띄어쓰기를 포함하지 않음. 

         ex) scanf("%s", str)에 "Love is"를 입력하면 배열에 Love만 저장됨.

 

 

16) 포인터의 기본 개념

- 변수의 저장공간이 메모리에 할당되면 주소를 갖는다.

- 주소 연산자(&)는 변수의 메모리 시작 주소를 구한다.

- 포인터는 주소를 저장하는 변수이다.

- 포인터에 간접 참조 연산자(*)를 사용하면 가리키는 변수를 사용할 수 있다.

- 포인터는 가리키는 자료형과 상관없이 모두 크기가 같다. (4바이트)

- const 포인터는 포인터로 가리키는 자료형을 바꿀 수 없다.

ex1) const int *pa = &a;

       pa = &b (o)

      *pa = 10 (x)

       a = 10;   // 가능

ex2) int * const pa = &a;  

        pa = &b (x)

      *pa = 10 (o)

       a = 10;   // 가능

ex3) const int * const pa = &a;

        pa = &b (x)

      *pa = 10 (x)

       a = 10;   // 가능

 

 

 

17) 포인터에 관한 궁금한 이야기

- 주소는 '상수'이고 포인터는 '변수'이다.

- 포인터는 가리키는 자료형과 관계없이 크기가 같다. (4바이트)

- 포인터는 가리키는 자료형이 같을 때만 대입한다.

- 포인터는 두 변수의 값을 바꾸는 함수의 매개변수로 쓴다.

 

 

18) 배열과 포인터의 관계

- 배열명의 첫 번째 요소의 주소로 바뀐다.

- 배열 + 정수 => 주소 + (정수 * 주소를 구한 변수의 크기)

ex) a + (4 * sizeof(*a))

- ary[1] ⇔ *(ary + 1)

- 포인터가 배열명을 저장하면 배열명처럼 쓸 수 있다.

- 배열명은 상수이고 포인터는 변수이다.

- 포인터 - 포인터 => 값의 차 / 가리키는 자료형의 크기

 

19) 배열을 처리하는 함수

- 배열을 처리하는 함수를 호출할 떄는 배열명을 준다.

- 배열을 처리하는 함수의 매개변수로는 포인터를 쓴다.

ex) doulbe average_ary(int *p, int size)

- 함수 안에서 포인터 매개변수는 배열명처럼 쓴다.

- 배열 요소의 수가 다른 배열도 출력하려면 배열 요소의 수를 함수의 인수로 준다.

- 함수의 매개변수에 선언된 배열은 포인터로 바뀐다.

 

 

20) 아스키 코드값과 문자 입출력 함수

- 문자는 아스키 코드(ASCII code)값으로 저장된다.

- %c 변환문자는 공백, 탭, 개행문자도 입력한다.

- %c 앞에 공백을 사용하면 문자도 분리하여 입력할 수 있다.

ex) scanf("%c %c", &a, &b);

- %c로 입력할 때는 char형 변수를 사용한다.

- getchar는 문자 전용 입력함수이다.

- putchar는 문자 전용 출력함수이다.


*%c는 제어문자(Enter, Spacebar 등)도 입력한다.

*getchar() / putchar()의 반환값 형태는 int형이다.

ex) int a;

      a = getchar();

      putchar(a);

 

 

21) 버퍼를 사용하는 입력함수

- scanf 함수는 키보드 이전에 버퍼(buffer)에서 입력한다.

- 키보드 입력 데이터는 개행문자가 함께 버퍼에 저장된다.

- scanf 함수는 키보드로 Ctrl+Z를 누르면 -1을 반환한다.

- getchar 함수를 반복 사용하면 문자열을 입력할 수 있다.

- 버퍼의 내용을 지울 때는 fflush(stdin) 함수를 사용한다.

 

 

22) 문자열과 포인터

- 문자열은 컴파일 과정에서 첫 번째 문자의 주소가 된다.

- 주소로 접근하여 문자열을 바꿔서는 안 된다.

- char 포인터에 문자열을 대입하여 사용할 수 있다.

- scanf 함수는 공백 전까지의 문자열만 입력한다.

- gets 함수는 공백을 포함한 한 줄의 문자열을 입력한다.

- fgets 함수는 최대 배열의 크기까지만 문자열을 입력한다.

- 표준 입력 함수들은 같은 버퍼를 공유한다.


*gets() 함수를 사용할 경우, 배열 속 개행 문자(\n)를 지우고 싶을 때 str[strlen(str - 1)] = '\0'; 사용.

 

 

23) 문자열 연산 함수

- strcpy 함수는 char 배열에 문자열을 복사한다.

- strncpy 함수는 문자열의 일부를 복사한다.

- strlen 함수는 char 배열에 저장된 문자열의 길이를 구한다.

- strcat 함수는 두 개의 문자열을 이어 붙인다.

- strncat 함수는 문자열의 일부를 붙인다.

- strcmp 함수는 문자열의 사전 순서

- strncmp 함수는 문자열의 일부를 비교한다.

 

 

24) 변수 사용 영역

- 지역 변수는 사용 범위가 블록으로 제한된다.

- 전역 변수의 사용 범위는 프로그램 전체이다.

- 정적 변수는 프로그램 끝날때까지 저장공간을 유지한다.

- 변수의 사용 범위가 겹치면 가까운 곳의 변수를 쓴다.

- 레지스터 변수는 저장공간을 레지스터에 할당한다.

 

 

25) 함수의 데이터 공유 방법

- 변수를 주고 함수를 호출하면 변수의 값이 전달된다.

- 주소를 주고 함수를 호출하면 원본의 값을 바꿀 수 있다.

- 지역 변수의 주소를 반환해서는 안 된다.

- C언어는 포인터를 통해 call by reference를 구현한다.

 

26) 2차원 배열

- 2차원 배열은 1차원 배열을 요소로 갖는다.

- int s[3][4]; 에서 마지막 요소는 s[2][3]이 된다.

- 2차원 배열은 물리적으로 1차원 배열처럼 할당된다.

- 2차원 배열의 초기화는 중괄호 쌍을 두 개 쓴다.

- 2차원 char 배열은 여러 개의 문자열을 저장한다.

- 2차원 char 배열은 각 행 단위를 문자열로 초기화한다.

- 3차원 배열은 2차원 배열을 요소로 갖는 새로운 배열이다.


*

[1차원 배열]

int s1[4];

□□□□


[2차원 배열]

int s2[3][4];

□□□□

□□□□

□□□□


[3차원 배열]

int s3[2][3][4];

□□□□     □□□□

□□□□     □□□□

□□□□     □□□□

 

 

27) 포인터 배열

- 포인터 배열은 같은 형태의 포인터로 만든 배열이다.

- char 포인터 배열은 여러 개의 문자열로 초기화한다.

- 포인터 배열이 1차원 배열을 연결하면 2차원 배열처럼 쓸 수 있다.

- 포인터 배열은 포인터 연산을 통해 2차원 배열처럼 쓴다.

 

 

 

28) 2중 포인터와 배열 포인터

- 포인터의 주소는 2중 포인터에 저장한다.

- 2중 포인터는 포인터의 값을 바꾸는 함수의 매개변수나 포인터 배열을 매개변수로 받는 함수에 사용한다.

- 배열의 주소는 배열 포인터에 저장한다.

- 배열 포인터를 매개변수에 쓰면 함수에서 2차원 배열처럼 사용한다.

 

 

29) 함수 포인터와 void 포인터 

- 함수명은 함수의 정의가 있는 메모리의 시작 위치다.

- 함수명을 함수 포인터에 저장하면 포인터로 함수를 호출할 수 있다.

- 형태가 같은 다양한 기능의 함수를 선택적으로 호출한다.

- void 포인터는 가리키는 자료형이 정해지지 않는다.

- void 포인터를 쓸 때는 원하는 형태로 반환하여 쓴다.

 

 

30) 동적 할당 함수

- 메모리 동적할당은 malloc 함수를 호출하고

- 반납할 때는 free 함수를 호출한다.

- 동적할당 영역은 원하는 형태로 형변환하여 사용한다.

- malloc 함수의 반환값이 널포인터가 아닌지 검사한다.

- 많은 저장 공간을 한꺼번에 동적 할당하여 배열처럼 쓴다.

- calloc 함수는 할당한 저장 공간을 0으로 초기화한다.

- realloc 함수는 동적할당 공간의 크기를 조절한다.

 

 

31) 동적 할당 저장 공간의 활용

- 동적 할당으로 입력되는 문자열의 길이에 맞게 저장공간을 사용한다.

- 포인터 배열을 처리하는 함수의 매개변수는 2중 포인터를 사용한다.

- 명령행 인수를 쓸 때는 main 함수의 매개변수를 선언한다.

- argc는 명령행 인수의 수, argv는 명령행 인수의 포인터

 

 

32) 구조체

- 구조체는 형 선언으로 그 형태를 컴파일러에게 알려준다.

- 구조체 변수의 특정 멤버를 사용할 때는 .연산자를 쓴다.

- 구조체의 크기는 바이트 얼라인먼트에 따라 달라진다.

- 배열, 다른 구조체, 포인터 등을 멤버로 쓸 수 있다.

- 초깃값을 중괄호로 묶고 멤버 순서대로 초기화한다.

- 형태가 같은 구조체 변수끼리 대입연산이 가능하다.

- 비트필드 구조체는 멤버의 크기가 비트 단위이다.

 

 

33) 구조체 활용, 공용체, 열거형

- 구조체 포인터로 가리키는 구조체의 멤버를 사용할 때는 → 연산자를 사용한다.

- 같은 형태의 구조체가 많이 필요하면 구조체 배열을 쓴다.

- 자기참조 구조체는 연결 리스트를 만들 때 쓴다.

- 공용체는 모든 멤버가 하나의 공간을 공유한다.

- 열거형은 열거형 변수에 저장할 값을 나열한다.

- 형 재정의를 위해 typedef 명령을 사용한다.

 

 

34) 파일 개방과 입출력

- fopen 함수로 파일을 개방하고 fclose 함수로 닫는다.

- 파일 입출력은 논리적 파일인 스트림 파일을 사용한다.

- fgetc 함수는 파일에서 하나의 문자를 입력한다.

- fputc 함수는 파일로 하나의 문자를 출력한다.

- stdin, stdout, stderr은 운영체제가 개방하는 파일이다.

- 파일에는 텍스트 파일과 바이너리 파일이 있다.

- + 개방모드, fseek, rewind, feof 함수 등이 있다.

 

 

35) 다양한 파일 입출력 함수

- fgets 함수는 파일에서 데이터를 한 줄씩 읽는다.

- fgets 함수가 파일의 데이터를 모두 읽으면 널포인터 반환

- 파일에 문자열을 출력할 때는 fputs 함수를 쓴다.

- 형식에 따라 입출력할 때는 fscanf,, fprintf 함수를 쓴다.

- fflush 함수는 스트림 버퍼의 내용을 비운다.

- 데이터 변환 없이 입출력할 때는 fread, fwrite 함수를 쓴다.

 

 

36) 전처리 지시자

- #include는 지정한 파일의 내용을 프로그램에 복사한다.

- #define은 매크로명을 정의한다.

- 매크로 함수는 괄호를 써서 부작용을 최소화한다.

- __FILE__, __LINE__, __DATE__ 등 미리 정의된 매크로다.

- #, ##, 대입 등은 전처리 구문에서 사용하는 연산자이다.

- #if, #elif, #else, #endif 등은 조건부 컴파일 지시자이다.

 

 

37) 분할 컴파일

- 하나의 프로그램은 여러 개의 파일로 나누어 분할 컴파일 할 수 있다.

- 다른 파일에 있는 전역 변수를 사용할 때는 extern선언을 한다.

- 사용자 정의 헤더파일은 각 파일에 공통으로 필요한 코드를 모아 만든다.

- 헤더파일의 중복 포함을 해결하기 위해 #ifndef, #efine 매클명, #endif의 지시자를 사용한다.

 

 

------------------------------------------------------------

내용출처 : 이것이 C언어다 (한빛미디어, 서현우지음)

 

728x90
그리드형(광고전용)
⚠️AdBlock이 감지되었습니다. 원할한 페이지 표시를 위해 AdBlock을 꺼주세요.⚠️
starrykss
starrykss
별의 공부 블로그 🧑🏻‍💻


📖 Contents 📖