Notes for C

메모리 관련 함수

Sloth Coder 2022. 8. 7. 17:59

<배경 지식>

  • 32비트에서 포인터가 저장하는 주소값의 크기는 4바이트, 64바이트에서는 8바이트이다.

 

 

<메모리 할당>

  • malloc함수로 포인터 변수에 메모리 동적 할당 가능.
  • malloc 함수는 할당하고자 하는 메모리 크기를 매개변수로 받고, 할당에 성공하면 메모리 주소를 리턴하고, 실패하면 NULL을 리턴한다.
  • 동적 할당과 일반 변수 생성시 사용하는 메모리 부분은 다르다. malloc함수는 heap부분의 메모리를 사용하고 변수는 stack부분의 메모리에 생성된다. 
  • malloc 함수로 할당한 메모리에 값을 저장할 때는 *ptr = 10;처럼 포인터를 역참조한 뒤 값을 저장한다.
#include <stdio.h>
#include <stdlib.h>

int main(){
	int *ptr;
    
    ptr = malloc(sizeof(*ptr)); //포인터가 가리키는 자료형의 크기만큼
    //or ptr = malloc(sizeof(int)); //자료형의 크기를 직접 명시
	//메모리 할당에 성공하면 메모리 주소를 리턴해 포인터인 ptr에 대입.

	free(ptr);
	
	return 0;
}

 

 

<메모리 해제>

  • stack에 생성된 변수는 사용한 뒤 따로 처리할 필요가 없지만 heap에 할당한 메모리는 반드시 해제를 해줘야 한다.
  • 메모리 해제는 free함수로 가능.
  • free함수는 포인터를 매개변수로 받고 아무것도 리턴하지 않는다.

 

 

<memset 함수>

  • string.h or memory.h 파일에 정의.
  • memset(pointer variable or address value, value, size of memory)
  • 포인터의 위치(또는 주소값)부터 size of memory에 설정해준 크기만큼의 메모리의 내용을 value로 설정한다. memset(시작위치, 넣고 싶은 값, 길이)라고 생각하면 쉽다. 시작 위치는 포인터 연산을 이용해 바꿀 수도 있다. 길이는 바이트 단위이다.
#include <stdio.h>
#include <string.h>

int main(){

    char test[10] = "Hi Hello";

    memset(test + 3, 'b', 5);

    printf("%s", test); //결과: "Hi bbbbb"

    return 0;
}
  • value는 integer타입으로 받지만 내부에서는 unsigned char로 변환되어 저장된다. 즉 문자(char)를 넣어도 괜찮다.
  • 메모리 설정에 성공하면 첫번째 인자로 들어간 포인터를 반환하고 실패하면 NULL을 반환한다.
  • 단, memset 함수는 1바이트 단위로 값을 초기화 하기때문에 0이외의 int값을 넣으면 원하는 값으로 설정할 수 없다. int값은 기본적으로 4바이트이기 때문에 1바이트로 표현될 수 없는 값들이 있고, 1바이트 내로 표현될 수 있는 값이라 하더라도 1바이트 단위로 저장하고 4바이트단위로 읽는 과정에서 필연적으로 오류가 발생할 수 밖에 없다.

 

1칸을 1비트, 한 줄을 1바이트(8비트)라고 해보자. 1바이트 단위의 1은 이렇게 저장될 것이다. 

0 0 0 0 0 0 0 1

 

int는 4바이트 단위이므로 int의 메모리 공간에는 다음과 같이 저장될 것이고, 이를 int단위(4바이트)로 읽으면 1이 아니라 16843009라는 숫자가 나오게 된다(1 + 2^8 + 2^16 + 2^24).

2^31 2^30 2^29 2^28 2^27 2^26 2^25 2^24
0 0 0 0 0 0 0 1
2^23 2^22 2^21 2^20 2^19 2^18 2^17 2^16
0 0 0 0 0 0 0 1
2^15 2^14 2^13 2^12 2^11 2^10 2^9 2^8
0 0 0 0 0 0 0 1
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
0 0 0 0 0 0 0 1
  • 따라서 memset으로 값을 설정할 때는 0 또는 같은 1바이트 단위인 char 타입 값만을 사용해야 한다.
  • 이러한 제약때문에 memset함수는 일반적으로 문자열(연속된 char 단위)에서 값을 변경하거나, 숫자를 0으로 초기화할 때 사용된다.

 

 

<memcpy 함수>

  • string.h or memory.h 파일에 정의.
  • memcpy(pointer variable1, pointer variable2, size of memory)
  • pointer variable2가 가리키는 곳부터 size of memory만큼 메모리에 있는 값을 pointer variable1에 복사한다.
  • memcpy(복사 받을 포인터, 복사해 올 포인터, 길이)라고 생각하면 쉽다. 길이는 바이트 단위이다.
  • 문자열 복사시, 만일 문자열 전체를 복사하는 것이라면 맨 끝에 NULL문자('\0')까지 고려해 길이를 설정해 주어야 한다.
  • 단, 문자열 중간에  붙여넣는 경우에는 NULL문자까지 붙여 넣으면 안된다. C언어에서는 NULL문자를 문자열의 끝으로 인식하기 때문이다.
#include <stdio.h>
#include <memory.h>

int main(){

    char test[10] = "Hi Hello";
    char destination[10] = "123456789";

    memcpy(destination, test, sizeof(test)); //복사할 대상 문자열의 sizeof를 사용하면 test배열의 사이즈만큼 복사하기때문에
                                            //NULL문자도 포함되게 size가 설정되어 NULL문자를 따로 고려할 필요가 없다.
    printf("%s", destination); //결과 : "Hi Hello"

    return 0;
}
#include <stdio.h>
#include <memory.h>

int main(){

    char test[10] = "Hi Hello";
    char destination[10] = "123456789";

    memcpy(destination, test, 8); //다음과 같이 NULL문자를 고려하지 않고 8바이트로 문자들의 크기만 고려하면
                                  //destination 은 "Hi Hello9\0"이 된다. 중간에 값을 끼워넣고 싶다면 이와 같이 해도 된다.
    printf("%s", destination); //결과: "Hi Hello9\0"

    return 0;
}
#include <stdio.h>
#include <memory.h>

int main(){

    char test[10] = "Hi Hello";
    char destination[11] = "0123456789";

    memcpy(destination, test, 9); //NULL문자까지 포함하도록 크기 설정
                                  //destination 은 "Hi Hello\09\0"이 된다.
    printf("%s", destination); //결과: "Hi Hello" - NULL문자에서 문자열의 끝이라고 인식하므로 9는 출력되지 않는다.

    return 0;
}