본문 바로가기
IT/note

C언어 기본 정리, 입문 문서 공유 [파일 첨부]

by 어느해겨울 2021. 12. 26.

 

C언어 기본 정리

C언어 기본 정리.docx
0.05MB

 

[ 챕터에 대한 링크 ]

1. C프로그램의 구성

2. 데이터형 / 변수 / 상수

3. 자료의 입출력 - 스트림과 자료 전송

4. 연산자

5. 제어문

6. 1차원 배열

7. 다차원 배열

8. 함수와 기억클래스

9. 포인터의 이해

10. 문자열

11. 전처리기

12. 구조체

13. 포인터 고급

14. 파일 입, 출력

15. 메모리 동적 할당

   

1. C프로그램의 구성

C언어는 한 개 이상의 함수로 프로그램이 작성되는데 프로그램 실행 시 가장 먼저 호출되는 함수가 main함수이다.

때문에 C프로그램은 단 한 개의 main함수가 반드시 존재해야 한다.

   

1.1. 프로그램의 기본구조

C언어는 대문자와 소문자를 구별하는데 일반적으로 소문자를 기초하여 작성한다. 모든 명령문은 반드시 세미콜론(;)으로 끝나야 한다. 단, #으로 시작하는 구문 뒤에는 세미콜론(;)을 붙이지 않는다.

   

1.2. 프로그램 기본구조 분석

1) int main()

- C프로그램은 main함수에서 시작된다. main 다음의 괄호 ( () )는 컴파일러에게 main이

함수라는 것을 알려준다.

2) { }

- 중괄호는 여러 문장들을 함께 묶는데 사용된다. main함수 다음의 중괄호는 함수의

시작과 끝을 의미하게 된다.

3) return 0;

- return 0;의 의미는 리턴타입이 int 일 경우 return 0;을 쓰면 프로그램이 정상 종료를

의미한다.

4) #include <stdio.h>

- stdio.h 헤더파일을 포함하라는 구문이다. 헤더 파일이란 C 컴파일러가 제공하는 표준

함수들의 원형이 선언된 파일을 말한다. stdio.h는 표준 입출력(standard input ouput)에

관련된 헤더파일로 입,출력 함수를 사용하기 위해 추가해야 하는 헤더파일이다.

1.3. 프로그램 실행

1) 컴파일(Compile) : 기계어로 번역하는 작업

2) 링킹(Linking) : 목적파일을 실행 가능한 파일(로드모듈)로 만드는 과정

3) 실행(Execute)

   

1.4. Escape Sequence

키보드에 나타나지 않는 문자나 화면에 출력되지 않는 문자들은 역 슬러시(\)를 사용하여 표현할 수 있다. 이 문자들을 이스케이프 시퀀스(출력제어문자)라고 한다.

   

문 자 기 능 문 자 기 능
\n 다음 줄로 이동 (newline) \t 탭 간격만큼 이동 (8byte)
\r 줄의 처음으로 이동 (carriage return) \a 내부 스피커를 통해 경고음 출력
\b 왼쪽으로 커서이동(backspace) \0 널 문자
\\ 백 슬러시(\) 문자 출력 \" 큰 따옴표 출력

* \t는 현재 있는 위치에서 가까운 탭 구간으로 이동

   

1.5. 주석

주석은 /* */ 사이에 쓴다. 컴파일러는 주석을 무시한다. // 다음의 내용은 한 줄 주석으로 처리

[목차로]

   

   

2. 데이터형 / 변수 / 상수

데이터형(Data type) - 정수, 실수, 문자를 구분하며 또한 데이터의 범위나 부호의 사용여부 등을 결정짓는 것을 말한다.

   

2.1. 정수 데이터형

소수점 이하를 표현하지 못함. 무한대의 범위는 지원하지 않는다.

데이터형 앞에 unsigned를 쓰면 음수를 표현할 수 없다.

short 형 : -32,768 ~ 32,767 - 2byte

int 형 : -2,147,483,648 ~ 2,147,483,647 - 4byte

int형의 크기는 규정되어 있지 않지만, 시스템에 따라 2byte(MS-DOS)일수도 있고, 4byte(Windows, UNIX)일수도 있다.

   

2.2. 실수 데이터형

소수점 이하를 표현. 정수와 같은 4byte지만 정수 데이터형보다 훨씬 큰 수와 작은 수를 저장할 수 있다. 이는 정수와 실수를 메모리에 저장하는 방식이 다르기 때문이다.

float(단정도) 형 : -3.4*10-37 ~ 3.4*1038 - 4byte

double(배정도) 형 : -1.7*10-307 ~ 3.4*10308 - 8byte

- 부동소수점형의 크기도 규정되어 있지 않다.

- 실수 데이터형에는 unsigned를 쓸 수 없다.

* 고정소수점 방식 : 실수의 정확한 값을 저장할 수 있고 저장 방법이 단순하기는 하지만 전혀 치밀하지 못하고 효율적이지도 않다. 실수를 부호, 정수부와 소수부로 나눈다.

* 부동소수점 방식 : 부동소수점으로 표현되는 실수는 여러 개 존재할 수 있기 때문에 가수의 정수부는 0이 아닌 한자리로 제한한다. 부호, 지수부와 가수부로 나눈다.

   

고정 소수점 방식 부동 소수점 방식
123.456 1.23456*102
0.00368 3.68*10-3

ex)

   

2.3. 문자형 데이터형

컴퓨터는 0과 1만 가지고 데이터를 저장하기 때문에 문자를 표현할 수 없다. 이에 문자 인코딩 방식으로 ASCII를 사용하여 문자를 표현한다.

Char 형 : -128 ~ 127 - 1byte (값에 문자가 예약)

* 0 ~ 32 - 제어문자, 33 ~ - 출력문자

   

2.4. 변수

데이터를 저장하기 위한 공간으로 저장된 값의 변경이 가능하다.

   

2.4.1. 변수 선언

변수 선언을 하면 메모리 공간을 할당 받아 사용할 수 있게 된다. 선언되지 않은 변수를 사용하면 에러가 발생하며 변수 선언은 반드시 함수 선두에 해야 한다. 최초 변수의 선언 시 의미 없는 값이 저장되는데 이를 쓰레기 값(Garbage Value)라고 한다.

   

