동적 메모리 할당의 개념

- 일반적으로 C언어에서 배열의 경우 사전에 적절한 크기만큼 할당해주어야한다.

- 우리가 원하는 만큼만 메모리를 할당해서 사용하고자 한다면 동적 메모리 할당을 사용한다.

- 동적이라는 말의 의미는 '프로그램 실행 도중에'라는 뜻이다.


동적 메모리 할당 함수

- C언어에서는 malloc() 함수를 이용해 원하는 만큼의 메모리 공간을 확보할 수 있다.

- malloc() 함수는 메모리 할당에 성공하면 주소를 반환하고, 그렇지않으면 null을 반환한다.

- malloc() 함수는 <stdlib.h> 라이브러이에 정의되어 있다.

- 사용법 : malloc(할당할 바이트 크기);


실습내용

실습결과



동적 메모리 할당을 수행할 때마다 할당되는 포인터의 주소값은 변칙적이다.


동적으로 할당된 변수는 <힙 영역>에 저장된다.

지역변수,매개변수는 <스택 영역>에 저장된다.


전통적인 C언어에서는 스택에 선언된 변수는 따로 메모리 해제를 해주지않아도 된다.

반면에 동적으로 할당된 변수(힙영역)는 반드시 free() 함수로 메모리 해제를 해주어야한다.

메모리 해제를 하지 않으면 메모리 내의 프로세스 무게가 더해져 언제가는 오류가 발생한다.

메모리 누수(Memory Leak) 방지는 코어 개발자의 핵심 역량이다.


실습내용

실습결과



동적으로 문자열 처리하기

- 일괄적인 범위의 메모리를 모두 특정한 값으로 설정하기 위해서는 memset()을 사용한다.

- 사용법 : memset(포인터,값,크기); 

- 한 바이트 씩 값을 저장하므로 문자열 배열의 처리 방식과 흡사하다.

- 따라서 memset() 함수는 <string.h> 라이브러리에 선언되어 있다.


실습내용

실급결과



동적 메모리 할당을 이용해 프로그램이 실행중인 도중에 메모리 공간을 배정받을 수 있다.

동적으로 할당 받은 프로그램은 반드시 명시적으로 free() 함수를 이용해 할당 해제를 해야만한다.

2차원 배열의 필요성

- 2차원 배열은 굉장히 많은 목적으로 사용된다.

- 행렬 데이터를 표현할 때, 그래프 알고리즘을 처리할 때, 다수의 실생활 데이터를 처리할 때 등이다.

- 흔히 우리가 보는 표 구조가 2차원 배열과 흡사하다(ex:수학,영어,국어성적)

+ 호날두 85 97 79

+ 메시 88 54 56


2차원 배열의 초기화

- 2차원 배열은 1차원 배열 중첩되었다는 의미로 []를 두 번 연속하여 사용한다.

+ 자료형 배열이름 [행][열] = { {값,값},{값,값} }

실습내용

실습결과


다차원 배열

- 2차원 배열 이상의 다차원 배열 또한 사용할 수 있다.

- 컴퓨터는 기본적으로 화면에 2차원 형태만 출력할 수 있다.

실습내용



실습결과


포인터 배열의 구조분석

- 배열은 포인터와 동일한 방식으로 동작한다.

- 배열의 이름은 배열의 원소의 첫 번째 주소가 된다.

- 유일한 차이점은 포인터는 변수,배열의 이름은 상수이다.

- 포인터는 연산을 통해 자료형의 크기만큼 이동한다.

- 정수(int)형 포인터는 4바이트(Bytes)씩 이동한다.


포인터배열 구조 예제

- 포인터는 벼수여서 값이 변경된다.

실습내용

실습결과


2차원 배열 포인터 처리방법

실습내용

실습결과




프로그램 메모리 주소

- 컴퓨터에서 프로그램이 실행되기 위해서는 프로그램이 메모리에 적재되어야한다.

