본문 바로가기
c언어

c언어 포인터 사용 시 주의할 점에 대하여 알아보기

by 개발자 L 2022. 12. 7.
반응형

c언어 포인터 사용 시 주의할 점에 대하여 알아보기

네 안녕하세요, 이번 포스팅에서는 포인터를 사용할 때 주의해야 하는 점들에 대하여 알아보도록 하겠습니다.

우리가 직접 c언어를 이용을 하여 개발을 할 때 약방의 감초 역할을 하는 포인터지만,

이 포인터도 우리가 잘 다룰 수 있을 때까지 연습을 하고, 그 외 주의사항을 잘 알고 있어야 슬기롭게 쓸 수 있겠죠?
그래서 이번 포스팅에서 그러한 것들을 다룰 것입니다.

그럼 지금부터 시작하도록 하겠습니다.

 

1. 반드시 초기화를 하고 사용하기

이는 포인터가 c언어에서 사용하는 강력한 도구임과 동시에, 수많은 오류를 일으키게 하는 원천 중 하나입니다.

실제로 가장 흔한 오류가 초기화가 되지 않은 포인터를 사용하여 범한 오류입니다.

포인터 역시 다른 변수들이나 배열처럼 초기화를 하지 않으면 쓰레기 값이 들어가게 됩니다.

예를 들면 이런 경우죠.

#include <stdio.h>

int main()
{
    int *p; // 초기화가 되지 않은 포인터 변수
    
    *p = 100;
    
    return 0;
}

이런 경우가 있다고 가정을 해봅시다.

이러면 필연적으로 오류가 납니다.

그 이유는 포인터가 가리키는 방향이 정의가 되어있지 않기 때문에 아무 곳이나 가리키고 있어서 그렇습니다.

그래서 포인터가 가리키는 값이 명확하지 않은데 포인터를 사용해야겠다면 이렇게 쓰세요.

int *p = NULL;

이렇게 널 값(NULL)을 넣어주는 것입니다.

널 값(NULL)은 값이 없다는 것을 나타내주는 데이터입니다.

그리고 이는 초기값을 공백으로 놔두는 것과는 큰 차이가 있습니다.

널 값(NULL)을 사용하지 않았을 경우는 변수가 아무 곳이나 가리키는 것을 의미하기 때문에 초기값으로 아무거나 들어와도 된다는 뜻이 되어 쓰레기 값이 들어가게 되고요,

널 값(NULL)으로 초기화를 했을 경우에는 변수가 가리키는 값이 비어있다고 하나의 값으로 표시를 하는 것이기 때문에 빈 값을 가리키게 됩니다.

이는 포인터 역시 마찬가지입니다.

반응형

 

2. 포인터 타입 변수와 일반 변수 타입은 반드시 일치해야 한다.

두 번째 경우도 사실 많이 저지르는 실수 중 하나입니다.

포인터의 자료형은 반드시 변수의 자료형과 같아야만 합니다.

예를 들어 정수형 변수를 선언했다면, 포인터의 자료형도 정수형이어야 하고,

문자형 변수를 선언했다면, 포인터의 자료형도 문자형이 되어야만 하는 겁니다.

예를 들자면 이런 경우입니다.

#include <stdio.h>

int main()
{
    int a;
    double *pd;
    
    pd = &a;
    *pd = 36.8
    
    return 0;
}

이럴 경우는 변수의 자료형과 포인터의 자료형이 일치하지 않으므로 실행 시에 오류가 생길 수 있습니다.

일반적인 경우는 double형 변수가 int형 변수보다 상위이기 때문에 컴파일러가 데이터를 덮어써서 갱신을 하여 자동으로 double형으로 상향 형 변환을 하게 됩니다.

그렇지만 이는 변수끼리의 자동 형 변환을 말하는 것이고,

포인터와의 관계를 본다면 이렇습니다.

정수형 자료형인 int형은 4바이트, 실수형 자료형인 double형은 8바이트입니다.

일반적인 변수라면 8바이트의 크기를 가진 상위 자료형인 double형을 따라가서 갱신이 되어야 하지만,

포인터의 경우는 int형과 double형의 호환 과정에서 남게 된 나머지 4바이트를 덮어쓰게 되는 겁니다.

다시 말하면 다운 그레이드가 되어서 언더플로우가 일어납니다.

그래서 실수형 자료형을 받을 수가 없어서 실행 시 오류가 나게 되는 것입니다.

그래서 특별한 경우가 없다면 절대로 다른 타입의 데이터를 가리키게 해서는 안됩니다.

 

3. 하드웨어에 들어가는 프로그램이 아니라면 절대 주소를 사용하지 않는다.

아두이노 같은 엠베디드 시스템이나 하드웨어는 절대 주소를 사용하여 개발을 할 수가 있습니다.

예를 들면 이런 식으로 말이죠.

int *p = (int *)100000;

이건 100000번지 인덱스를 가진 변수를 int형으로 캐스팅을 하겠다는 뜻입니다.

그리고 이런 방법은 이미 정해져 있는 인덱스에 들어가서 바로 찍어내는 방법이기 때문에 절대 주소를 사용했다고 합니다.

그렇지만 이런 방법은 하드웨어에 들어가는 시스템에서나 가능한 경우이고,

하드웨어 개발자가 아닌 소프트웨어 개발, 다시 말하면 웹이나 앱을 개발한다면 이렇게 쓰게 되면 치명적인 오류를 범하게 됩니다.

그 이유는 메모리를 관리하는 것은 운영체제가 가지는 고유한 권한이라서, 그걸 개발자가 침범을 하는 일이 벌어지는 것이기에 개발자가 관여를 할 수가 없습니다.

하지만 하드웨어의 경우는 초기에는 아무것도 들어가지 않은 깡통이기 때문에 개발자가 곧 감독이 되기 때문에 개발자가 직접 메모리를 관리해도 문제가 없습니다.

그러니 이 점을 꼭  유의하세요.

 

여기까지 포인터를 사용할 때 주의할 점에 대하여 알아보았는데요,

다음 포스팅에서는 포인터로 연산을 하는 방법에 대하여 알아보도록 하겠습니다.

긴 글 읽어주신 독자분들께 진심으로 감사드립니다~

반응형

댓글