[C언어] 포인터

이가영·2023년 8월 29일
0

C언어

목록 보기
10/16

포인터의 정의와 사용

  • 변수를 선언하는 것은 메모리에 기억공간을 할당하는 것이며 할당된 이후에는 변수명으로 그 기억공간을 사용한다.
  • 할당된 기억공간을 사용하는 방법에는 변수명 외에 메모리의 실제 주소값을 사용하는 것이다. 이 주소값 = 포인터

포인터란?

  • 메모리에는 바이트단위로 그 위치를 식별할 수 있는 물리적인 주소값이 있다.
    -메모리의 용량이 64kb라면 주소값은 0번지부터 65535번지까지 존재한다.
64kbyte = 64 X 1024 = 65535 (1k = 2의 10승 = 1024)
  • 변수를 선언하면 그 자료형의 크기만큼 메모리에 연속된 바이트의 기억공간이 할당되는데 그 첫번째 바이트의 주소값이 포인터이다.
  • 이 포인터를 사용하여 4바이트의 기억공간에 값을 저장하거나 저장된 값을 꺼내어 쓸 수 있다.

주소연산자 -> 주소 읽기 연산자

  • 특정 변수의 포인터를 구하기 위해서는 주소연산자(&)를 사용한다.
& gayeong -> 포인터를 구해준다.
주소연산자 / 변수명
  • 포인터를 구하여 출력
char ch;
int in;
double db;
printf("ch의 포인터 : %u\n", &ch);
printf("in의 포인터 : %u\n", &in);
printf("db의 포인터 : %u\n", &db);
->
ch의 포인터 : 1245052 //char형 변수의 주소값
in의 포인터 : 1245048 //int형 변수의 시작 주소값
db의 포인터 : 1245040 //double형 변수의 시작 주소값

포인터는 특정 자료형을 가리킨다.

  • 포인터에는 자신이 어떤 자료형으로부터 만들어졌는지에 대한 정보를 가지고 있다.
  • 포인터가 특정 자료형에 대한 정보를 가지고 있다는 것을 간단히 표현할 때 "가리킨다"고 하고 화살표를 사용하여 그림을 그린다.
int형 변수 gayeong을 가리키는 포인터
&gayeong -> 변수 gayeong //4바이트의 기억공간 전체를 가리킨다.

참조연산자 -> 데이터 쓰기 / 읽기 연산자

  • 포인터를 통해서 기억공간을 사용하기 위해서는 참조연산자(*)를 사용한다.
                 포인터에 참조연산자 붙이면 
* & gayeong -> 포인터가 가리키는 기억공간 사용 -> 변수처럼 사용
참조연산자 / 포인터(& gayeong)
char ch;
int in;
double db;
*&ch = 'P'; //포인터 &ch가 가리키는 기억공간에 'P'를 저장
*&in = 100; //포인터 &in가 가리키는 기억공간에 100를 저장
*&db = 3.14; //포인터 &db가 가리키는 기억공간에 3.14를 저장
printf("변수 ch에 저장된 문자 : %c\n", ch);
printf("변수 in에 저장된 문자 : %d\n", in);
printf("변수 db에 저장된 문자 : %lf\n", db);
->
변수 ch에 저장된 문자 : P
변수 in에 저장된 값 : 100
변수 db에 저장된 값 : 3.140000

참조연산자

  • "참조"는
    • 기억공간을 사용 -> 데이터 쓰기
    • 기억공간에 저장된 값도 사용 -> 데이터 읽기
int a=100, b=0;
b = *&a; //포인터 &a가 가리키는 기억공간의 값을 b에 대입
printf("b의 값 : %d\n", b);
  • 기억공간을 사용하는 것과 값을 사용하는 것은 대입연산자의 어디에 위치하느냐에 따라 결정된다. ★ 포인터 -> 실체?
int a=10, b=20;
*&a = *&b; //변수 b에 저장된 값을 변수 a의 기억공간에 저장
printf("a의 값 : %d\n", a); //a의 값은 20이 출력
->
기억공간을 사용(왼쪽) *&a = *&b; 기억공간의 값을 사용(오른쪽) => a=b;
       오른쪽의 값을 왼쪽의 기억공간에 저장한다.

포인터변수

  • 포인터의 값 자체는 정수 값이지만 가리키는 자료형에 대한 정보를 가지고 있으므로 정수형 변수에 저장할 수 없다.
★ 포인터 = 주소 + 자료형 정보 ★
int a;  //포인터를 구할 변수
int ap; //포인터를 저장할 변수
ap = &a; //a의 포인터를 구해서 ap에 저장
  • 직관적으로는 충분히 가능할 듯 하지만 컴파일 에러가 발행한다.
  • 포인터는 포인터가 가진 정보를 그대로 보존할 수 있도록 "포인터변수에 저장해야 한다."
  • 포인터변수는 변수명 앞에 '*'을 붙이고 가리키는 자료형을 앞에 적어준다.
    -int형 변수의 포인터를 저장하는 포인터변수의 선언
