본문 바로가기
C/C 문법

혼자 공부하는 C언어 (9~10강)

by Sein_ 2025. 9. 6.
728x90
1. 메모리와 변수
2. 포인터
3. 포인터와 배열

 

메모리와 변수

  • 메모리와 변수
    • 메모리는 데이터를 넣고 꺼내 쓰는 공간이다.
    • 메모리의 위치는 주소 값으로 식별할 수 있고 주소 값은 바이트(byte) 단위로 구분된다.
    • int a; => 메모리를 100번지부터 할당한다 가정하면, 100~103번지에 총 4byte로 할당된다.
  • 주소 연산자 (&)
    • &변수명
    • 변수가 할당된 메모리 공간의 시작 주소가 반환된다.
  • 메모리가 할당된 주소
    • 시작주소 + 변수의 크기
  • 메모리 주소의 출력 변환 문자
    • 주소는 보통 16진수로 표기
    • 전용 변환문자 %p (ex. printf("%p", &a); )

 

포인터

  • 포인터
    • 변수의 메모리 주소를 저장하는 변수
    • 포인터가 필요한 경우
      • 임베디드 프로그래밍 시, 메모리에 직접 접근하는 경우 필요
      • 동적 할당한 메모리를 사용하는 경우 포인트가 필요
      • 함수로 여러개의 값을 반환하지 못하기 때문에 이때 포인터를 활용 가능 
    • 포인터 선언
      • 주소 위치에 있는 변수의 자료형 *포인터 변수명; (ex. int *pa;)
    • 포인터에 주소값 할당  
      • 포인터 변수명 = &변수명; (ex. pa = &a;)
    • 포인터 초기화
      • 자료형 *포인터 변수명 = 주소; (ex. int *pa = &a;)
    •  
// 일반 변수 선언
int a;
// 포인터 변수 선언
int *pa;

// 포인터 pa가 변수 a를 가리킬 경우
pa ---> a
// 포인터 변수에 주소값 할당
pa = &a;

//포인터 초기화
int *b = &a

 

  • 간접 참조 / 포인터 연산자 (*)
    • 포인터가 가리키는 변수를 사용할 때 쓰는 연산자
    • 포인터가 가리키는 변수 사용: *포인터
//포인터로 변수 a에 값 대입
*pa = 10;

//변수 a와 *pa 는 동일
*pa == a

//변수 a의 주소와 pa가 가리키는 변수의 주소는 동일
&a == &*pa

 

  • 포인터와 const
    • const 포인터 자료형 *포인터명 = 배열 주소
    • 포인터가 가리키는 변수를 포인터가 간접 참조하여 바꿀 수 없도록 한다,
const int *pa = &a;

*pa = 20; //에러 발생

 

  • 주소 vs 포인터
    • 주소: 변수에 할당된 메모리 저장 공간의 시작 주소값 자체 (상수)
    • 포인터: 주소값을 저장하는 또 다른 메모리 공간 (변수)
  • 포인터의 크기
    • 모든 주소와 포인터의 크기는 가리키는 자료형과 상관없이 동일하다. 
// 자료형과 상관없이 주소는 동일한 크기
char *pc = &ch;		//4byte
int *pi = ∈		//4byte
double *pd = &db;	//4byte
  • 포인터의 대입
    • 포인터의 주소 크기는 자료형과 상관없이 같으나 자료형이 다른 포인터를 대입해선 안된다.
int a = 10;
int *p = &a;

double *pd;
pd = p; // int형 포인터가 double형 포인터로 생각하게되어 int형 포인터에 할당된 영역 외도 사용하게 된다.

 

 

포인터와 배열

  • 배열명(배열 주소)
    • 배열명은 첫 번째 배열 요소의 주소 값으로 첫 번째 배열 요소를 가리킨다.
    • 컴파일러는 배열명을 컴파일 과정에서 첫번째 배열 요소의 주소로 변경한다.
  • 배열 주소의 덧셈
    • 배열명(배열 1번째 요소) + 1 => 배열 2번째 요소의 주소값을 반환
    • 배열 요소에 사용하는 [] 대괄호는 연산식이다.
      • 배열 요소 표현식: ary[1]
      • 포인터 연산식: *(ary + 1)
int ary[3];

*(ary + 0) = 10;	// => ary[0] = 10;
  • 포인터를 이용한 배열요소 제어
    • 포인터에 배열명을 저장하여 제어가 가능하다.
int ary[3];
int *pa = ary;          //포인터에 배열 주소 저장

*pa = 10;               //배열 1번째 요소에 값 10 대입
*(pa + 1) = 20;         //배열 2번째 요소에 값 20 대입
*pa[2] = pa[0] + pa[1];	//배열 3번째 요소에 값 30(10+20) 대입

 

  • 배열명 vs 포인터
    • 배열명은 상수이고 포인터는 변수이다.
    • sizeof 연산 결과가 다르다.
      • sizeof(배열명): 배열의 전체 크기
      • sizrof(포인터): 포인터 하나의 크기
  • 포인터의 뺄셈
    • 배열 요소간의 간격 차이를 반환
    • 포인터 1 - 포인터 2 => (포인터1 주소값 - 포인터2 주소값) / sizeof(자료형)
int *pa = ary;
int *pb = pa + 3;

printf("pb - pa : %u", pb - pa);	//pb - pa : 2
  • 포인터의 관계 연산
    • 배열 요소는 메모리에 순서대로 할당된다.
    • 관계 연산을 통해 배열 요소의 순서를 확인할 수 있다.
int *pa = ary;
int *pb = pa + 3;

if(pa < pb)
{
    printf("%d", *pa);
}

 

 

  • 함수의 배열 처리
    • print_ary(ary);    /    void print_ary(int *pary) { - }
    • 배열명( 주소 값 )을 함수의 인수로 주면 주소 계산을 통해 모든 배열 요소를 사용 가능하다.
    • 매개변수로 배열을 받을 시, 주소를 저장할 포인터를 선언한다.
      • 매개변수 자리에 배열 선언시 저장 공간이 할당되지 않음
      • 배열명은 컴파일 과정에서 포인터로 변환되므로 요소 개수가 무의미
        • (ex. void func(pa[5]){...} => void func(*pa){...} )
  • 배열의 크기(갯수)
    • sizeof(배열명) / sizeof(배열 첫번째 요소); ( ex. sizeof(ary) / sizeof(ary[0]); )
    • 함수 안에서는 sizeof 연산자로 배열의 크기를 알 수 없다. (호출 시 넘겨줄 것)
int main(void)
{
    int ary[5] = {1,2,3,4,5};
    //배열의 갯수 구하기
    int ary_count = sizeof(ary) / sizeof(ary[0]);
    print_ary(ary, ary_count);
}

void print_ary(int *pa, int count)
{
    for (int i=0; i < count; i++)
    {
        printf("%d", pa + i);
    }
}

 

'C > C 문법' 카테고리의 다른 글

혼자 공부하는 C언어 (13~14강)  (0) 2025.09.07
혼자 공부하는 C언어 (11~12강)  (1) 2025.09.07
혼자 공부하는 C언어 (7~8강)  (0) 2025.09.05
혼자 공부하는 C언어 (5~6강)  (0) 2025.09.03
혼자 공부하는 C언어 (3~4강)  (1) 2025.09.02