1. 메모리 구조


메모리는 크게 4개의 영역으로 나뉜다. 코드 영역, 스택 영역, 힙영역, 데이터 영역 이다.


1) 코드 영역 : 실행 명령어 저장

- 소스코드가 저장되는 영역으로, 실행할 명령어들이 순서대로 쌓인다.

- cpu가 이 영역에서 명령어들을 하나씩 가져다가 처리한다. (큐 구조)



2) 스택 영역 : 개발자가 제일 많이 사용하는 메모리는 스택 메모리 영역이다.  

- 스택이란 모든 원소들의 삽입 삭제를 한쪽 방향에서만 수행하도록 하는 선형 자료 구조이다.

- 이를 후입선출방식 (Last In First Out)이라 한다.

- 스택메모리는 지역변수와 매개변수같은 값들이 저장되는 공간이다.



void Test(int a)
{
    char b = 'A';
    int c = 1;
    double d = 3.14;
}

먼저 메모리에 int a 4바이트가 할당되고, char b 1byte, int c 4byte, double d 8 byte가 순서대로 할당되며 함수가 종료될때에는 거꾸로 메모리에서 제거된다. (d, c, b, a)



3) 힙 영역 : 개발자가 직접 할당

- 힙은 컴퓨터 메모리의 일부가 할당되었다가 회수되는 일들의 반복을 의미

- 합은 컴파일시가 아닌 실행 시 사용자로부터 할당 메모리를 입력 받음

- 생성과 삭제를 개발자가 직접 해줘야하는데, 삭제를 해주지 않으면 메모리 누수현상(메모리 릭)이 생긴다. 



4) 데이터 영역 : 전역 변수, 스태틱수 저장

- 전역 변수와 static변수가 저장되는 메모리이다.

- 프로그램 시작시 모든 전역변수와 static 변수가 데이터 영역에 저장되며, 프로그램이 종료시 메모리에서 소멸된다.






2. 동적 메모리 할당

1) 동적으로 메모리를 할당 하는 이유


일반적으로 변수는 컴파일타임에 할당된다. 

그렇다면 다음의 상황에서는 어떻게 될까?


Q. 전교생이 10명인 학교의 학생 수를 배열로 선언한다면?

A. int student[10];


Q. 학생수가 100명으로 늘어나게 되면?

A. int stduent[100];


학생수가 계속 유동적으로 변하게 된다면?

개발자가 그 상황에 맞게 계속 변수를 할당해줄 수 없다. 학생 수를 고정하지 말고 실행시 결정하자는 개념


int num;
fputs("학생수를 입력하세요 : ",stdout);
scanf("%d", &num);
int student[num];
문제점 
 - scanf는 런타임에 실행되지만 사용자가 값을 입력하는건 런타임이다. 
 - int student[num]은 컴파일타임에 실행된다. 런타임에 입력 받은 변수를 컴파일 타임에 대입하는 형태가 되기 때문에 컴파일 에러가 생긴다. 

 해결 방법

 - 실행 중에 학생 수를 알아야 하는 경우, 동적 메모리 할당 기법을 통해 문제 해결이 가능하다.





2) 메모리 할당 및 해제


malloc()

- 동적 메모리 할당 함수의 원형


void* malloc(size_t size);


- malloc 또는 말록이라고도 읽는다.

- 전달인자size는 바이트 단위로 입력한다.

- 메모리 할당이 되면 메모리의 주소값을 리턴한다.

- 메모리 부족 시 null 포인터 리턴한다.

- 리턴형이 void*인데, 타입이 지정되어 있지 않는 포인터를 리턴 한다.



free()

- 동적 메모리 해제 함수의 원형


void free(void* memblock);


- 메모리 사용후 반드시 해제 해야한다. (메모리 누수현상(메모리 릭)이 발생한다.)

- 전달인자로 메모리를 가리키는 포인터를 대입한다.



#include 
#include 