int *ap;
가리키는 자료형을 앞에 붙임/변수명 앞에 *을 붙여 포인터변수임을 표시
->
이름은 ap고 포인터변수이다. int형 변수의 시작주소값만을 저장. 그래서 int형 변수를 가리킨다고 함.

포인터변수가 포인터를 저장하면 포인터와 마차낙지로 기억공간을 가리킨다.

int a;
int *ap;
ap = &a;

포인터변수를 사용한 참조

  • 포인터를 저장한 포인터변수도 참조연산자로 그것이 가리키는 기억공간 또는 그 기억공간의 값을 사용할 수 있다.
int a; //int형 변수의 선언
int *ap = &a; //포인터변수의 선언과 동시에 초기화, ap는 변수a를 가리킨다.
*ap = 10; //포인터변수가 가리키는 기억공간에 10 저장
//ap에 a의 주소값을 저장 
//주소값에 별표(참조연산자)를 붙이면 그 주소의 실체를 의미!
//a주소값의 실체는 a와 같다. -> a=10
  • 포인터변수도 하나의 변수이므로 주소연산자로 메모리에서의 위치를 구할 수 있다.
int a; //int형 변수의 선언
int *ap = &a; //포인터변수의 선언과 동시에 초기화, ap는 변수a를 가리킨다.
printf("ap에 저장된 값 : %u\n", ap); //변수 a의 시작주소값 출력
printf("ap자체의 주소값 : %u\n", &ap); //vhdlsxj //포인터변수 ap의 시작주소값 출력

포인터 정리

int a = 10; //int형 변수 선언, 정수값 10으로 초기화
int *ap = &a; //int포인터변수 선언, a의 시작주소값으로 초기화

4.48    <시작주소값>  2.52
3.주소값 52   ----> 1.정수값 10
포인터변수 ap        int형 변수 a
printf("%d", a);    //a에 저장된 정수값 10
printf("%d", *ap);  //ap(ap의 실체:52)가 가리키는 곳에 저장된 값 10(*ap=&a)
printf("%u", &a);   //a의 시작주소값 52번지
printf("%u", ap);   //ap에 저장된 주소값 52번지
printf("%u", &ap);  //ap의 시작주소값 48번지

연습문제1

  • 포인터를 사용하여 두 변수의 값을 바꾸는 프로그램(=치환 프로그램)

포인터의 필요성

  • 함수들은 독립된 기억공간을 가지므로 다른 함수에 선언된 변수를 사용할 수 있다.

포인터로 다른 함수의 기억공간을 사용

  • assign함수가 main함수의 cheoli변수를 사용하기 위해서는 메모리에서의 위치(포인터)를 알아야 한다.
#include <stdio.h>
void assign();
int main()
{
	int cheoli = 0;
	assign(&cheoli); //포인터를 구해서 전달인자로 넘겨준다.
	printf("함수가 호출된 후에 cheoli에 저장된 값 : %d\n", cheoli); //100출력
	return 0;
}
void assign(int *ip) //포인터변수를 선언하여 포인터를 받는다.
{
	*ip = 100;
}

※ 내가 넘겨주는 타입이 포인터라면 받을려고 하는 변수도 포인터이어야 한다.

함수의 한계를 극복한다.

  • 함수는 전달인자가 많아도 리턴되는 값은 오직 하나이다.
  • 따라서 메인함수에 있는 두 변수의 값을 바꾸는 함수는 포인터를 사용해야 한다.

연습문제2

  • 함수를 호출하여 세 변수의 값을 정렬하는 프로그램

포인터에 관한 중요한 질문

  • 포인터와 포인터변수의 크기는 몇 바이트인가?
    -컴파일러마다 다를 수 있으므로 sizeof연산자로 계산한다.
int in;
int *ip = &in;
printf("int형 변수의 포인터 크기 : %d\n", sizeof(&in));
printf("int형 변수를 가리키는 포인터변수의 크기 : %d\n", sizeof(ip));

-포인터와 포인터변수의 크기는 가리키는 자료형과는 관계없이 항상 같다.(4byte)

char ch;
int in;
double dp;
char *cp = &ch;
int *ip = &in;
double *dp = &db;
printf("%d, %d, %d\n", sizeof(cp), sizeof(ip), sizeof(dp)); //4, 4, 4
printf("%d, %d, %d\n", sizeof(*cp), sizeof(*ip), sizeof(*dp)); //1, 4, 8
  • 포인터와 포인터변수는 자동 형변환이 가능한가?
    -기본자료형을 자동형변환이 가능하나 포인터(변수)는 불가능하다.(형변환 연산자를 사용한 명시적 형변환은 가능)
int *ip; 
double dp = 6.5;
ip = &dp;

※ 컴파일 에러 -> error C2440: '=' : cannot convert from 'double *' to 'int *'

-자동 형변환이 가능하다면 정수값이 저장된 기억공간에서 실수값을 참조하는 오류를 범하게 될 것이다.
-포인터의 형변환 규칙은 함수의 전달인자와 매개변수 사이에도 적용된다.

int in;
                          void func(int *ip);
func(&in);
int형 변수의 포인터  -----> int형 변수를 가리키는 포인터 변수
profile
gy’s portfolio

0개의 댓글