2.4.2. 변수 작성 규칙

1) 영문자, 숫자, 밑줄문자(_)를 조합하여 만든다.

2) 첫 변수 명에 숫자는 올 수 없다. (반드시 영문자나 밑줄문자로 시작)

3) 대, 소문자를 구분한다.

4) 공백, 특수문자는 포함할 수 없다.

5) 예약어는 사용할 수 없다.

   

2.4.3. 변수 초기화

선언된 변수에 값을 대입하는 과정을 초기화라 한다. 문자를 쓸 때는 반드시 작은따옴표(' ')안에 써야 한다.

   

2.4.4. 출력 변환 문자

출력문자와 대응되는 뒤쪽의 인수를 문자열 안에 넣어 같이 출력한다.

%d (decimal) - 10진 정수 출력

%f (floating) - 고정 소수점 출력 (소수점 이하 6자리 출력)

%c (character) - 문자 출력

   

2.5. 상수

한번 값을 초기화하면 변경할 수 없는 공간으로 선언하면서 바로 초기 값을 설정해야 한다.

   

2.5.1. 심볼릭(Symbolic) 상수

const 키워드를 붙여 선언한 변수를 의미. 읽기 전용으로 함수 내에서 변경이 불가능하다.

   

2.5.2. 리터럴(Literal) 상수

이름을 갖지 않는 상수로 값 자체를 의미한다.

* 변수 값이 0으로 시작하면 8진수를 의미하며, 0x로 시작하면 16진수를 의미한다. L을 뒤에 붙이면 long형으로 표현되고, 실수 형은 뒤에 f를 붙인다.

[목차로]

   

   

3. 자료의 입출력 - 스트림과 자료 전송

   

3.1. 스트림(Stream)

운영체제는 키보드, 모니터, 프린터 등등 스트림이라는 동등한 장치로 다룬다. 즉, 입, 출력 장치는 다르지만 스트림이라는 논리적인 동등한 장치로 표현되기 때문에 동일한 방법으로 입출력이 가능하다.

   

3.2. 표준 입, 출력 함수와 버퍼(Buffer)

표준 입, 출력 함수는 스트림 내에 버퍼(Buffer)를 사용한다. 여기서 버퍼란 임시 기억장소를 말한다. 입력되거나 출력되는 데이터는 하나씩 전송 되는게 아니라 임시 기억장소에 저장되었다가 일정 순간에 입/출력 되는데 이때 데이터가 저장되는 임시 기억장소를 버퍼라 한다.

   

3.3. 버퍼를 비우는 fflush함수

fflush는 버퍼를 비우는 함수이다. 인수로는 stdin(표준 입력 스트림)이 전달되면 버퍼의 모든 데이터를 비우게 되고, stdout(표준 출력 스트림)이 전달되면 버퍼의 모든 데이터가 즉시 출력된다.

- 입력버퍼 비우기 : fflush(stdin);

- 출력버퍼 비우기 : fflush(stdout);

   

3.4. 입력 함수 - scanf

scanf 함수는 정해진 양식에 맞게 버퍼의 내용을 꺼내오는 함수이다. 변수 명 앞에는 주소를 의미하는 & 연산자(주소연산자)를 써야한다.

ex) scanf("입력 변환문자", &변수);

   

문 자 인수가 입력되는 형태 문 자 인수가 입력되는 형태
%d 정수 입력 %lf double형 실수 입력
%ld long형 정수 입력 %c 문자 입력
%f float형 실수 입력 %s 문자열 입력

   

3.4.1. 입력 함수 - getchar

버퍼에서 한 글자를 가져오는 함수이다.

ex) 변수 = getchar();

   

3.4.2. 입력 함수 - getch

키보드에서 한 글자를 입력받는 함수로 기능키에 주로 사용된다. getch는 버퍼를 사용하지 않기 때문에 입력 즉시 전달된다. 콘솔 입, 출력에 관한 헤더파일인 conio.h 헤더파일을 포함해야 한다.

ex) 변수 = getch();

   

3.5. 출력 함수 - printf

일반적인 출력함수로써, 표준 입, 출력에 관련된 헤더파일인 stdio.h를 추가해야 한다.

ex) printf("출력 변환문자", 변수);

   

문 자 인수가 출력되는 형태 문 자 인수가 출력되는 형태
%d 10진 정수 출력 %c 문자 출력
%f 고정 소수점 출력 %s 문자열 출력
%e 지수 출력 %o 8진 정수 출력
%x 16진 정수 출력 %p 포인터의 번지 출력
%u 부호 없는 10진 정수 출력 %% 문자 % 출력

개형 : %[-][0][m][.n]변환문자 = %[좌측정렬][0][폭][.정확도]변환문자

[목차로]

   

   

4. 연산자

   

4.1. 산술 연산자

정수연산의 결과는 정수이며, 정수와 실수 연산의 결과는 실수이다. 정수 나눗셈의 결과가 양수면 소수점 아래를 버리고, 음수면 소수점 아래를 올린다. % 연산자는 정수 연산에만 사용한다.

* % - 나머지 연산자 ex) 5/2 = 2, 5%2 = 3

   

4.2. 증, 감 연산자

변수에 저장된 값을 1 증가시키거나 1 감소시키는 연산자를 말한다.

* 전치연산(증감연산자가 변수 앞에 나오는 경우) : 변수의 저장된 값을 증/감 시킨 후 연산

* 후치연산(증감연산자가 변수 뒤에 나오는 경우) : 연산 수행 후 변수에 저장된 값을 증/감 시킴

연산자 : ++ (1 증가) , -- (1 감소)

   

4.3. 대입 연산자

변수와 연산 후 다시 그 변수에 대입하는 경우 사용하는 연산자를 말한다.

   

연산자 의미 연산자 의미
= 오른쪽 값을 왼쪽으로 대입 *= 곱한 값 대입
+= 더한 값 대입 /= 나눈 값 대입
-= 뺀 값 대입 %= 나머지 값 대입

   

4.4. 비교 연산자

