C에서 malloc을 언제 사용해야하고 언제 사용하지 않아야합니까?


94

malloc ()이 어떻게 작동하는지 이해합니다. 내 질문은 다음과 같은 것을 보게 될 것입니다.

#define A_MEGABYTE (1024 * 1024)

char *some_memory;
size_t size_to_allocate = A_MEGABYTE;
some_memory = (char *)malloc(size_to_allocate);
sprintf(some_memory, "Hello World");
printf("%s\n", some_memory);
free(some_memory);

간결함을 위해 오류 검사를 생략했습니다. 내 질문은 메모리의 일부 정적 저장소에 대한 포인터를 초기화하여 위의 작업을 수행 할 수 없다는 것입니다. 혹시:

char *some_memory = "Hello World";

유지해야하는 값을 선언 / 초기화하는 대신 실제로 메모리를 직접 할당해야하는 시점은 무엇입니까?


5
Re : 간결함을 위해 오류 검사를 생략했습니다 . 불행히도 너무 많은 프로그래머 가 실패 할 수 있다는 것을 깨닫지 못하기 때문에 오류 검사를 생략합니다malloc() !
앤드류

답변:


132
char *some_memory = "Hello World";

문자열 상수에 대한 포인터를 만들고 있습니다. 즉, "Hello World"문자열이 메모리의 읽기 전용 부분 어딘가에 있으며 포인터 만 있으면됩니다. 문자열을 읽기 전용으로 사용할 수 있습니다. 당신은 할 수없는 그것을 변경합니다. 예:

some_memory[0] = 'h';

문제를 요구하고 있습니다.

반면에

some_memory = (char *)malloc(size_to_allocate);

char 배열 (변수)을 할당하고 some_memory는 할당 된 메모리를 가리 킵니다. 이제이 배열은 읽고 쓸 수 있습니다. 이제 다음을 수행 할 수 있습니다.

some_memory[0] = 'h';

배열 내용이 "hello World"로 변경됩니다.


19
명확히하기 위해 내가이 대답을 좋아하는만큼 (+1을주었습니다) 문자 배열을 사용하여 malloc () 없이도 똑같이 할 수 있습니다. 다음과 같습니다. char some_memory [] = "Hello"; some_memory [0] = 'W'; 또한 작동합니다.
randombits 2009

19
당신이 옳습니다. 할 수 있습니다. malloc ()을 사용할 때 메모리는 런타임에 동적으로 할당되므로 컴파일 타임에 배열 크기를 수정할 필요가 없습니다. 또한 realloc ()을 사용하여 확장하거나 축소 할 수 있습니다. 다음 중 어떤 것도 수행 할 수 없습니다. char some_memory [] = "안녕하세요"; 여기서 배열의 내용을 변경할 수 있지만 크기는 고정되어 있습니다. 따라서 필요에 따라 1) char const에 대한 포인터 2) 동적 할당 배열 3) 고정 크기, 컴파일 시간 할당 배열의 세 가지 옵션 중 하나를 사용합니다.
codaddict 2009

읽기 전용이라는 점을 강조하려면 const char *s = "hi";실제로 표준에서 요구하지 않습니까?
Till Theis

@Till, 아니요, 문자열 리터럴 "hi"의 기본 주소로 초기화 된 포인터를 선언했기 때문입니다. s는 상수가 아닌 문자를 가리 키도록 완벽하게 합법적으로 다시 할당 될 수 있습니다. 읽기 전용 문자열에 대한 상수 포인터를 원하면 다음이 필요합니다.const char const* s;
Rob11311

38

정확한 예를 들어 malloc은 거의 사용되지 않습니다.

malloc이 필요한 주된 이유는 코드 범위와 다른 수명을 가져야하는 데이터가있을 때입니다. 코드는 하나의 루틴에서 malloc을 호출하고 포인터를 어딘가에 저장하고 결국 다른 루틴에서 free를 호출합니다.

두 번째 이유는 C가 할당을 위해 스택에 충분한 공간이 남아 있는지 알 수 없기 때문입니다. 코드가 100 % 견고해야하는 경우 malloc을 사용하는 것이 더 안전합니다. 그러면 코드가 할당 실패를 알고 처리 할 수 ​​있기 때문입니다.


4
메모리 수명주기 및 할당 해제시기와 방법에 대한 관련 질문은 많은 공통 라이브러리 및 소프트웨어 구성 요소에서 중요한 문제입니다. 그들은 일반적으로 잘 문서화 규칙이 "당신에 대한 포인터를 전달하면 내 루틴 중 하나, 당신은 그것을 malloc이 한 필요 나는 그것을 추적하고, 나는 그것으로 끝났어요 때 무료 것입니다.. " 불쾌한 버그의 일반적인 원인은 정적으로 할당 된 메모리에 대한 포인터를 이러한 라이브러리에 전달하는 것입니다. 라이브러리가 free ()를 시도하면 프로그램이 충돌합니다. 나는 최근에 다른 누군가가 작성한 것과 같은 버그를 고치는 데 많은 시간을 보냈습니다.
Bob Murphy

malloc ()이 실제로 사용되는 유일한 시간은 malloc 이후로 여러 번 호출되고 '정리'되어야하는 프로그램 수명 동안 여러 번 호출 될 코드 세그먼트가있을 때입니다. ()에는 free ()가 동반됩니까? 예를 들어, wheel of fortune과 같은 게임에서 추측하고 지정된 char 배열에 입력을 넣은 후 malloc () 크기 배열이 다음 추측을 위해 해제 될 수있는 곳은 어디입니까?
스미스 윌 충분

