C언어 포인터란?  포인터라쓰고 탈모라 읽는다

C언어에서 포인터는 프로그래밍을 하면서 아주 어렵게 배우는 주제이기도 합니다. 어렵다기보다는 헷갈리는 경우가 많아서 멘탈붕괴가 오고는 하죠. 포인터는 말 그대로 무엇을 가리키는 놈입니다. 무엇을 가리킬까요??

다른 변수의 주소를 가리킵니다! 

모든 변수는 그 데이터가 저장되는 공간의 주소를 갖고 있습니다.

그것을 어떻게 표현할까요??

int B = 4;

int *A = &B;

이렇게 표현하게 됩니다. A는 B의 주소를 값으로 갖고 있다는 의미랍니다. 만약 B의 주소가 0x20이고 B의 값은 4라고 할때 A의 값은 0x20이 됩니다.

만약 B가 가지고 있는 값을 가져오고 싶다고 할때는 *A로 값을 참조할 수 있습니다.

그림으로 나타내면 이런 식으로 나타낼 수 가 있겠지요.

 

정말 제 말대로 되는 지 코드로 살펴보도록 하지요.

#include <stdio.h> 
int main() { 
        int B = 4;   
        int *A = &B;    
        printf("B의 값:%d\n", B);
        printf("B의 주소 :%p\n", &B);   
        printf("A의 값:%p\n", A);       
        printf("A가 참조하는 값 :%d\n", *A);     
}

 

네, 그렇게 나오네요
 
그렇다면 이중포인터는 무엇을 말할까요??
똑똑하신 여러분은 이미 알고 계시겠지만 포인터를 2번 쓰는 것을 말합니다.
아래 그림과 같은 상황이 바로 이중 포인터라는 것이죠, 포인터의 포인터! 스트레스의 향연

A는 B를 가리키고 있고, B는 C를 가리키고 있습니다.

int C = 10;

int *B = &C;

int **A = &B;

이렇게 쓸 수 있다는 거지요. A에 **(포인터의 포인터, 이중포인터)가 붙어있는 것을 확인 할 수 있네요

A는 B의 주소값을 값으로 가지고 있고, B는 C의 주소값을 값으로 갖고 있습니다. 그렇다면 A가 B의 값을 참조하려고 한다면 *A가 되겠죠?? 그러면 무슨 값이 나올까요??

바로 B가 가지고 있는 값, C의 주소입니다. A가 C의 값을 참조하기 위해서는 한 번 더 가리켜야하는데요.

그때 더블포인터가 사용이 되는 것입니다.  **A는 10을 확인할 수 있을 겁니다.

코드로 확인해 보도록 하죠.

#include <stdio.h>

int main() { 
        int C = 10; 
        int *B = &C;
        int **A = &B;

        printf("C의 값 : %d\n", C); 
        printf("C의 주소 : %p\n", &C); 
        printf("B의 값 : %p\n", B); 
        printf("B의 주소 : %p\n", &B); 
        printf("B가 참조하는 값 : %d\n", *B);
        printf("A의 값 : %p\n", A); 
        printf("A가 참조하는 값 : %p\n", *A); 
        printf("A가 참조하는 값이 참조하는 값 : %d\n", **A);
}

결과는 아래와 같습니다.

 

 

앞서 말한 대로 C의 주소를 B가 값으로 가지고 있고, B의 주소를 A가 값으로 가지고 있는 걸 확인할 수 있겠죠?? *A는 C의 주소값을 갖고 있습니다. 왜냐면 *A는 B의 값을 가리키고 있는 데 B의 값은 C의 주소이니까요!

그렇다면 삼중포인터는 어떻게 될까요??

뭐하러 어려운 포인터를 쓰나?

포인터는 언제 써먹을 수 있을까요? 대표적으로 다음과 같은 상황일때 사용합니다. 

어떤 함수가 있다고 칠게요. 아주 단순합니다. 그저 매개변수인 a와 b의 값을 교환하는 swap이라는 함수입니다.

void swap(int a, int b) {
        int temp; 
        temp = a; 
        a = b;
        b = temp;
}  

int main() {
        int x = 10;
        int y = 20; 
        swap(x, y); 
        printf("x: %d, y: %d\n", x, y); 
}

 

call-by-value

우리는 x와 y의 값을 바꾸고 싶다 이겁니다. 그 과정을 살펴보지요.

1. 우선 temp에 a의 값을 넣습니다. 그렇다면 10이 temp의 값에 들어있겠네요.

2. 그리고 b의 값을 a에 집어 넣습니다. 그렇다면 a의 값은 b의 값인 20이 들어가겠군요.

3. 마지막으로 변수 b에 temp값을 넣습니다. temp는 10이었으니까 b는 10이 되어지겠군요.

이제 함수에서 빠져나옵니다. 그 값이 바뀌어있을까요? 아닙니다. 이 함수는 a와 b를 함수 내부에서만 교체할 뿐이지, 함수 호출이 끝나고 반환되서도 x와 y의 값은 변함이 없습니다. 왜 그럴까요?

함수인자 a와 b는 전달받은 매개변수의 값(x, y)만 복사해오기 때문입니다.

예를 들면 졸업증명서 원본이 있고, 그걸 복사해서 사본을 갖고 있습니다. 사본을 불에 태워도 원본이 같이 탈까요? 동시에 같이 태우지 않는 한 원본은 살아있습니다. 이렇기 때문에 main에서 swap을 호출하고 나서도 x와 y의 값은 변함이 없습니다.