참과 거짓을 판별하여 참인 경우 결과는 1(참)이 되고, 거짓인 경우는 0(거짓)이 된다.

   

연산자 의미 연산자 의미
< 작다 >= 크거나 같다
> 크다 == 같다
<= 작거나 같다 != 같지 않다

   

4.5. 논리 연산자

여러 조건을 동시에 검사할 때 주로 사용되는 연산자로 비교가 참인 경우 1(참), 거짓은 0(거짓)

또한, C언어는 0만 거짓으로 취급된다. 즉, 0이 아닌 모든 값은 참이다.

   

연산자 의미 설명
&& AND 조건식이 모두 참일 때만 참
!! OR 조건식 중 하나라도 참이면 참
! NOT 참이면 거짓, 거짓이면 참

   

4.6. 비트 연산자

2진수로 변환하여 비트 단위의 연산을 수행하는 연산자. 정수형 데이터에서만 사용가능

   

연산자 의미
& 비트 단위의 AND
! 비트 단위의 OR
^ 비트 단위의 XOR
~ 비트 단위의 NOT

   

4.7. 이동 연산자

비트 단위의 이동을 수행하는 연산자로 '값<<자릿수' 또는 '값>>자릿수'로 표현. 좌측 시프트인 경우 '값*2자릿수'가 되고, 우측 시프트인 경우 '값/2자릿수'가 된다.

   

4.8. 조건 연산자

조건을 판별하여 조건이 참인 경우 참을 실행하고 조건이 거짓인 경우 거짓을 수행

* 조건 ? 참 : 거짓; ex) value = a>b ? a : b;

[목차로]

   

   

5. 제어문

   

5.1. 제어문의 종류

   

조건문 if
   switch
반복문 for
   while
   do ~ while
기타제어문 break
   continue

   

5.1. if문

조건식을 판별하여 조건이 참이면 중괄호 {}안의 명령을 수행하고, 거짓이면 중괄호 {}안의 명령을 점프 후 다음 명령을 수행. 조건에 따라 수행해야 할 명령문이 한 개일 경우 중괄호는 생략가능하다.

   

5.1.1. if ~ else문

둘 중 한 개를 선택하는 조건문으로 조건이 참인 경우와 거짓인 경우(else)에 수행하는 명령이 다르다. else 다음에는 절대로 조건을 쓸 수 없다.

   

5.1.2. 다중 if문

여러 개 중 한 개를 선택하는 경우 사용하는 조건문이다. 다중 if문은 위에 있는 조건부터 차례대로 비교하면서 내려오게 되는데 조건이 참이 되어 명령을 수행하게 되면 아래 있는 나머지의 조건은 비교하지 않고 다중 if문 전체를 빠져 나온다.

   

5.2. switch문

변수의 값을 case에서 찾아 명령을 수행하는 조건문이다. 정수형과 문자형만 가능하며 비교, 논리 연산자는 쓸 수 없다. 변수 혹은 연산식만 가능. 만약 해당하는 값이 없을 경우에는 default의 명령을 수행한다.

ex) switch(변수) { case 'A' : 수행문; default : 수행문; }

   

5.3. for문

조건이 참인 경우 중괄호 {}안의 명령문을 반복적으로 수행하는 제어문이다. for문의 괄호 안에는 3개의 명령을 쓸 수 있는데 이 명령은 세미콜론(;)으로 분리된다. 필요 없는 명령은 생략 가능하며 모든 명령이 생략되면 무한루프(무한반복)에 빠지게 된다.

   

5.3.1. 이중 for문

for문 안에 for문이 들어간 형태로 내부의 명령을 외부의 횟수만큼 반복하게 된다.

   

5.4. while문

조건이 참인 경우 중괄호 {}안의 명령문을 반복적으로 수행하는 제어문으로 조건에 따라 수행해야 할 명령이 한 개일 경우에는 중괄호는 생략이 가능하다.

ex) while(조건) { 명령문 1; 명령문 2; ..... 명령문 n; }

   

5.4.1. do ~ while문

while문과 비슷한 형태의 반복문이지만 명령문을 먼저 실행하고 조건을 비교한다. 따라서 do ~ while문의 명령문은 최소 한번은 반드시 수행된다. do~while문은 뒤에 세미콜론(;)을 써야한다.

   

5.5. break 문

반복 명령의 실행 도중 강제적으로 반복문을 빠져나올 때 사용되는 명령이다. 여러 개의 반복문이 중첩되어 있는 경우 반복문 한 개만 빠져나온다.

   

5.5.2. continue 문

반복문의 나머지 부분을 무시하고 그 반복문의 선두로 이동할 때 사용되는 명령. 여러 개의 반복문이 중첩되어 있는 경우 continue 명령이 있는 반복문의 선두로 이동한다.

   

5.5.3. goto 문

지정한 곳으로 조건 없이 무조건 점프하는 제어문으로 쉽게 사용할 수는 있지만, 프로그램의 구조를 복잡하게 하기 때문에 권장하는 방법이 아님. goto로 옮길 지점은 레이블로 표시하며, 레이블 다음에는 콜론(:)을 붙여 점프할 위치에 삽입한다.

   

5.6. rand 함수

0 ~ RAND_MAX 범위의 난수를 리턴해주는 함수. RAND_MAX는 최소 32767의 값을 갖는 상수이다. stdlib.h에 포함 되어있다.

   

5.6.1. srand 함수

난수 발생의 초기 값을 지정해주는 함수이다.

   

5.6.2. time 함수

srand함수에 고정된 숫자를 초기 값으로 넘겨주면 항상 같은 수가 나오기 때문에, 현재 시간을 초 단위로 리턴하게 하는 time함수를 사용한다. 때문에 srand(time(null))과 같이 호출 하면 rand함수는 항상 다른 값을 나타낸다.

[목차로]

   

   

6. 1차원 배열

   

6.1. 배열(array)

배열은 같은 타입의 변수가 여러 개 필요한 경우 이용한다. 배열은 같은 타입의 변수가 하나의 배열이름에 연속적인 메모리에 할당된다.

   

6.1.1. 1차원 배열의 선언

배열 선언 시 배열의 크기는 반드시 정수상수로 해야 한다.

ex) 데이터형 배열이름[크기];

   