int main(void)
{
    int num;
    int* student);

    fputs("학생 수 입력 : ",stdout);
    scanf("%d", &num);
    student = (int*)malloc(sizeof((int)*num);

    if(student == null)
    {
        printf("메모리가 부족하가 부족하여 메모리를 할당 할 수 없습니다.\n");
        return 0;
    }

    printf("학당된 메모리의 크기는 %d 입니다. \n", sizeof((int)*num);
    free(student);

    return 0;
}



realloc()

- 실시간 메모리를 할당하여 사용한다 해도 사용중에 메모리 크기를 더 늘려야 하는 경우가 발생할 수 있다.

- malloc 함수로 할당된 메모리를 다시 동적으로 재할당해주는 함수가 realloc이다.




#include 
#include 

int main(void)
{
	int i;
	int *arr = (int*)malloc(sizeof(int) * 5);
	int *rearr; 

	for (i = 0; i < 5; i++)
	{
		arr[i] = i + 1;
	}
	rearr = (int*)realloc(arr, sizeof(int) * 10);
	for (i = 0; i < 10; i++)
	{
		rearr[i] = i + 1;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", rearr[i]);
	}

	free(rearr);
	return 0;
}


calloc()

- malooc 함수와 똑같은 기능을 갖는다

- 전달인자의 형태와 조금 다른데, 메모리 개수와 자료형의 크기를 대입한다.


int* a = (int*)calloc(elt_count, elt_size);

int* a = (int*)malloc(size * sizeof(int));


#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	int num, i, total = 0;
	int* student;

	fputs("학생 수 입력 : ", stdout);
	scanf("%d", &num);
	student = (int*)calloc(num, sizeof(int));

	if (student == NULL)
	{
		printf("메모리가 부족하가 부족하여 메모리를 할당할 수 없습니다.\n");
		return 0;
	}

	for (i = 0; i < num; i++)
	{
		printf("%d번째 학생의 성적 입력 : ", i + 1);
		scanf("%d", &student[i]);
	}
	for (i = 0; i < num; i++)
	{
		total += student[i];
	}
	printf("총점 : %d 평균 : %d \n", total, total / num);
	free(student);
	return 0;
}



memset()

- 메모리 블록에서 모든 바이트를 특정 값으로 설정 할 때 사용하는 초기화 함수


void* memset(void* dest, int c, size_t count)


#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main(void)
{
	int* arr= (int*)malloc(sizeof(int) * 10);
	int i;
	
	printf("=========초기화 하기 전========= ");
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", arr[i]);
	}
	memset(arr, 0, sizeof(int) * 10);
	printf("=========초기화 하기 후-======== ");
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", arr[i]);
	}
	free(arr);
	return 0;
}


>



memcpy()

- 메모리를 복사하는 함수


void* memcpy(void* dest, void* src, size_t count);


#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main(void)
{
	int* arr1 = (int*)malloc(sizeof(int) * 5);
	int arr2[5];
	int i;
	
	for (i = 0; i < 5; i++)
	{
		arr1[i] = i + 1;
	}
	memcpy(arr2, arr1, sizeof(int) * 5);
	for (i = 0; i < 5; i++)
	{
		printf("%d\n", arr2[i]);
	}
	free(arr1);
	return 0;
}


memcmp()

- 메모리를 비교하는 함수


void* memcmp(const void* ptr1, const void* ptr2, size_t num);


#include <stdio.h>
#include <string.h>

int main(void)
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,3,4,5 };
	
	if (memcmp(arr1, arr2, sizeof(int) * 5) == 0)
	{
		printf("arr 1 == arr2");
	}
	else
	{
		printf("arr 1 != arr2");
	}
	return 0;
}


Posted by 루우지

[C언어] 열거형 enum

C 2018.08.24 19:56

열거형이란?

- 열거형은 enumeration의 약자로 enum(이넘)이라고 읽는다.

- 데이터들을 열거한 집합이다. 

- 컴파일러는 열거형 멤버들을 정수형 상수로 취급한다.




열거형의 사용법

- 키워드는 enum을 사용하여 정의한다.   

#include 

enum Week
{
	sun = 0,
	mon,
	tue,
	wed,
	thu,
	fri,
	sat
};

int main(void)
{
	int day;
	printf("요일을 입력하세요(1.일, 2.월, 3.화, 4.수, 5.목, 6.금, 7.토) : ");
	scanf("%d", &day);

	switch (day)
	{
	case sun:
		printf("sunday");
	case mon:
		printf("monday");
	case tue:
		printf("tueday");
	case wed:
		printf("weday");
	case thu:
		printf("thuday");
	case fri:
		printf("friday");
	case sat:
		printf("atday");
	default:
		printf("err");
	}
	return 0;
}


- 열거형의 멤버들은 각 요일을 나타낸다.

- 첫번째 멤버 sun을 0으로 설정하면 다음 멤버 mon은 각 1씩 증가한다.

Posted by 루우지

1. 구조체란?

- 하나 이상의 서로 다른 종류의 변수들을 묶어서 새로운 자료형을 정의하는 것이다.



구조체를 사용하는 이유

- 연관된 변수들을 하나로 묶어서 관리함으로써 데이터 관리에 유용하다.

