Chater 1. C 언어 개념 : 포인터, 동적 할당, 문자열
카테고리: Data Structure
태그: C Data Structure Algorithm
권오흠 교수님의 유튜브 강의 영리한 프로그래밍을 위한 알고리즘 강좌 를 듣고 정리한 필기입니다. 😀
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.
- 주소 0 번지 ~ \(2^{32}-1\) 번지까지 있는, 즉 \(2^{32}\) 칸의 크기를 가진 메모리
- 64bit 컴퓨터 환경
- 주소 0 번지 ~ \(2^{64}-1\) 번지까지 있는, 즉 \(2^{64}\) 칸의 크기를 가진 메모리
- 👉 메모리의 총 크기 = \(2^{64}\) × 1 byte = 대략 16 EB
- 메모리 주소값을 비트로 표현한다면 64bit 짜리여야 한다. 메모리는 총 \(2^{64}\) 칸을 가지니까!
- 64bit 컴퓨터는 메모리 1 칸을 처리하기 위해 한번에 64 bit 를 읽어 들인다.
- 메모리의 주소를 읽어야 하니까!
- 포인터의 크기는 64 bit = 8 byte.
- 주소 0 번지 ~ \(2^{64}-1\) 번지까지 있는, 즉 \(2^{64}\) 칸의 크기를 가진 메모리
포인터 정의
포인터
: 메모리의 주소를 값으로 가지는 변수.
- 포인터의 크기는 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)
가 성립하게 됨.
🔔 동적 메모리 할당
🔔 문자열
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글남기기