6.1.2. 1차원 배열의 접근

배열은 같은 이름의 변수가 연속적인 메모리에 할당되어 있기 때문에 배열 이름에 인덱스 ([])를 이용하여 각각의 변수를 구별한다. 따라서 1차원 배열의 변수는 인덱스를 써서 구별해야 한다. 이 때 인덱스는 항상 0에서부터 시작하기 때문에 마지막 인덱스는 배열의 크기보다 항상 1이 작다.

   

6.1.3. 1차원 배열의 초기화

초기 값과 배열의 크기가 일치하면 배열의 크기를 생략할 수 있는데 배열의 크기를 생략하면 초기 값의 개수가 묵시적으로 배열의 크기가 된다. 또한, 배열의 크기보다 적은 개수의 초기 값을 할당하게 되면 나머지 배열의 값은 무조건 0으로 초기화 되며, 배열의 크기보다 많은 초기 값을 설정하면 에러가 발생한다.

[목차로]

   

   

7. 다차원 배열

   

7.1. 다차원 배열

2차원, 3차원 등의 배열을 다차원 배열이라 한다.

   

7.1.1. 2차원 배열의 선언

2차원 배열은 행과 열로 구성된 형태로, 첫 번째 크기는 행을 의미하며 두 번째 크기는 열을 의미한다. 행과 열은 논리적인 표현일 뿐, 실제 메모리는 1차원 배열과 같은 방식으로 할당된다.

ex) 데이터형 배열이름[크기1][크기2];

   

7.1.2. 2차원 배열의 접근

2차원 배열도 인덱스를 사용하는데 행과 열로 구성된 2차원 배열은 인덱스 두 개를 써서 각각의 변수를 구별해야 한다.

ex) int array[3][4]; [행→] ,[열↓];

   

1
int
array[0][0]
2
int
array[0][1]
3
int
array[0][2]
4
int
array[0][3]
5
int
array[1][0]
6
int
array[1][1]
7
int
array[1][2]
8
int
array[1][3]
9
int
array[2][0]
10
int
array[2][1]
11
int
array[2][2]
12
int
array[2][3]

   

7.1.3. 2차원 배열의 초기화

2차원 배열도 1차원 배열과 같이 중괄호 {}안에 차례대로 초기 값을 설정하는 방법과 행단위로 초기화 하는 방법이 있다.

[목차로]

   

   

8. 함수와 기억클래스

   

8.1. 함수

main함수 안에 모든 프로그램을 작성하면 전체 프로그램은 복잡해지고 이해하기가 어려워진다. 따라서 기능별로 분리된 단위 프로그램으로 나누어 정의함으로써 코드의 재사용이나 유지, 보수가 용이하게 된다. 또한 중복되는 작업을 함수로 정의하면 중복을 피할 수 있게 된다.

   

8.2. 사용자 정의 함수

필요에 따라 함수를 정의해서 쓸 수 있는 함수를 사용자 정의 함수라 한다.

   

8.2.1. 함수의 정의

ex)

   

리턴타입 함수명(데이터형 변수1, 데이터형 변수2, ... , 데이터형 변수n)

{

return 값;

}

- 리턴타입 : int, double, char, void, 등 리턴 시 돌려주는 값의 데이터형을 의미. 리턴 시 돌려주는 값이 없을 경우는 void를 쓰는데 리턴타입이 void인 경우 return은 생략 가능하다.

- 함수명 : 가급적이면 의미 있는 이름으로 정하는 것이 좋으며, 변수명의 규칙과 같다.

- 함수의 괄호 ( () ) : 호출부에서 전달한 값을 받을 변수를 선언한다. 전달하는 개수와 데이터형은 일치해야하며, 없으면 생략 가능하다.

- return : 호출한 곳으로 결과 값을 돌려주며, 함수를 강제 종료 시킨다. return 명령을 만나면 함수의 나머지 내용을 무시하고 함수를 호출한 곳으로 돌아간다.

   

8.2.2. 함수의 선언

함수의 선언은 컴파일 시 컴파일러에게 함수의 정보를 알려주는 역할을 하며, 이 정보를 이용하여 컴파일러는 함수사용에 관련된 오류를 검사하게 된다. 함수 선언은 함수호출 이전에 하며, 함수 정의 Header부분에 세미콜론(;)을 추가하면 된다. 함수정의부를 함수 호출 이전에 두면, 함수 선언을 생략할 수 있다.

   

8.2.3. 함수의 호출

함수는 함수명으로 호출한다. 이때 함수로 전달하려는 값이 있는 경우 함수의 괄호( () )안에 값을 전달하면 된다. 함수를 호출하면 제어 권은 호출한 함수로 넘어가고 함수의 실행이 완료되면 다시 호출한 곳으로 돌아와 다음 구문을 수행하게 된다. 함수선언을 하게되면 함수들 간의 순서에 영향을 미치지 않는다.

   

8.3. 기억클래스

변수는 데이터형과 기억클래스(storage class)를 갖는다. 데이터형은 변수의 크기와 어떤 타입의 데이터를 처리할 것인가를 결정하게 된다면 기억클래스는 변수가 사용되는 유효범위와 또한 초기화 방법을 결정하게 된다.

   

8.3.1. 지역변수와 전역변수

- 지역 변수 :

1) 함수 내에서 선언된 변수로 선언된 함수 내에서만 사용 할 수 있다.

2) 함수가 종료되면 메모리에서 소멸 된다.

3) 매개변수(인수)도 지역변수에 포함된다.

4) 초기화하지 않으면 쓰레기 값을 갖는다.

- 전역 변수 :

1) 함수 외부에서 선언된 변수로 모든 함수에서 사용할 수 있다.

2) 프로그램이 실행될 때 메모리가 한번 할당되며 프로그램이 종료되면 소멸한다.

3) 초기화하지 않으면 0으로 자동 초기화 된다.

   

8.3.2. 정적 변수

static을 붙여 선언된 변수를 말한다.

1) 선언된 함수 안에서만 사용할 수 있다. (지역변수 특징)

2) 프로그램 실행 시 메모리가 한번 할당되며 프로그램 종료시 소멸. (전역변수 특징)