- 당연히 프로그램의 크기를 충당할 수 있을 만큼의 메모리 공간이 있어야한다.


- 일반적인 컴퓨터의 운영체제는 메모리 공간을 네 가지로 구분하여 관리한다.

+ 코드영역 - 소스코드

+ 데이터영역 - 전역변수,정적변수

+ 힙영역 - 동적할당변수

+ 스택영역 - 지역변수,매개변수


전역변수

- 전역변수(Global Variable)란 프로그램의 어디서든 접근 가능한 변수를 말한다.

- main함수가 실행되기도 전에 프로그램의 시작과 동시에 메모리에 할당된다.

- 프로그램의 크기가 커질 수록 전역 변수로 인해 프로그램이 복잡해질 수 있다.

- 메모리의 데이터영역에 저장된다.

실습내용

실습결과



지역변수

- 프로그램의 특정한 블록에서만 접근가능하다.

- 함수가 실행될때마다 메모리에 할당되어 함수가 종료되면 메모리에서 해제된다.

- 메모리의 스택(Stack)영역에 기록된다.

실습내용

실습결과



정적변수

- 정적변수(Static Variable)는 특정한 블록에서만 접근할 수 있는 변수이다.

- 프로그램이 실행될 때 메모리에 할당되어 프로그램이 종료되면 메모리에서 해제된다.

- 메모리의 데이터 영역에 적재된다.

실습내용

실습결과



레지스터변수

- 레지스터변수(RegisterVariable)은 메인 메모리 대신 CPU의 레지스터를 사용하는 변수이다.

- 레지스터는 매우 한정되어 있으므로 실제로 레지스터에서 처리될 지는 장담할 수 없다.

실습내용

실습결과



함수의 매개변수가 처리될 때

- 함수를 호출할 때 함수에 필요한 데이터를 매개변수로 전달한다.

- 전달 방식은 1: 값에 의한 전달 방식, 2 : 참조에 의한 전달 방식이 있다.

- 값에 의한 전달 방식은 단지 값을 전달하므로 함수 내에서 변수가 새롭게 생성된다.

+ 지역변수에 가깝다.

- 참조에 의한 전달 방식은 주소를 전달하므로 원래의 변수 자체에 접근할 수 있다.

+ 전역변수에 가깝다.

+ 매개변수로 포인터 변수를 보내는것이다.


실습내용

실습결과


문자

- C프로그램의 문자는 아스키 코드를 따른다.


- 아스키 코드는 0~127중의 1바이트로 구성되며 주요 문자를 출력하도록 해준다.

+ 0 = 48, A = 65, a = 97


- 컴퓨터는 내부적으론 다 숫자로 처리한다.


버퍼

- 문자열을 처리할 때 버퍼의 개념이 많이 사용된다.


- 버퍼(buffer)란 임시적으로 특정한 데이터를 저장하기 위한 목적으로 사용한다.


- C 프로그램은 기본적으로 사용자가 의도하지 않아도 자동으로 버퍼를 

  이용해 입출력을 처리한다.


  - scanf로 5를 입력하게되면 버퍼에 5를 입력할때 입력된 엔터도 저장되게된다.

    while((temp = getchat()) != EOF && temp != '\n') {} 구문으로 엔터를 제거해준다.

실습내용


실습결과




문자열

- 문자열은 말 그대로 문자들의 배열이다


- 문자열은 컴퓨터 메모리 구조상에서 마지막에 널(NULL) 값을 포함한다.

+끝을 알기위해 NULL(\0) 한자리가 추가된다.




문자열과 포인터

- 문자열 형태로 포인터를 사용하면 포인터에 특정한 문자열의 주소를 넣게된다.


- 예를들어 char *a = "Hello World"라는 문자열이 입력되면 읽기 전용으로 

  메모리 공간에 넣고 그 위치를 처리한다.


- 위에 방식을 "문자열 리터럴"이라고 한다.


