카테고리 없음

C언어 강좌(공부) #13장(★포인터★)

바래다주기 2024. 5. 7. 03:32

★13장 포인터★

포인터라는 표현을 잘 사용하지않아서 어렵게 느껴지는것

 

포인터는 메모리를 효과적인 사용하는 기술이다
운영체제와 프로그래밍
변수 -> 메모리 주소

  1. 기계어에서는 변수가 위치한 메모리 주소를 통해 변수 값을 읽거나 변경
  2. 컴퓨터 시스템의 메모리는 운영체제가 관리
  3. 운영체제가 메모리를 관리하는 방법에 따라 프로그래밍 방법도 달라진다

32비트(4바이트) 운영체제 64비트(8바이트) 운영체제

  1. 운영체제에서 실행되는 프로그램을 32비비트용(x86) 프로그램과 64비트용
    프로그램(x64)으로 나누어 개발 가능
  2. 32비트용 프로그램은 32비트 운영체제와 64비트 운영체제에서 모두 동작(64비트는 64비트만 동작가능)

64비트 운영체제의 장단점

장점 : 1. 동시 처리 능력이 좋음
          2. RAM을 16EB(엑사바이트, 2^60)까지 사용가능 (32bit -> 4GB, 2^32)

 

단점 : 1. 기본적인 메모리 사용량이 많음
          2. 32비트 프로그램과 호관하기 위한 모듈까지 관리해야 하기 떄문에 낮은 사양의 컴퓨에 설치하면 손해

         메모리를 비효율적으로 사용할 가능성이 높아지고 호환성이 떨어져 아직까지 많은 개발자들이
         32비트 방식으로 프로그램을 개발

메모리 주소 지정 방식

  1. 운영체제는 메모리 주소를 1바이트 단위로 관리
  2. 32비트 윈도우 운영체제는 0 ~ 4,294,967,295번까지의 주소 사용
  3. 메모리를 사용하려면 반드시 사용할 메모리 주소를 지정해야 함
  4. 메모리를 사용할 때 한 번에 읽거나 젖아할 크기를 명시해야 함

직접 주소 지정 방식

  1. 메모리를 사용할 때 프로그래머가 사용할 메모리 주소를 직접 적는 방식
  2. '102'번지에 1042 라는 값을 2바이트 크기로 저장하겠다

1042가 왜 4와 18로 나누어 질까

  1. 1042 값은 8비트에 저장할 수 없기 때문에 두 개의 8비트에 나누어 저장
  2. 102번지에 18, 103번지에 4가 저장
  3. 윈도우 운영체제는 리틀 엔디언이라는 바이트 정렬을 사용

16진법으로 메모리 형태 표시하기

  1. C언어에서는 2진수를 직접 사용하는 방법을 제공하지 않음
  2. 2진수에 가장 가까운 표현법인 16진수를 주로 사용
  3. 16진수 한 자릿수는 4비트(2^4 = 16)로 표시 가능
  4. 16비트 두 자리는 1바이트를 의미
  5. 16진수로 표현된 숫자는 바이트 단위로 나누기가 편리함

10진수 1042
2진수 0000 0100 0001 0010
10진수 4 18
16진수 0x04 0x12
--------------------------------------------
바이트 단위로 저장 0x0412

 

0x0412 값을 0x00000066번지에 2바이트 크기로 대입하라

 

직접 주소 지정 방식은 주소를 직접 명시한다
간접 주소 지정 방식은 사물함이라는 매개체를 이용해 주소를 간접적으로 명시한다

 

간접 주소 지정 방식
102번지에 4바이트 크기의 '주소'가 저장되어 있는데 이 주소에 가서 '값' 1042를 2바이트 크기로 대입하라

★포인터(Pointer)★

  1. 일반 변수도 주소를 저장할 수 있으나, 저장된 주소의 메모리에 가서 값을 읽거나 저장할 수 있는 기능은 없다
  2. C언어는 갅버 주소 지정 방식으로 동작하는 포인터 문법을 제공
  3. 자신이 사용하고 싶은 메모리의 '주소'를 저장하고 있는 메모리가 포인터
  4. 포인터 변수는 자료형을 선언하지 않아도 무조건 크기가 4바이트

변수가 저장된 메모리 공간의 주소 얻기

  1. 변수의 주소는 프로그램이 실행될 때마다 달라지기 때문에 포인터 변수에 주소를 직접 입력하는 것보다
    프로그램 안에 선언한 다른 변수의 주소를 받아와 사용하는 것이 안전!

short birthday Short형 변수 birthday를 선언
short *ptr 포인터가 가리키는 대상의 크기가 2바이트인 포인터 변수를 선언
ptr = &birthday birthday 변수의 주소를 ptr 변수에 대입
*ptr = 1042 ptr에 저장된 주소에 가서 값 1042를 대입, 즉 birthday = 1042

ptr = *ptr = 의 차이점

ptr = 형태는 포인터 변수에 주소를 저장한다

  1. 포인터 변수에 저장된 주소는 '포인터가 가리키는 대상 메모리'의 시작 주소를 의미

*ptr = 형태는 포인터가 가리키는 대상에 값을 저장한다

  1. 포인터가 가리키는 대상의 값을 변경할 때는 ptr 변수 앞에*(번지 지정) 연산자를 추가하여
    *ptr = 과 같이 사용

포인터를 사용하여 간접 주소 방식으로 값을 대입하는 이유?
L 모든 변수가 같은 함수에 선언되는 것은 아니기 때문
일단 변수는 다른 함수에 있는 변수 사용 불가
포인터 변수는 다른 함수에 선언된 변수의 값을 읽거나 변경 가능

포인트 cosnt 키워드

cosnt 키원드로 주소 변경 실수 막기

  1. cosnt 키워드를 이용하여 피호출자에서 호출자로부터 전달받은 주소를 변경하는 실수를 방지

포인터 변수에서 const 키워드를 사용하여 여러 가지 방법

  1. 포인터 변수는 const 키워드를 사용할 수 있는 위치가 두 곳
  2. 위치를 조합하여 cosnt 키워드를 사용한 포인터 변수를 세 가지 방법으로 선언 가능
  3. 포인터 변수를 다룰 때 실수할 확률이 높기 때문에 cosnt키워드를 적절하게 활용하면 실수로 인한 버그를 줄일 수 있다

int * const p
p 가 가지고 있는 주소를 변경하면 변역할 때 오류 발생

 

cosnt int *p
*p를 사용하여 대상의 값을 변경하여 변역할 때 오류 발생

 

cosnt int * const p
p 가 가지고 있는 주소를 바꾸거나 *p를 사용하여 대상의 값을 바꾸면 변역할 때 오류 발생

포인터 변수의 주소 연산

사용할 메모리의 범위를 기억하는 방법

  1. 시작 주소와 끝 주소를 기억하는 것
  2. 시작 주소와 사용할 크기를 기억하는 것

포인터 변수의 주소 연산

  1. 포인터 변수에 저장된 주소도 일반 변수처럼 사용 가능
  2. 주소를 1만큼 증가시킨다는 의미가 일반 수학 연산과 다르다
  3. 포인터에서 +1의 의미는 그 다음 데이터의 주소를 의미
  4. 포인터 주소 연산 : 포인터 변수가 가진 주소를 연산하면 자신이 가리키는 대상의 크기만큼 연산