[목차로]

   

   

9. 포인터의 이해

   

9.1. 포인터

포인터란 메모리의 주소를 저장하기 위한 변수를 말한다. 포인터가 변수기 때문에 포인터 변수라는 표현을 많이 사용한다.

   

9.1.1. &연산자

& 연산자를 이용하면 변수의 주소를 구할 수 있다.

   

9.1.2. 포인터 변수의 사용

포인터를 선언할 때는 * 연산자를 사용한다. 이때 포인터도 데이터형이 존재한다. 포인터의 데이터형은 주소를 저장하는 변수의 데이터형과 일치 돼야 한다. 포인터는 데이터형에 상관없이 모두 4byte다.

ex)

1) 데이터형 * 포인터명;

- 기능 : 데이터형이 일치하는 변수의 주소를 저장하는 포인터 변수 선언

- 사용 예 : int *ip; // int형의 주소를 저장할 수 있는 포인터 ip를 선언

2) 포인터명 = &변수;

- 기능 : 변수의 주소를 포인터변수에 저장한다.

- 사용 예 : ip = &i; // i의 주소를 포인터 변수 ip에 저장한다.

** 포인터가 변수의 주소를 저장하면 "포인터는 변수를 가리킨다."

   

9.1.3. * 연산자를 이용한 간접 접근

포인터 변수 앞에 * 연산자를 쓰면 포인터가 가리키는 곳의 값을 접근할 수 있다. 포인터를 이용한 메모리 접근 방식을 간접접근(Indirect Access)이라 하는데 간접접근을 위해 포인터에 데이터 형이 존재해야 한다.

※ * 연산자의 쓰임

   

연산자 용 도 형 식 사용 예
* 곱하기 변수 또는 상수 a * b;
x * 3;
   포인터
주소를 저장하는 변수
데이터형 *변수명 int *ip;
double *dp;
   간접 접근
포인터가 가리키는 값
*포인터명 *ip;
*dp;

   

9.2. 배열과 포인터

- 배열이름도 포인터다.

배열이름은 배열의 시작주소를 가리키는 포인터다. 즉, 배열이름은 배열의 첫 번째 주소를 말한다.

   

9.3. 포인터 연산

- 포인터는 연산 시 가리키는 데이터형의 크기만큼 증가 및 감소한다.

   

9.3.1. 배열의 시작주소를 저장한 포인터의 연산

- 포인터는 가리키는 데이터형의 크기만큼 증/감되기 때문에 배열의 시작주소를 저장한 포인터는 포인터 연산으로 배열에 접근할 수 있다.

   

9.4. 배열이름의 연산

배열이름도 포인터기 때문에 배열이름을 1씩 증가하면 배열의 증가되는 주소를 알 수 있다.

배열의 이름은 배열의 시작주소기 때문에 1씩 증가해서 다음 자료 주소에 접근 할 수 있으며, 그 주소를 간접접근하면 포인터가 가리키는 값에 접근할 수 있기 때문이다.

* C언어에서는 포인터가 가리키는 값에 접근(간접접근)시 * 연산자를 이용한다. 그러나 []연산자를 이용하는 것도 가능하다. 간접접근 시 * 연산자와 [] 연산자의 쓰임은 같다.

ex) int[3] = {1, 2, 3};

int *p = a;

   

변수 접근 방법 p[0] *p 또는 *(p+0) *a 또는 *(a+0) a[0] 1 &a[0] a 또는 a+0 p 또는 p+0 주소 접근 방법
   p[1] *(p+1) *(a+1) a[1] 2 &a[1] a+1 p+1   
   p[2] *(p+2) *(a+2) a[2] 3 &a[2] a+2 p+2   

   

9.4.1. 배열이름과 포인터의 차이점

배열이름은 상수 포인터기 때문에 배열의 시작주소 변경은 불가능 하다.

   

9.5. 포인터와 함수의 데이터전달 방법

데이터전달 방법에는 값에 의한 전달(call by value)과 주소에 의한 전달(call by address)이 있다

   

9.5.1. 값에 의한 전달(call by value)

전달한 변수의 복사본이 생성되어 복사본이 변경돼도 전달 변수에는 아무런 영향을 미치지 않는 방식이다.

   

9.5.2. 주소에 의한 전달(call by address)

전달한 변수의 주소를 포인터에 저장하는 방식으로 포인터는 간접접근으로 전달 변수를 변경할 수 있는 방식이다.

* 포인터는 여러 개의 값을 동시에 변경하는 경우 유용하게 사용된다.

[목차로]

   

   

10. 문자열

   

10.1. 문자 상수 / 문자열 상수

   

   문 자 문자열
형태 한 글자 두 글자 이상
표기방법 작은 따옴표 ('') 큰 따옴표 ("")
사용 예 'A', 't', '\n' "apple", "banana"
처리방법 정수로 처리된다. 주소로 처리된다.
특징 아스키코드와 대응된다. 문자열 끝에 널 문자('\0')가 추가된다.
때문에 문자열의 길이보다 항상 1이 길다.

* 문자열은 문자열상수가 저장된 시작주소로 처리 한다. 때문에 각기 다른 문자열 길이의 끝을 알 수 있도록 문자열 끝에는 문자열의 끝을 의미하는 널 문자('\0')가 들어있다. 때문에 문자열의 길이는 실제 문자열의 길이보다 항상 1byte가 길다.

* 문자열 변환문자는 %s다. 입력 시 %s는 주소가 가리키는 메모리로부터 차례대로 한 글자씩 저장한 후 끝에 널 문자('\0')를 추가한다. 출력 시 %는 주소로부터 널 문자 이전까지 출력된다.

   

10.2. 문자열 처리 방법

- 배열을 이용한 문자열 처리

: 문자열은 문자열의 끝을 의미하는 널 문자가 있기 때문에 항상 문자열의 길이 보다 1byte크게 배열의 크기를 설정해야 한다. 또한, 한글은 1음절이 2byte기 때문에 음절의 두 배 + 1에 goekdd하는 크기로 설정해야 한다.

- 포인터를 이용한 문자열 처리

