<배경 지식>
- 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;
}
'Notes for C' 카테고리의 다른 글
정수 자료형의 저장 방식과 scanf함수 사용시 주의할 점 (0) | 2022.08.28 |
---|---|
후위 증감연산자와 전위 증감연산자의 비밀 (0) | 2022.08.17 |
scanf 함수 (0) | 2022.08.11 |