- 데이터의 양이 많아지면 궂체가 유리하다.

- 예를 들어 학생정보 관리 변수를 생성할때 이름, 나이, 성별 등의 정보들은 모두 변수로 선언하여 각각의 변수를 별도로 관리하면 연관성을 알 수가 없다. 



구조체 정의 방법

#include 
struct student
{
	char name[10];
	int age;
	int height;
};	// 구조체 정의

int main(void)
{
	struct student st1;	// 구조체 선언
	struct student st2;
}


- struct 키워드는 구조체라는 자료형을 의미

- student 는 만든 구조체의 이름

- name, age, height는 구조체 멤버 변수

- 구조체는 사용자가 정의한 새로운 자로형이다.



구조체 멤버 접근 방법

- 구조체 변수를 통해 구조체 멤버의 값을 참조해야 한다.

- 멤버에 접근시 . 콤마를 사용하는데, 이를 직접 접근이라 한다.


[구조체 변수명].[구조체 멤버]

ex) st1.name, st1.age, st1.height




2. 공용체란?

- 공용체도 사용자가 정의한 자료형이다

- 구조체와의 차이점은 메모리 공간을 공유한다는 점이다.


struct stTemp
{
	char a;
	int b;
	double c;
}st;


위와 같은 구조체가 있을때 메모리가 차지하는 용량은

a = 1byte, b = 4byte, c = 8byte 로 총 13byte가 메모리에 적재된다.

union unTemp
{
	char a;
	int b;
	double c;
}un;


위의 공용체와 같은 경우는 구조체와는 전혀 다른 메모리 적재방식이 적용된다.

제일 큰 멤버변수 double형 c가 8byte가 메모리에 적재되어 각각의 변수가 1회용으로 8byte 메모리안에 적재된다.

구조체는 멤버변수가 각각의 메모리 공간을 할당받고 있지만 공용체는 같은 메모리공간을 모든 변수가 공유하는 형태이다.


#include 

union unTemp
{
	char a;
	int b;
	double c;
}un;

int main(void)
{
	printf("문자형 a의 주소와 크기 : %x, %d\n", &un.a, sizeof(un.a));
	printf("정수형 b의 주소와 크기 : %x, %d\n", &un.a, sizeof(un.b));
	printf("실수형 c의 주소와 크기 : %x, %d\n", &un.a, sizeof(un.c));

	un.a = 'A';
	printf("문자형 a의 값 : %c\n", un.a);
	un.b = 100;
	printf("정수형 b의 값 : %d\n", un.b);
	un.c = 3.14;
	printf("실수형 c의 값 : %.2f\n", un.c);
	printf("문자형 a의 값 : %c\n", un.a);
	return 0;
}



- 시작 주소는 세 변수가 모두 같다.

- 예제의 마지막줄 a값을 다시 출력 시 쓰레기값이 출력된다. 

- 그 이유는 double형 8byte에 저장된 값은 3.14인데 그중 1byte의 값만 읽어와 출력하는것이니 쓰레기값이 출력된다.


공용체를 사용하는 이유

- 메모리 절약을 위해서

- 구조체는 각 가정의 화정실, 공용체는 공원의 공중 화장실이라 생각하면 된다. 


공용체 사용 시 유의 사항

- 공용체 멤버는 동시에 사용하게 되면 데이터가 별질될 우려가 있으므로 따로 따로 사용해야한다.




Posted by 루우지


void CAVI_PROJECTDlg::OnBnClickedBtnFind()
{ 
	BROWSEINFO BrInfo;
	TCHAR szBuffer[512];                                      // 경로저장 버퍼 

	::ZeroMemory(&BrInfo,sizeof(BROWSEINFO));
	::ZeroMemory(szBuffer, 512); 

	BrInfo.hwndOwner = GetSafeHwnd(); 
	BrInfo.lpszTitle = _T("파일이 저장될 폴더를 선택하세요");
	BrInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_RETURNONLYFSDIRS;
	LPITEMIDLIST pItemIdList = ::SHBrowseForFolder(&BrInfo);
	::SHGetPathFromIDList(pItemIdList, szBuffer);				// 파일경로 읽어오기

	CString str;
	str.Format(_T("%s"),szBuffer);
	AfxMessageBox(str);
}


MFC 버튼컨트롤에 클릭이벤트를 건뒤 해당 함수에 위의 소스를 복붙해서 실행하시면 폴더 찾기 다이얼로그가 생성되는걸 확인 할 수있습니다. 





Posted by 루우지