: 문자열은 문자열이 저장된 곳의 시작주소로 처리되기 때문에 char형 포인터는 문자열을 저장할 수 있다. 이 경우 포인터는 문자열의 주소를 저장하고 있는 것이다.

포인터에 문자열을 저장하면 문자열의 길이에 상관없이 문자열의 주소를 저장하는 4byte 포인터만 있으면 되기 때문에 메모리를 효율적으로 사용할 수 있다. 그러나 문자열의 수정은 불가능한 읽기 전용이 된다.

   

10.3. 문자열 입력함수

문자열을 입력받기 위해서는 반드시 메모리 공간이 할당 돼야 한다. 즉, 할당된 메모리의 크기만큼 문자열을 입력받을 수 있다. 배열에는 문자열을 입력받을 수 있지만 주소를 저장하는 4byte포인터에는 문자열을 입력받을 수 없다.

   

10.4. 문자열 함수

문자열 함수는 string.h에 정의되어 있으므로 문자열 함수를 사용하려면 이 헤더파일을 추가해야한다.

- strlen 함수 : 문자열의 주소로부터 널 문자 이전의 길이를 구해 리턴 하는 함수

- strcpy 함수 : 문자열을 복사하는 함수로 주소부터 널 문자까지 복사

- strcat 함수 : 첫 번째 문자열과 두 번째 문자열이 연결되어 첫 번째 문자열에 저장

- strcmp 함수 : 두 문자열이 완벽하게 일치하면0을, 앞 문자열이 크면 양수를(보통 1)를, 뒤 문자열이 크면 음수(보통 -1)을 리턴 하는 함수

- strrev 함수 : 널 문자 이전의 문자열을 역순으로 저장하는 함수

- strupr, strlwr 함수 : 소문자를 대문자로, 대문자를 소문자로 변환하는 함수

- strchr 함수 : 문자열에서 문자를 앞에서부터 검사하여 문자가 저장된 번지를 리턴 하는 함수

   

10.5. 데이터 변환 함수

데이터 변환 함수는 stdlib.h에 정의되어 있으므로 데이터 변환 함수를 사용하려면 이 헤더파일을 추가해야한다.

- atoi(Ascii to Integer) 함수 : 숫자 형태의 문자열을 정수로 변환하는 함수

- atof 함수 : 문자열을 부동 소수점으로 변환

- atol 함수 : 문자열을 long형 정수로 변환

- itoa(Integer to Ascii) 함수 : 정수를 문자열로 변환하는 함수

- ultoa 함수 : 부호 없는 정수를 문자열로 변환

[목차로]

   

   

11. 전처리기

   

11.1. 전처리기란,

전처리기(preprocessor)란 컴파일에 앞서 미리 처리되는 처리기를 의미. 원시프로그램은 컴파일과 링크의 단계를 거쳐 실행 파일을 생성하는데, 컴파일 단계를 좀 더 세분화 한다면 전처리 단계와 컴파일 단계로 나눌 수 있다.

이때 전처리기 단계는 전처리기(preprocessor)에 의해 처리되고, 컴파일단계는 컴파일러(compiler)에 의해 처리되고, 링크는 링커(linker)에 의해서 처리된다.

   

* 반드시 해시 표시(#)으로 시작해야 한다.

* 명령문의 끝은 세미콜론(;)을 붙이지 않는다.

* 한 줄에 하나의 명령만 쓴다.

* 일반적으로 대문자를 기초로 작성된다.

   

11.2. 매크로 정의

매크로(macro)는 매크로명을 명령이나 수식 또는 상수로 치환한다. #define은 매크로를 정의함.

   

11.2.1. 매크로 상수

ex) define 매크로명 상수

- 기능 : 매크로명을 상수로 치환

- 사용 예 : #define PI 3.141592

   

11.2.2. 매크로 함수

매크로 함수는 데이터형에 독립적이며(어떤 데이터형이 전달되어도 상관없음), 함수 호출 시 발생하는 오버헤드가 발생하지 않아 실행속도가 향상된다. 그러나 함수 호출부가 매크로 함수 몸체 부분으로 완전히 치환되기 때문에 코드의 크기는 커질 수밖에 없다. 따라서 매크로 함수는 함수의 크기가 작은 경우에만 사용하는 것이 좋다.

ex) define 매크로명(인수) 수식

- 기능 : 매크로명을 수식으로 치환한다.

- 사용 예 : #define SUM(a, b) a+b

※ 함수의 호출 과정

   

1. 인수를 전달하기 위해 메모리에 저장한다.

2. 호출하는 함수의 다음 명령의 주소를 저장해서 리턴 할 수 있게 한다.

3. 함수가 정의되어 있는 주소로 점프한다.

4. 함수의 지역변수 메모리에 할당한다.

5. 함수를 수행한다.

6. 리턴 값을 저장한다.

7. 저장한 주소로 리턴 한다.

[목차로]

   

   

12. 구조체

   

12.1. 구조체란,

구조체란 두 개 이상의 데이터형을 묶어서 새로운 데이터형을 정의하는 것을 말한다. 각각의 컬럼들은 독립된 의미를 갖는데 이를 모아 하나의 가치를 지니는 정보로 만드는 것이다. 즉, 각 항목을 서로 다른 변수에 저장하는 것이 아니라 필요한 정보를 그룹지어 하나의 변수에 저장할 수 있도록 데이터형을 정의하는 것이다.

   

12.2. 구조체 사용

   

1. 구조체 정의
struct 구조체명
{
멤버 1;
멤버 2;
멤버 n;
};
2. 구조체 선언
struct 구조체명 변수명;
3. 구조체 멤버 접근
변수명.멤버;
4. 구조체 초기화
struct 구조체명 구조체변수명 = {값1, 값2, 값3};
1) 구조체로 정의한 데이터형은 struct 키워드가 붙는다.
2) 구조체 정의 끝은 항상 세미콜론(;)으로 끝난다.
3) 구조체 정의 시 멤버변수 초기 값을 할당은 불가능하다.
구조체 멤버 초기화 방법은 배열과 같다

   

12.3. typedef

