[C] 포인터
★포인터 : C언어는 포인터 변수를 이용하여 컴퓨터의 메모리에 직접 접근하여 값을 대입하거나 변경할 수 있다. 잘 사용하면 유용한 도구가 되지만 실수할 경우 프로그램이 구동되지 않는 상태가 될 수 있다.
int a = 10;
a라는 4byte공간을 할당하고 10을 대입
int *pa = &a;
pa라는 공간을 할당하고 &a(a변수의 주소)를 대입하여 a를 가리키게 한다
★포인터란 주소를 담는 자료형이다.
*(asterisk) : 포인터 변수를 선언하거나 대상을 참조할 때 사용. 변수 선언시에는 해당 변수가 포인터 변수임을 표시한다. 그 외에는 포인터 변수가 가지는 주소값의 위치(대상, 값, 내용물)을 참조한다.
printf("a : %d\n", a); // a = 10
printf("&a : %d\n", &a); // &a = 11795872
printf("pa : %d\n", pa); // pa = 11795872
printf("*pa : %d\n", *pa); // *pa = 10
포인터를 따라가면 값이 나오게 된다.
★포인터 변수의 자료형은 대상의 자료형과 일치해야 한다.
★주소는 무조건 정수
★포인터 변수로 대상이 되는 변수를 출력도 가능하고, 참조도 가능하다.
int num = 10;
int *pnum = #
printf("num : %d\t *pnum : %d\n", num, *pnum);
printf("%d + %d = %d\n", 13, *pnum, 13 + *pnum);
그냥 *pnum은 num이라고 생각하고 써도 된다.
★(*)와 (&)는 서로 역할이 반대다
★배열과 포인터 : 배열의 변수명은 사실 배열의 첫번째 값의 주소를 의미한다.
★만약 int arr[5]라는 배열이 있고, 어떤 함수에 이 배열의 이름을 넣는다면 배열의 주소를 넣는것과도 같다.
★arr[i] => 주소[인덱스] => *(주소 + 인덱스)임 그래서 아래 두줄은 같은 결과를 만듬
printf("test[3] : %d\n", test[3]);
printf("3[test] : %d\n", 3[test]);
★배열의 이름으로 값을 변경할수 없음. 왜냐면 주소값을 바꿀수는 없으니까, 근데 포인터값으로는 저장가능
char name[20] = "불꽃남자 강덕현";
name = "강덕현"; (x)
char *name2 = "불꽃남자 강덕현";
name2 = "강덕현"; (o)
★동적 할당 : 컴파일할때가 아니라 실행하면서 메모리 할당하는 것
- 컴파일 시점에서 변수의 개수가 정해지지 않았을 경우나
- 어디에서나 접근 가능한 변수를 생성하기 위해서(여러함수에서 접근할수 있게) 사용한다.
malloc()함수는 함수 내부의 메모리가 아니라 Heap영역에 공간을 할당해서 변수를 만들기 때문에 함수가 종료되어도 변수는 제거되지 않는다. 즉 malloc()함수로 만든 변수는 지역변수가 아니다. 따라서 그 어떤 함수에서도 Heap에 접근하면 해당 변수를 사용할 수 있다.(위에 2번이랑 같은말)
int *p = malloc(int);
()안의 수의 byte만큼 Heap
이라고 하는 동적할당 전용의 메모리안의 공간을 배열형태로 만들고 그 시작점을 포인터변수로 반환한다
int *p = (void *)malloc(sizeof(int) * 5);
malloc() 함수는 (void *) 형태를 반환한다. 자료형이 지정되어 있지는 않지만 어떤 주소를 반환하는 함수이다. 위 경우에는 나중에 void를 int로 변환하게 됨.
★동적할당으로 생성한 변수는 사용자가 할당해제 하지 않는 한 소멸되지 않는다. 프로그램이 종료되도 소멸되지 않기때문에 꼭 해제 해줘야 한다.
★동적할당을 해제하는 함수free(해당 변수의 주소)
free(p);
★문자열 복사하기
int main() {
char *str = "practice";
char *dst = (char *)malloc(sizeof(char) * 20);
/*char * ps = str;
char * pd = dst;
while (*ps != '\0') {
*pd++ = *ps++;
}
*pd = '\0';*/
for (char * ps = str, *pd = dst; *pd++ = *ps++;) {
// △포인터를 굳이 한개 더 만드는 이유는 원본의 위치는 건드리지 않는게 좋기때문
// 나중에 못찾게 된다...
printf("str : %s\ndst : %s\n", str, dst);
// '\0' (널 문자)의 아스키 코드 값 : 0
// 0은 C언어에서 논리 거짓을 의미하므로
// for문의 조건절이 0이 되면 반복을 중단
}
free(dst);
return 0;
}