이런 함수 호출 방법을 Call-By-Value라고 부르는 것입니다.

 

call-by-reference

그렇다면 우리는 어떻게 함수를 변경해야 할까요?

그럴때 포인터가 사용이 됩니다.

void swap(int *a, int *b) { 
        int temp; 
        temp = *a; 
        *a = *b; 
        *b = temp;
}

int main() { 
        int x = 10; 
        int y = 20; 

        swap(&x, &y);
        printf("x: %d, y: %d\n", x,y);
}

a는 x의 주소를 가리키고 있고, b는 y의 주소를 가리키고 있습니다. a는 x의 주소를 참조하고 있기 때문에 x에 영향이 주게 되는 겁니다. b 역시 마찬가지가 되겠구요.

그림을 통해서 설명해보도록 하지요.

1.  temp = *a

temp에 a가 가리키는 값을 대입합니다. a가 가리키는 값은 10입니다.

 

2.  *a = *b

a가 가리키는 값에 b가 가리키는 값을 넣습니다. 그림과 같이 x의 값이 변경됩니다.

3. *b = temp

b가 가리키는 값에 temp의 값을 저장합니다. temp는 방금전 10이었기 때문에 b가 가리키는 곳(y)의 값은 10으로 변경됩니다.

 

결과는 어떨까요?

결과 역시 우리가 예상했던 대로군요. 우리는 이와 같이 함수에서의 조작이 외부 변수에 조작이 가해질때, 그럴때를 Call-By-Reference라고 합니다.

반응형
블로그 이미지

REAKWON

와나진짜

,

 

 

C언어 문자열 처리 함수

문자열 처리는 어느 언어에서나 중요하죠.

우선 C언어에서 문자열을 처리하려면 string.h를 반드시 포함해야합니다. 

 

※이제부터 설명하는 함수들은 보안적인 취약점이 발견되있는 함수들이 있습니다. 테스트를 해보시기 전에 SDL을 NO로 설정하세요.

Project - [Project Name] Properties - (왼쪽) C/C++ - SDL checks : No
또는 전처리 구문을 사용합니다.

#define _SECURE_CRT_NO_WARNINGS

 

가장 많이 쓰이는 4개의 함수에 대해서만 우선 알아 보도록 합시다.

 

 문자열 길이  size_t strlen(const char *str) 

문자열을 input으로 넣어주면 반환되는 문자열의 길이가 나오게 됩니다. NULL문자

까지가 아닌 순수 문자열의 길이를 반환해주게 됩니다.

 

ex)

char str[20] = "hello, world";

int len = strlen(str);

 

문자열 연결 char* strcat(char *_Destination, const char* _Source)

문자열을 합치게 됩니다. _Destination 뒤에 _Source를 이어주게 됩니다. 주의해야 할 점은 매개변수로 _Destination은 배열로써 그 크기가 지정되어진 문자열이어야 합니다. 

ex) 

char dst[30]="dst";    //char *dst="dst"; 로 바꾸게 되면 error가 나오게 됩니다.

char src[30]="src";

printf("%s \n", strcat(dst,src));

 

문자열 비교 int strcmp(const char *_Str1, const char *_Str2)

문자열을 비교하게 됩니다.  

_Str1이 _Str2보다 사전순으로 나중에 등장하면 1

_Str1이 _Str2보다 사전순으로 먼저 등장하면 -1

_Str1과 _Str2와 사전순이 같다면 0

 

보통 문자열을 비교할때 이 함수를 사용하는데 두 문자열이 같다면 0이 나오기 때문에 문자열이 같은 지 if문에서 확인하려면 !strcmp(str1,str2)로 확인해야 합니다. 왜냐면 str1,str2가 같다면 0(FALSE)가 반환되기 때문이죠.

 

문자열 복사 char* strcpy(char *_Dest, const char *_Source)

문자열 _Source를 _Dest에 복사합니다. strcat와 마찬가지로 _Dest는 배열의 형태로 넘겨받습니다. _Dest에 _Source문자열을 합치기 때문에 _Dest는 _Source의 문자열을 포함할 만큼 크기가 커야합니다.

 

ex)

char _dest[20] = "hello,";

char _src[10] = "world";

strcat(_dest, _src);

 

 

 

 

위 네 가지 함수를 실제로 적용시켜볼까요??

#include<stdio.h>
#include<string.h>

int main() {

	char country[32] = "korea";
	char south[32] = "south";
	char southkorea[32] = "southkorea";
	char south_korea[32] = "South Korea";

	printf("문자열의 길이 : %d\n", strlen(country));

	strcat(south, country);
	printf("문자열 결합 : %s\n", south);

	printf("문자열 비교 : ");
	if (!strcmp(south, southkorea)) {
		printf("%s = %s\n", south, southkorea);
	}
	else {
		printf("%s != %s\n", south, southkorea);
	}


	strcpy(southkorea, south_korea);
	printf("문자열 복사 : %s\n", southkorea);

}

 

그리고 그 결과입니다.

 

이상으로 문자열과 관련해서 자주쓰이는 함수 몇가지를 살펴보았습니다.

 

 

반응형
블로그 이미지

REAKWON

와나진짜

,