- 문자열리터럴방식은 컴파일러가 알아서 메모리 주소를 결정한다.


  - gets()함수를 이용하게 문자배열의 길이를 제한할 수 없다.

    gets_s()함수를 사용하여 문자배열 크기만큼 입력받고 넘을경우 런타임 오류를 낸다.

실습내용

실습결과


문자열함수

- strlen()은 문자열의 길이를 반환한다.


- strcmp()는 문자열1이 문자열2보다 사전적으로 앞에 있으면 -1, 뒤에 있으면 1을 반환한다.


- strcpy()는 문자열을 복사한다.

  기본적으로 C언어에선 a = b같은 방법으로 복사가 안된다.


- strcat()는 뒤에 있는 문자열을 앞에 있는 문자열에 합친다.


- strstr()은 긴 문자열에서 짧은 문자열을 찾아 그위치를 반환한다.

  짧은 문자열을 찾은 주소 값 자체를 반환하므로 단순히 출력하면

  찾은 이후 모든 문자열이 반환된다.

실습내용

실습결과


포인터의 개념

- 변수는 그 자체로 자신의 자료형에 맞는 값을 저장한다.


- 포인터(Pointer) 변수는 특이한 변수로, 메모리 주소를 저장한다.


- 포인터는 특정한 변수 자체가 존재하는 메모리 주소값을 가진다.

+ int a = 5; 의 주소값 : 0xAFB03954

  int *b = &a; 의 값 : a의 메모리 주소 0xAFB03954

  int *b 도 변수이기때문에 주소값을 가진다.


- int *b = &a;에서 *(포인터 변수 선언)은 포인터 변수임을 알려주기 위한 목적이다.

  &는 변수 앞에 붙어서 변수의 메모리 시작 주소값을 구한다.

- 따라서 위에 *b는 5라는 값 자체가 된다. 


- *(간접참조연산자) : 현재 포인터가 가르키고있는 주소에 들어있는 값을 참조한다.


 실습내용

실습결과


- 실제로 int a = 5; 와 같이 변수를 할당하면 메모리 주소상에서는 4Byte를 차지한다.

+ 메모리주소를 한칸에 1Byte씩 표현한다면 4칸을 차지한다.


실습내용 : 배열 각 원소의 주소 값 출력하기

십습결과 : 주소값이 4씩 증가하는것을 확인할 수 있다.




포인터의 강력한 기능

- 포인터는 컴퓨터 시스템의 특정한 메모리에 바로 접근할 수 있다.


- 기존에 존재하던 중요한 메모리 영역에 접근하지 않도록 해야한다.

+ int *a = 0x1234123;

  *a = 0;

  이렇게 구현한다면 메모리 0x1234123가 무슨 일을하는지 모르기에 위험하다.


다중포인터

- 포인터의 포인터도 존재할 수 있다.


- 포인터도 메모리에 기록되는변수이다. 


- 포인터를 여러개 겹칠 수 있다.


실습내용

실습결과



배열과 포인터관계

- 배열과 포인터는 사실 동일하다.


- 배열을 선언한 이후에는 그 이름 자체를 포인터 변수처럼 쓸 수 있다.


포인터(핵심)

- 포인터는 특정한 변수가 메모리 상에 존재하는 위치 주소를 저장한다.


- 포인터는 특정한 메모리 주소에 바로 접근할 수 있으므로 조심스럽게 사용해야한다.



함수

- 함수는 입력을 받아 처리한 뒤에 출력하는 구조를 가진다.

+ 입력 -> 함수(값처리) -> 출력

- 함수는 특정한 기능에 대한 소스코드가 반복되는 것을 감소하게해준다.

- 함수를 만들어 묶어놓은것을 라이브러리라고 한다.(패키지형태)


- 함수의 형태는 다음과 같다.

+ 매개변수,return 값은 없을 수 있다.(void)