데이터형을 새롭게 정의하는 명령. typedef를 하면 원래 데이터형과 새롭게 정의한 데이터형을 모두 사용할 수 있다. 데이터형의 이름을 명시적으로 쓰고 싶은 경우나 구조체와 같이 데이터형의 이름이 긴 경우 사용한다.

ex) typedef 데이터형 재정의데이터형

- 기능 : 데이터형의 이름을 새롭게 정의한다.

- 사용 예 : typedef struct student student; (구조체 student를 student로 명시한다)

   

12.4. 구조체 배열

구조체도 데이터형이기 때문에 배열을 선언할 수 있다.

ex)

   

s[0].no s[1].no s[2].no
s[0].name s[1].name s[2].name
s[0].score s[1].score s[2].score
s[0] s[1] s[2]

   

12.5. 구조체 포인터

구조체 포인터란 구조체의 주소를 저장하는 포인터다. 구조체 포인터로 구조체 멤버를 접근할 때는 간접 멤버 접근 연산자( -> )를 이용한다.

1) 구조체 포인터 선언

struct 구조체명 *포인터명;

- 사용 예 : struct person *pP;

2) 구조체 포인터로 멤버 접근

포인터 -> 멤버;

- 사용 예 : pt -> name

ex) score st; score *p; p = &st;

st.sum = st.kor + st.eng + st.mat;

p->sum = p->kor + p->eng + p->mat;

(*p).sum = (*p).kor + (*p).eng + (*p).mat; 3가지 경우는 같은 표현이다.

   

12.6. 구조체 연산

구조체 변수도 제한된 연산이 허용되는데 가장 대표적인 연산이 대입 연산이다. 구조체 대입연산은 멤버 대 멤버 복사가 수행된다.

   

12.7. 구조체와 함수

구조체 변수도 Call by value방식과 Call by address방식으로 전달한다. Call by value방식으로 전달하는 경우는 멤버 대 멤버 복사가 수행되며, Call by address방식으로 전달하는 경우는 구조체 변수의 주소를 포인터가 저장한다.

[목차로]

   

   

13. 포인터 고급

   

13.1. 포인터 배열

포인터 배열이란 이름 그대로 포인터들의 배열을 말하는 것으로 같은 타입의 포인터가 여러 개 필요한 경우 포인터를 배열로 선언한다.

ex) char *ch1, *ch2, *ch3; -> char *ch[3];

   

13.2. 더블 포인터(double pointer)

싱글포인터(포인터)는 변수의 주소를 저장하기 위한 포인터라면 더블 포인터는 싱글포인터의 주소를 저장하는 포인터이다.

ex) 데이터형 **포인터명;

- 포인터의 주소를 저장하기 위한 포인터다.

- 사용 예 : int **p;

   

13.3. 2차원 배열과 포인터

1. 배열이름은 배열의 시작주소를 가리키는 포인터다.

2. 배열이름[행]은 행의 시작주소다.

3. 배열이름 증 / 감 연산 시 행 단위로 이동한다.

   

13.3.1. 2차원 배열이름의 포인터 타입

1차원 배열이름은 배열이름 연산 시 증 / 감 되는 바이트가 항상 같기 때문에 데이터형이 같은 경우 포인터 타입도 일치한다. 2차원 배열이름은 포인터 연산 시 증 / 감 되는 바이트가 일치하지 않기 때문에 포인터 타입이 달라진다.

[목차로]

   

   

14. 파일 입, 출력

   

14.1. 파일 입, 출력의 개념

표준 입, 출력 함수는 모니터와 키보드로 입, 출력을 수행하지만 파일 처리 함수는 보조기억장치 파일(file)에 데이터를 입, 출력 한다. 파일 입, 출력은 텍스트 모드와 2진 모드로 구분된다. 텍스트 모드는 프로그램에서 파일로 읽어 들이거나 쓰는 경우에 데이터 변환이 일어나는 입, 출력 모드를 의미하며, 2진 모드는 아무 변환 없이 데이터를 입, 출력 모드를 의미한다. 일반적으로 문자열과 같은 텍스트 기반의 데이터는 텍스트 모드로 입, 출력하며, 영상 데이터와 같이 데이터의 변환이 발생하면 안 되는 경우에는 2진 모드로 데이터를 입, 출력한다.

   

14.2. 파일 입, 출력의 수행 과정

1. 파일을 개방한다.

2. 입, 출력을 수행한다.

3. 파일을 닫는다.

○ file 구조체 : file은 내부적으로 정의 된 구조체로 파일에 대한 여러 가지 정보를 저장한다.

파일 입, 출력 함수들은 file 구조체의 정보를 참조하여 동작하도록 되어있다.

○ fopen 함수 : fopen 함수는 파일을 개방하는 함수로 파일의 정보를 저장하는 FILE 구조체 변수를 내부적으로 생성한 후 그 주소를 리턴한다.

ex) FILE* fopen(const char *filename, const char *mode);

○ 파일 입출력 함수를 이용하여 입, 출력 수행한다.

○ fclose 함수 : fclose 함수는 개방한 파일을 닫는 함수로 버퍼에 남아있는 데이터를 파일로 완전히 출력하고 파일 입, 출력을 위해 내부적으로 생성했던 FILE 구조체를 해제한다.

ex) fclose(FILE *);

   

14.3. 파일 모드

텍스트 모드는 파일모드 뒤에 't'를 쓰며, 2진 모드는 'b'를 쓴다.

   

모드 의미
r (읽기전용) 파일을 읽기전용으로 개방한다.
파일이 존재하지 않으면 NULL을 리턴 한다.
w (쓰기전용) 파일을 쓰기전용으로 개방한다.
파일이 존재하는 경우 기존의 데이터를 삭제한 후 데이터를 기록한다.
만약 파일이 존재하지 않으면 파일을 생성한 후 데이터를 기록한다.
a (추가전용) 파일을 쓰기전용으로 개방한다.
지정한 파일이 존재하면 기존 데이터의 끝에서부터 데이터를 추가한다.
만약 파일이 존재하지 않으면 파일을 생성한 후 데이터를 기록한다.
r+ (갱신용) 파일을 읽고 쓰기위해 개방한다.
파일이 존재하지 않으면 NULL을 리턴 한다. 파일이 존재하는 경우 기존 데이터를 삭제한 후 데이터를 기록한다.
w+ (갱신용) 파일을 읽고 쓰기위해 개방한다.
파일이 존재하는 경우 기존의 데이터를 삭제한 후 데이터를 기록한다.
만약 파일이 존재하지 않으면 파일을 생성한 후 데이터를 기록한다.
a+ (갱신용) 파일을 읽고 쓰기위해 개방한다.
지정한 파일이 존재하면 기존 데이터의 끝에서부터 데이터를 추가한다.
만약 파일이 존재하지 않으면 파일을 생성한 후 데이터를 기록한다.

   

