Chater 1. C 언어 개념 : 포인터, 동적 할당, 문자열

Date:     Updated:

카테고리:

태그:

권오흠 교수님의 유튜브 강의 영리한 프로그래밍을 위한 알고리즘 강좌 를 듣고 정리한 필기입니다. 😀

Chapter1. 자료구조를 위한 C 언어 지식

🔔 포인터

메모리

  • 데이터를 보관 하는 장소
  • 메모리 1 칸당 8bit = 1 byte의 데이터를 담을 수 있다.
  • 32bit 컴퓨터 환경
    • 주소 0 번지 ~ \(2^{32}-1\) 번지까지 있는, 즉 \(2^{32}\) 칸의 크기를 가진 메모리
      • 👉 메모리의 총 크기 = \(2^{32}\) × 1 byte = 대략 42억 byte = 대략 4 GB
    • 메모리 주소값을 비트로 표현한다면 32bit 짜리여야 한다. 메모리는 총 \(2^{32}\) 칸을 가지니까!
    • 32bit 컴퓨터는 메모리 1 칸을 처리하기 위해 한번에 32 bit 를 읽어 들인다.
      • 메모리의 주소를 읽어야 하니까!
    • 포인터의 크기는 32 bit = 4 byte.
  • 64bit 컴퓨터 환경
    • 주소 0 번지 ~ \(2^{64}-1\) 번지까지 있는, 즉 \(2^{64}\) 칸의 크기를 가진 메모리
      • 👉 메모리의 총 크기 = \(2^{64}\) × 1 byte = 대략 16 EB
    • 메모리 주소값을 비트로 표현한다면 64bit 짜리여야 한다. 메모리는 총 \(2^{64}\) 칸을 가지니까!
    • 64bit 컴퓨터는 메모리 1 칸을 처리하기 위해 한번에 64 bit 를 읽어 들인다.
      • 메모리의 주소를 읽어야 하니까!
    • 포인터의 크기는 64 bit = 8 byte.


포인터 정의

포인터 : 메모리의 주소를 값으로 가지는 변수.

  • 포인터의 크기는 int* 이든 double* 이든 언제나 4byte다. (32bit 컴퓨터 기준) ⭐
    • 메모리의 주소는 32bit = 4byte 이기 때문!
  • & : 변수 앞에 붙이면 그 변수의 주소값을 리턴한다.
  • *포인터변수 : 간접 참조. 그 포인터가 담고 있는 주소값에 있는 데이터.
int a = 12;
int b = 1;

int * p;
p = &a;

b = *p;
*p = 3;
  • 포인터 p 는 int 데이터를 담는 공간의 주소값만 가질 수 있다.
  • a 의 주소값이 포인터 p 에 들어간다.
  • *p : p가 담고 있는 주소값에서 담고 있는 실제 데이터. 즉 a 값
  • b 에 a 값을 대입한다. 12가 됨.
  • a 에 3 을 대입한다.


포인터와 배열

int a[10];
  • 배열의 이름이 되는 a에는 배열의 첫번째 원소의 주소가 저장되는 상수 포인터 변수다.
    • 주소값을 변경할 수 없다.
      • 마치 int * ptr const 타입.
        • 간접참조로 값을 변경하는 것은 가능하나 (즉 배열의 원소를 변경하는 것은 가능하나)
        • 주소값, 즉 포인터 값 자체를 바꿀 순 없다.
#include <stdio.h>

int calculate_sum(int * array)
{
    int sum = 0;
    for (int i = 0; i < 10; i++)
        sum = sum + array[i];

    return sum;
}

int main(void)
{
  int sum, average;
  int num[10];

  for (int i = 0; i < 10; i++)
      scanf("%d", &num[i]);
  sum = calculate_sum(num);
  average = sum / 10;
  printf("%d\n", average);

  return 0;
}
  • 배열의 이름 num의 값, 즉 배열 num의 첫번째 원소의 주소값을 인수로 넘긴다.
  • num값이 복사되어 매개 변수 array에 복사된다.
    • 배열 이름(int * ptr_A const)은 일반 포인터(int * ptr_B)에 복사될 수 있으며 그 일반 포인터로 [] 연산자를 통해 원소에 간접 참조할 수 있게 된다.
      • array 포인터로 복사 받은 num의 주소값을 통해 num의 원소들에 접근하고 수정할 수 있게 된다. array[i]
    • cf) 간접 참조로 값을 변경할 수는 없지만 포인터의 주소값 변경은 가능한 const int * ptr_A 같은 포인터는 일반 포인터(int * ptr_B)에 복사될 수 없다.


포인터 연산

a 가 배열 이름이라고 할 때

*a = a[0]
a = &a[0]

*(a + 3) = a[3]
a + 3 = &a[3] 
int a = 1;
int * ptr1 = &a;

double d = 3.14;
double * ptr2 = &d;

포인터 연산 규칙 : 포인터에 1 을 더한 다는 의미는 진짜 1 을 더한다는게 아니라 그 다음 주소를 가리키는 것이다. C/C++ 만의 규칙임!

  • 만약 ptr1 값이 0x0A 라면 ptr1 + 1 은 0x0B 가 되는 것이 아닌 0x0E 가 된다.
    • int 는 4 byte 라서 int 데이터 하나가 메모리를 4 칸 차지하기 때문이다.
    • 따라서 다음 int 데이터는 4 칸 뒤이므로
      • int 포인터 + 1 은 사실 주소값에 4 를 더해주는 것이나 마찬가지다
  • 만약 ptr2 값이 0x00 라면 ptr2 + 1 은 0x01 가 되는 것이 아닌 0x08 가 된다.
    • double 는 8 byte 라서 double 데이터 하나가 메모리를 8 칸 차지하기 때문이다.
    • 따라서 다음 double 데이터는 8 칸 뒤이므로
      • double 포인터 + 1 은 사실 주소값에 8 를 더해주는 것이나 마찬가지다

위의 규칙 때문에 a[i] = *(a + i) 가 성립하게 됨.


🔔 동적 메모리 할당


🔔 문자열



🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

댓글남기기