반환자료형 함수명(매개변수){

return 반활할 값;

}


실습내용 - mian함수에서 add 함수를 이용하여 출력하기

실습결과



재귀함수

- 재귀함수란 자기 자신을 포함하는 함수

- 기본적으로 자기 자신을 계속불러낸다.

- 따라서 반드시 재귀 종료 조건이 필요하다.


실습내용 - 숫자 입력시 자기 자신을 1이 될때까지 자기자신을 호출한다.



실습결과

아래 결과에서 보면 factorial 함수가 자기 자신을 계속 호출하는 것을 볼수 있다.

따라서 5 * 4 * 3 * 2 * 1이 실행된다.


함수정리

- C언어는 함수로 시작해서 함수로 끝난다.

- 재귀함수는 반복적으로 자기 자신을 불러내므로 

  경우에따라 무한루프가 일어날 수 있어 조심해야한다..

배열

- 변수가 여러개 필요할때 사용하기 유용하다.

- 배열을 사용안할시 int a,int b,int c...형식으로 해야한다.

- 간단하게 동일한 자료형을 여러개 담을수 있는것을 배열이라고 한다.

- 배열은 인덱스,데이터 조합이다.

+ 인덱스는 0부터 시작하고, 데이터는 입력된 값이다.

- 배열 선언 방법

+ 자료형 배열명[배열의 크기] = {초기화 값};

- INT_MIN은 #include <limits.h>로 사용한다.

- INT_MIN은 최대값을 구하기위해 자주 사용하는 상수이다(int형 최솟값 반환).

- 반대로 INT_MAX도 있다.


문자열과 배열

- 원시적인 C언어는 기본적으로 자체적인 문자열 자료형을 제공하지 않는다.

- C언어는 문자(char)를 여러 개 묶어 놓는 형태로 문자열을 표현한다.

+ char a[20] = "TEST";


실습내용

실습결과


조건문

- 조건의 개수가 적을때 if문, 많을때는 switch문을 사용한다. 


if문

- if문 내부의 조건을 검사해 프로그램의 진행 결로를 결정한다.

- if문은 조건의 개수가 많지 않을때 사용하는것이 유리하다.


if (조건1) {

//조건 1에 부합할 때

}else if (조건2) {

//조건 1에 부합하지 않고 조건2에 부합할 때

}else{

//위 조건들에 모두 부합하지 않을때

}


실습 내용


실습 결과


Switch문

- 다양한 조건이 존재할 때 사용하면 소스코드를 짧게 유지할 수 있다.

- 조건을 정확히 판별할때 유용하게 사용가능하다.

- swtich문은 조건에 부합하는 경우 아래쪽의 case도 모두 만족시킨다.

- 따라서 일반적인 경우case문의 마지막에 break를 넣어 특정부분만 실행시키도록한다.


switch (확인 대상) {

case 값1:

//값 1에 부합할 때

break;

case 값2:

//값 2에 부합할 때

break;

Default:

//모든경우

}


실습 내용


실습결과




반복문


for문

- for문 내부의 조건에 부합하면 계속해서 실행한다.

- 반복문을 탈출하고자 하는 위치에 break 구문을 삽입한다.

주의할점

- 무한루프

+ 무한루프란 종료 조건 없이 무한반복되는 것을 말한다.

+ 일부러 무한루프를 만드는 경우는 거의 없고 개발자의 실수로 인해 발생한다.


for( 초기화; 조건; 반복 끝 명령어) {

//반복적으로 실행할 부분

}


실습 내용

실습 결과



while문

- while문의 조건에 부합하면 계속해서 반복한다.

- 반복문을 탈출하고자 하는 위치에 break 구문을 삽입한다.

while (조건) {

//반복적으로 실행할 부분

}


실습 내용


실습 결과


중첩된 반복문(2중for문)

- 중첩된 반복문이란 반복문 내부에 다른 반복문이 존재하는 형태의 반복문을 말한다.

