C언어 전역변수 동적 할당 - Ceon-eo jeon-yeogbyeonsu dongjeog haldang

전역변수와 지역변수로 해결이 되지 않는 상황

malloc은 메모리공간을 할당할 때 사용하는 함수 [잠시 변수 할당]

1. 지역변수일 경우

C언어 전역변수 동적 할당 - Ceon-eo jeon-yeogbyeonsu dongjeog haldang

ReadUserName : 이름을 입력받고 입력받은 이름을 반환하는 함수

main : ReadUserName의 주소값을 반환해 출력

-> 문자열을 입력받기 위한 메모리 공간이 필요하다.

작동 순서

1. 메모리 공간 할당

2. 입력

3. 반환

-> name2의 출력이 끝났을 때

name1이 가리키는 것 : 첫번째로 입력한 문자열

name2가 가리키는 것 : 두번째로 입력한 문자열

-> ReadUserName()을 name1에 반환

-> name은 지역변수이므로 return과 동시에 소멸한다.

-> name1에는 소멸된 변수를 가리킨다. [에러 : 출력은 될수도 있지만 잘못된 코드]

2. 전역변수일 경우

C언어 전역변수 동적 할당 - Ceon-eo jeon-yeogbyeonsu dongjeog haldang

ReadUserName 함수

1. 전역변수 name

2. gets

3. return

-> 전역변수는 고정 [삭제, 추가 불가]

 -> name1과 name2을 입력받으면 두 개의 메모리공간 할당해야하지만

하나의 메모리 공간을 공유한다.

-> 출력을 하면 name1을 덮어써서 name1과 name2과 같아진다.

해결 방법

=>어떤 형태의 메모리 할당이 필요할까?


ReadUserName이 여러번 호출될때 각각 메모리가 할당되는 방법

함수가 호출되었을 때 메모리공간이 할당이 되어서 원하는 시간에 지울 수 있는 방법

: malloc()

-> 프로그래머가 지우지 않는 이상 계속해서 메모리에 남아있다.

데이터 영역 : 전역 변수

힙 영역 : 프로그래머가 원하는 시점에 할당과 해제하는 변수

스택 영역 : 지역 변수

#include <stdlib.h>
void* malloc(size_t size); //힙 영역으로의 메모리 공간 할당
void free(void * ptr); //힙 영역에 할당된 메모리 공간 해제
int main(void)
{
 void* ptr1= malloc(4);
 void* ptr2= malloc(12);
 
 ...
 free(ptr1);
 free(ptr2);
 ...
 }

-> 포인터연산을 하기 위해서는 데이터형변환이 필요하다

*ptr1= 20을 하기위해서는

int* ptr=(int *) ptr1;

*ptr1 = 20;

malloc 함수의 반환형이 void형 포인터인 이유

void* ptr1=malloc(sizeof(int)); //4
void* ptr2=malloc(sizeof(double)); //8
void* ptr3=malloc(sizeof(int)*7); //28 //7개 변수의 배열
void* ptr4=malloc(sizeof(double)); //72 //9개 변수의 배열
int* ptr1=(int*)malloc(sizeof(int));
double* ptr2=(double *)malloc(sizeof(double));
int* ptr3=(int*)malloc(sizeof(int)*7);
double* ptr4=(double *)sizeof(double)*9);

-> malloc함수는 메모리의 용도를 모르기 때문에 포인터형의 결정을 못한다.

-> 형변환 과정을 통해 할당된 메모리의 주소값을 저장


힙 영역으로의 접근

int main(void)
{
 int* ptr1=(int *)malloc(sizeof(int));
 int* ptr2=(int *)malloc(sizeof(int)*7);
 int i;
 
 *ptr1=20;
 for(i=0; i<7; i++)
 	ptr2[i]=i+1;
printf("%d \n", *ptr1);
for(i=0; i<7; i++)
	printf("%d ", ptr2[i]);
free(ptr1);
free(ptr2);
return 0;
}

-> 힙 영역으로의 접근은 포인터를 통해서만 이루어진다.

int* ptr=(int*) malloc(sizeof(int));
if(ptr==NULL)
{
 //메모리 할당 실패에 따른 오류의 처리
}

-> malloc 호출 후 반환된 주소값이 NULL이 아닌지 확인 후 메모리 공간을 사용해야 한다.


동적 할당인 이유

: 컴파일 시 할당에 필요한 메모리 공간이 계산되지 않고, 실행 시 할당에 필요한 메모리 공간이 계산되므로 동적할당

free 함수를 호출하지 않으면

: 할당된 메모리 공간은 메모리라는 중요한 리소스를 계속 차지하게 된다.

-> 프로그램이 종료되면 할당된 메모리가 소멸된다. [종료시 모든 리소스는 소멸된다.]

꼭 free함수를 호출해야 하는 이유는 무엇인가?

: fopen 함수와 쌍을 이루어 fclose 함수를 호출하는 것과 유사하다.

malloc을 호출하면 반드시 free 호출을 해야한다.


문자열 반환 함수 해결