데이터의 수명은 실제로 malloc을 사용하는 진짜 이유입니다. 추상 데이터 유형이 모듈로 표현되고 목록 유형을 선언하고 목록에서 항목을 추가 / 삭제하는 루틴을 선언한다고 가정하십시오. 이러한 항목 값은 동적으로 할당 된 메모리에 복사해야합니다.
Rob11311 2014-06-08

@Bob : 그 끔찍한 버그는 할당자가 메모리를 해제하는 규칙을 훨씬 더 우수하게 만듭니다. 결국 재활용 할 수 있습니다. 전체 블록에 대해 free를 한 번만 호출해야하므로 해당 라이브러리의 손상된 특성을 노출하는 참조의 지역성을 개선하기 위해 calloc으로 메모리를 할당했다고 가정합니다. 다행히도 저는 메모리를 'malloc-ed'로 지정하는 라이브러리를 사용할 필요가 없었습니다. 이것은 POSIX 전통이 아니며 버그로 간주 될 가능성이 높습니다. 그들이 당신이 malloc을 사용해야한다는 것을 "알고"있다면, 라이브러리 루틴이 당신을 위해 그것을하지 않는 이유는 무엇입니까?
Rob11311 2014-06-08

17

malloc은 컴파일 타임에 처리되므로 크기를 변경할 수없는 hello world 예제와 같은 정적 선언과 비교할 때 런타임에 메모리를 할당, 재 할당 및 해제하는 훌륭한 도구입니다.

따라서 Malloc은 파일 내용 읽기 또는 소켓 처리와 같이 임의 크기의 데이터를 처리 할 때 항상 유용하며 처리 할 데이터의 길이를 알지 못합니다.

물론, 당신이 준 것과 같은 사소한 예에서 malloc은 마법의 "올바른 작업에 적합한 도구"는 아니지만 더 복잡한 경우 (예 : 런타임에 임의의 크기 배열 생성)의 경우 유일한 방법입니다. 가다.


7

사용해야하는 정확한 메모리 크기를 모르는 경우 동적 할당 ( malloc) 이 필요합니다 . 예를 들어 사용자가 애플리케이션에서 파일을 여는 경우가 있습니다. 파일의 내용을 메모리로 읽어야하지만 물론 사용자가 런타임에 그 자리에서 파일을 선택하기 때문에 파일의 크기를 미리 알 수 없습니다. 따라서 기본적으로 malloc작업중인 데이터의 크기를 미리 모를 때 필요 합니다. 적어도 이것이 .NET을 사용하는 주요 이유 중 하나입니다 malloc. 컴파일 타임에 이미 크기를 알고있는 (수정하고 싶지 않은 경우) 간단한 문자열이있는 예제에서는 동적으로 할당하는 것이별로 의미가 없습니다.


주제에서 약간 벗어 났지만 ... .NET Framework를 사용할 때 메모리 누수가 발생하지 않도록 매우주의해야합니다 malloc. 이 코드를 고려하십시오.

int do_something() {
    uint8_t* someMemory = (uint8_t*)malloc(1024);

    // Do some stuff

    if ( /* some error occured */ ) return -1;

    // Do some other stuff

    free(someMemory);
    return result;
}

이 코드에 무엇이 잘못되었는지 보십니까? malloc와 사이에 조건부 반환 문이 free있습니다. 처음에는 괜찮아 보이지만 생각해보십시오. 오류가 있으면 할당 한 메모리를 해제하지 않고 돌아갑니다. 이것은 메모리 누수의 일반적인 원인입니다.

물론 이것은 매우 간단한 예이며 여기서 실수를 쉽게 알 수 있지만 포인터, mallocs, frees 및 모든 종류의 오류 처리로 가득 찬 수백 줄의 코드를 상상해보십시오 . 상황이 정말 빨리 지저분해질 수 있습니다. 이것이 내가 적용 가능한 경우 C보다 현대적인 C ++를 선호하는 이유 중 하나이지만, 그것은 완전히 다른 주제입니다.

따라서를 사용할 때마다 malloc항상 메모리가 free가능한 한 d 일 가능성이 있는지 확인하십시오 .


훌륭한 예! 가는 길 ^ _ ^
Musa Al-hassy

6
char *some_memory = "Hello World";
sprintf(some_memory, "Goodbye...");

는 불법이며 문자열 리터럴은 const.

이것은 스택에 또는 전역 적으로 (선언 된 위치에 따라) 12 바이트 문자 배열을 할당합니다.

char some_memory[] = "Hello World";

추가 조작을위한 공간을 남겨 두려면 배열의 크기를 더 크게 지정하도록 지정할 수 있습니다. (하지만 스택에 1MB를 넣지 마십시오.)

#define LINE_LEN 80

char some_memory[LINE_LEN] = "Hello World";
strcpy(some_memory, "Goodbye, sad world...");
printf("%s\n", some_memory);

5

메모리를 할당해야하는 한 가지 이유는 런타임에 메모리를 수정하려는 경우입니다. 이 경우 스택의 malloc 또는 버퍼를 사용할 수 있습니다. 포인터에 "Hello World"를 할당하는 간단한 예제는 "일반적으로"런타임에 수정할 수없는 메모리를 정의합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.