14.4. 파일 입, 출력 함수

1. fputc 함수 : 스트림에 한 문자를 출력하는 함수. 출력한 문자를 리턴하며 에러가 발생할 경우 EOF(-1)을 리턴한다.

ex) int fputc(int c, FILE *stream);

2. fget 함수 : 스트림에서 한 문자를 읽어오는 함수. 입력된 문자를 리턴 하지만 파일의 끝을 만났을 경우 EOF(-1)를 가질 수도 있기 때문에 정수형 변수에 대입해야 한다.

ex) int fgetc(FILE *stream);

3. fputs 함수 : 스트림에 문자열을 출력하는 함수로 개행문자('\n')가 있더라도 한꺼번에 출력된다. 널 문자이전까지 출력되므로 문자열은 반드시 널문자로 끝나야한다.

ex) int fputs(const char *string, FILE *stream);

4. fgets 함수 : 스트림에서 문자열을 읽어와 char형 배열에 저장하는 함수. 개행문자를 만날 때 까지 문자열을 읽어 들이거나 두 번째 인수의 길이만큼 읽어 들인다. 즉, 개행문자를 만나면 읽기를 중단하기 EOans에 행 단위로 읽어 들일 경우 많이 이용된다.

ex) int fgets(char *string, int n, FILE *stream);

5. fprintf 함수 : 스트림에 서식 화 된 데이터를 출력하기 위해 사용되는 함수. 사용방법은 FILE의 포인터를 첫 번째 인수로 넘긴다는 것을 제외하고 같다.

ex) int fprintf(FILE *stream, const char *format [,argument ]...);

6. fscanf 함수 : 스트림에서 서식화된 데이터를 읽어오기 위해 사용되는 함수. 사용방법은 FILE의 포인터를 첫 번째 인수로 넘긴다는 것을 제외하고는 scanf와 같다.

ex) int fputc(int c, FILE *stream);

7. fcloseall 함수 : 열려 있는 모든 스트림을 닫는 함수.

ex) int fcloseall();

[목차로]

   

   

15. 메모리 동적 할당

   

15.1. 메모리

프로그램이 실행되는 동안 저장되는 데이터는 RAM이라는 메모리 공간에 저장되며 RAM은 크게 다음과 같이 나눠진다.

   

메모리 영역 저장되는 데이터
Stack 함수 내에서 선언된 지역 변수(매개변수)
Heap 동적으로 할당된 메모리
Data 전역변수나 정적변수(static 변수)

   

   RAM   
High Address Stack
Heap
함수나 블록내에서만 메모리 할당
(지역변수, 매개변수)
프로그래머 할당/해제
Low Address Data 프로그램 실행~종료될 때까지 메모리 할당
(전역변수, 정적변수(static변수))

여기서 Stack영역과 Heap영역은 정형화된 영역이 아니다. 즉, Stack영역이 많이 할당되면 Heap영역은 줄어들게 되며, Heap영역이 많이 할당되면 Stack영역은 줄어들게 되는 가변화된 공간이다.

Stack 영역과 Data영역은 시스템에 의해 할당되고 해제는 되는 영역이지만, Heap영역은 프로그래머에 의해 할당 및 해제가 이뤄지는 영역이다.

   

15.2. 정적 할당과 동적 할당

1. 정적 할당

1) Compile시 할당될 메모리 크기가 결정되어야 한다.

2) Stack영역과 Data영역에 할당되는 메모리는 모두 정적 할당이다.

2. 동적 할당

1) Runtime(실행)wnddp 메모리가 할당되어야 한다.

2) 동적 할당된 메모리는 Heap영역에 할당된다. 때문에 Heap메모리를 동적 메모리라 함.

* 전역변수, 지역변수, 정적변수는 컴파일 시 할당될 메모리 크기를 결정할 수 있는 정적 할당

   

15.2.1. malloc 함수 / free 함수

동적으로 메모리를 할당하기 위해 malloc 함수를 해제하기 위해서는 free함수를 이용.

- 동적 메모리 할당

ex) void* malloc(size_t n);

: 인수의 크기만큼 메모리를 할당하고 할당된 메모리의 시작주소를 리턴.

: 리턴되는 주소는 void포인터 타입이기에 반드시 형 변환해서 사용해야 함.

- 동적 메모리 해제

ex) void free(void*)

: 주소가 가리키는 메모리를 해제한다.

- 헤더파일 : stdlib.h

: malloc함수와 free함수는 stdlib.h 헤더파일에 포함되어 있다.

** void 포인터(void*)는 모든 타입의 주소를 저장할 수 있는 포인터를 의미. void포인터는 간접접근을 할 수 없기 때문에 형 변환해서 주소가 가리키는 데이터로 접근해야 함.

문자열 동적 할당은 문자열의 길이가 일정치 않은 데이터를 여러 개 저장할 때 사용한다. 문자열 동적 할당은 메모리를 동적 할당 한 후 할당된 주소를 포인터가 저장해야 하기 때문에 성능도 떨어지고 메모리를 잘못 할당할 수 있는 위험성도 있다. 그러나 일정치 않은 길이의 많은 데이터를 처리할 때 메모리를 효율적으로 사용할 수 있다는 장점이 있다.

[목차로]

'IT > note' 카테고리의 다른 글

정보보안기사 핵심 정리  (0) 2021.12.31
정보보안기사 핵심 용어 모음  (0) 2021.12.31
보유 자격증과 22년 목표  (0) 2021.12.26
MCU / ALU / Register 용어 설명  (0) 2021.12.22
시스템 분석과 설계 문서 정의  (0) 2021.12.22

댓글