char* ReadUserName(void)
{
 char* name=(char *)malloc(sizeof(char)*30);
 printf("What's your name? ");
 gets(name);
 return name;
 }
int main(void)
{
 char* name1;
 char* name2;
 name1=ReadUserName();
 printf("name1: %s \n", name1);
 name2=ReadUserName();
 printf("name1: %s \n", name2);
 
 printf("again name1: %s \n", name1);
 printf("again name2: %s \n", name2);
 free(name1);
 free(name2);
 return 0;
}

1. 메모리 할당 -> 함수를 빠져나가도 소멸되지 않는다.

2. 입력

3. 반환


calloc & realloc

-> malloc, calloc, realloc 함수 호출을 통해서 할당된 메모리 공간은 모두 free 함수호출을 통해서 해제한다.

13 Aug 2017 in Language on C

C언어 전역변수 동적 할당 - Ceon-eo jeon-yeogbyeonsu dongjeog haldang


제가 책(윤성우의 열혈 C 프로그래밍)을 보다가 까먹었던 부분만 포스팅 하는 것입니다!

순서가 뒤죽박죽이어도 이해해주세요~~!

C언어의 메모리 구조

프로그램 실행 시 운영체제에 의해서 마련되는 메모리 구조는 다음과 같습니다.

코드영역: 실행할 프로그램의 코드가 저장되는 메모리 공간


데이터영역: 전역변수와 static으로 선언되는 static 변수 할당

이 영역에 할당되는 변수들은 프로그램의 시작과 동시에 메모리 공간에 할당되고,
프로그램 종료 시 까지 남아있게 됩니다.


스택영역: 지역변수와 매개변수 할당

이 영역에 할당되는 변수들은 선언된 함수를 빠져나가면 소멸됩니다.


힙 영역: 데이터, 스택 영역에 할당되는 변수들은
 
생성과 소멸의 시점이 이미 결정되어 있습니다.

그래서 C언어에서는 프로그래머가 원하는 시점에 변수를 할당하고 소멸하도록 지원하는데,

이러한 유형의 변수들은 이 힙 영역에 할당됩니다.

메모리의 동적 할당

전역변수와 지역변수로 해결이 되지 않는 상황을 보겠습니다.

함수를 이용해서 사용자의 이름을 저장하고 싶은 것인데요~

첫번째는 지역변수를 사용한 경우입니다

#include <stdio.h>

//이름을 저장해서 반환하는 함수
char* your_name(void)
{
	char name[30]; //지역변수로 선언
	printf("이름을 입력하세요:");
	gets(name);
	return name;
}

int main(void)
{
	char * name1;
	
	name1=your_name();
	
	printf("%s",name);

	return 0;
}

위의 경우는 에러를 발생시키는데,

그 이유는 함수 your_name을 빠져나오면서 그 안의 선언된 지역변수들은

모두 소멸되어서 name1에는 쓰레기 값이 저장되기 때문입니다.

그렇다면 전역변수를 사용하면 문제가 해결될까요?

#include <stdio.h>
char name[30]; //전역변수로 선언

char* your_name(void)
{
	printf("이름을 입력하세요:");
	gets(name);
	return name;
}

int main(void)
{
	char* name1;
	char* name2;
	name1=your_name();
	name2=your_name();
	
	printf("%s",name1);
	return 0;
}

전역변수를 사용하면 위의 경우와 같이 여러명의 이름을 받을 때,

다른 이름을 덮어쓰는 문제가 발생합니다.

이를 해결해주는 것이 힙 영역에 할당되는 변수입니다.

힙 영역의 메모리 공간 할당과 해제는 malloc과 free함수로 할 수 있습니다.

#include <stdlib.h>

int *ptr=(int *)malloc(sizeof(int)*7); //동적할당

free(ptr); //동적해제

그리고 malloc함수를 선언했으면 꼭 free함수로 동적해제를 해주어야합니다~!

그럼 아까 문제를 malloc을 써서 해결해보겠습니다.

#include <stdio.h>

char* your_name(void)
{
	//동적할당
	char * name=(char *)malloc(sizeof(char)*30);
	printf("이름을 입력하세요:");
	gets(name);
	return name;
}

int main(void)
{
	char* name1;
	char* name2;
	name1=your_name();
	name2=your_name();
	
	printf("%s",name1);
	printf("%s",name2);
	
	free(name1); //동적해제
	free(name2);
	return 0;
}

문제가 깔끔히 해결되는 것을 보실 수 있습니다~!

calloc과 realloc 함수

힙 영역에 메모리 공간을 할당하는 함수로 calloc이 있습니다.

#include <stdlib.h>

int * ptr=(int *)calloc(7,sizeof(int));

//인자만 다를 뿐 malloc과 동일합니다.

그리고 힙에 할당된 메모리 공간 확장 시에는 realloc 함수를 이용합니다~

#include <stdlib.h>

int main(void)
{
	int *arr=(int *)malloc(sizeof(int)*3); //길이가 3인 int형 배열 할당
	
	arr=(int *)realloc(arr,sizeof(int)*5); //길이가 5인 int형 배열로 확장
}