- 반복문이 중첩될수록 연산 횟수는 제곱형태로 늘어난다.


실습내용


실습결과


for문과 while문의 관계

- 모든 for문은 while문으로 변경할 수 있으며 모든 while문은 for문으로 변경할 수 있다.

- C언어 소스코드가 최적화 되면서 어셈블리어 단에서는 동일한 명령어로 동작한다.

연산자

연산자와 피연산자

- 연산자(Operator)란 연산을 수행하는 기호를 의미한다.

- 피연산자(Operator)란 연산에 포함되는 변수나 상수를 의미한다.

- A + B에서 A와 B는 피연산자에 해당하며 +는 연산자에 해당한다.


C언어에서 사용하는 연산자

대입연산자 : =

- '=' 등호를 이용하여 우변항을 좌변항에 넣을 수 있다.

- 자료형에 부합하는 값을 좌변항에 있는 변수에 넣는다.


산술연산자 : +, -, *, /, %

- 기본적인 사칙연산 사용가능하다

- 나머지를 구하기 위해 모듈러연산(%)을 사용한다.

실습 내용


실습결과



관계연산자 : ==, !=, >, <, >=, <=

논리연산자 : !, &&, ||

증감연산자 : ++, --

삼항연산자 : ?:

비트연산자 : !, ~, &, ^, >>, <<


이스케이프 시퀀스(Escape Sequence)

- \n : 줄 바꾸기

- \t : 수평 탭 넣기

- WW : 백슬래시 넣기

- \" : 큰 따옴표 넣기

- \b : 백 스페이스 넣기

실습내용


실습결과



증감연산자

- ++(변수) : i의 값을 1 증가시킨 후에 증가된 값을 반환한다.

- (변수)++ : i의 값을 1 증가시킨 후에 증가되기 전의 값을 반환한다.

- --(변수) : i의 값을 1 감소시킨 후에 감소된 값을 반환한다.

- (변수)-- : i의 값을 1 감소시킨 후에 감소되기 전의 값을 반환한다.

실습내용


실습결과


기본 입출력

scnaf()

- scanf()를 이용할 때 &를 이용하는 이유는?

- &는 특정한 변수의 주소를 의미한다.

- 실제로 컴퓨터는 특정한 메모리 주소에 접근하여 데이터를 수정하므로

  &를 이용하는 것이다.

- 그렇다면 메모리 주소에 얼마만큼의 크기로 데이터를 쓸 지 결정해야한다.


형식 지정자

- int(4Byte) : 정수형 데이터를 입력 및 출력할때 %d 사용


- long long(8Byte) : 큰 정수형 데이터를 입력 및 출력할때 %lld 사용


- double(8Byte) : 큰 실수형 데이터를 입력할때 %lf, 출력할때 %f 사용

+ 입력과 출력이 다른이유

입력을 받을 땐 특정 주소에 특정한 크기만큼 입력하겠다고 정확하게 명시

출력할땐 주소가 아닌 그값자체를 출력하기 때문에

정확한 크기를 정해주지 않아도 되기 때문이다.

- float(4Byte) : 실수형 데이터를 입력 및 출력할때 %f 사용


- string(제한 없음) : 문자열데이터를 입력 및 출력할때 %s 사용


- char(1Byte) : 문자데이터를 입력 및 출력할때 %c 사용


- %를 출력하고 싶으면 "%%"로 사용한다.


실습 내용

- scanf 사용위해 #define _CRT_SECURE_NO_WARNINGS 사용(화면상단)

- int,double(소수자리설정),int(한자리씩쪼개기) 테스트


실습결과



정리

- C언어에서 입력 받거나 출력할 때는 형식 지정자를 적절히 따라야한다.

- printf()는 단순히 데이터를 넘기고, 

  scanf()는 입력 받을 주소를 나타내기 위해 &를 사용한다.

+ Recent posts