C언어를 리뷰하기전 다음 3가지를 알면 c언어를 이해하는데 큰 도움이 됩니다.
- 컴퓨터의 메모리는 데이터를 보관하는 장소
- 바이트(8bits)단위로 주소가 지정됨
- 모든 변수는 주소를 가짐
예를들어 정수는 4바이트를 할당되고, 메모리의 4바이트 공간에 sum변수가 할당됩니다.
이때 가장 앞의 번지가 그 변수의 주소가 됩니다.
포인터는 메모리 주소를 값으로 가지는 변수이고, 포인터 변수는 다음과 같이 선언됩니다.
type-name * variable-name
variable-name은 선언된 포인터 변수의 이름이며, *는 variable-name이 포인터 변수임을 표시하고, type-name은 포인터 변수 variable-name에 저장될 주소에 저장될 데이터의 유형을 지정합니다. ex) int * ptr;
연산자 &는 변수로부터 그 변수의 주소를 추출하는 연산자입니다.
위 예제를 살펴보면 정수형 변수c가 선언되고 c에 12라는 값이 저장되었습니다. 또한 정수형 포인터 변수 p가 선언되었고 그 변수 p에 변수 c의 주소값이 저장되었습니다. 즉 , c의 주소값을 갖는 포인터형 변수 p도 1028번지 메모리 상에 저장되었음을 알 수 있습니다.
또다른 예를 살펴보면 *연산자가 두가지 의미를 나타낸다는 것을 인지합시다.
*기호가 어떤 변수를 선언할때 변수명 앞에 등장하면 이는 포인터 변수를 나타내는것
변수의 선언이 아니라 어떤 포인터 변수앞에 *가 쓰이면, 포인터 변수가 저장하고 있는 주소 그주소에 저장된 값을 나타낸다.
int *ip;의 의미는 ip라는 정수형 포인터형 변수를 의미하고,
ip = &x;의 의미는 정수형 포인터 변수 ip에 정수형 변수 x의 주소값 1028이라는 것이 저장된 상태입니다.
y = *ip의 의미는 ip라는 포인터 변수의 값(주소값)이 아니라 ip라는 포인터형 변수가 가지고있는 주소(1028) 즉, 그 주소에 저장된 값을 의미합니다. 즉, *ip는 1 이다. 1이라는 값을 변수 y에 저장해라는 의미이다. y = 1 동일합니다.
*ip = 0 의미는 ip라는 포인터변수가 현재 저장하고 있는 그 주소에 0을 써라 즉, 1028번지에 0을 써라 변수 x에 0을 써라는 의미다.
포인터와 배열
포인터와 배열은 매우 긴밀히 연관되어 있다.
예를 들어 다음과 같이 선언된 배열 a가 있다고 하자.
배열 크기 10 배열의 타입은 정수 각각의 칸에는 정수가 저장된다.
배열의 이름은 배열의 시작 주소를 지정하는 포인터 변수이다.
배열의 포인터 변수는 그 값을 수정할 수 없다.
예제 코드를 살펴보면
#include <stdio.h>
int calculate_sum(int array[]);
int main() {
int sum, i, average;
int num[10];
for (i = 0; i < 10; i++)
scanf_s("%d", &num[i]);
sum = calculate_sum(num);
average = sum / 10;
printf("%d\n", average);
return 0;
}
//
//int calculate_sum(int array[]) {
// int sum, i;
// sum = 0;
// for (i = 0; i < 10; i++)
// sum = sum + array[i];
// return sum;
//}
int calculate_sum(int *array) {
int sum, i;
sum = 0;
for (i = 0; i < 10; i++)
sum = sum + array[i];
return sum;
}
위 코드는 10개의 값을 키보드로 입력받아 배열의 값을 정의하고 그 평균을 구하는 코드입니다.
calculate_sum함수에서 int array[] 배열 자체를 받아도 되지만 *array를 써도 무방합니다. 왜냐하면 *array의 의미는 전과 같이 array라는 배열의 주소에 있는 값을 의미하기 때문입니다.
즉 *array로 받더라도 똑같이 실행하다. 배열의 이름은 그 배열의 첫번째칸의 포인터주소이므로 가능하다.
(괄호 치는 이유는 *연산자가 +연산자보다 우선순위이기 때문입니다.)
포인터 arithmetic
*a와 a[0]은 완전히 동일한 의미입니다.
또한 a[1]은 *(a+1)과 동일하고, a[i]는 *(a+i)와 동일합니다..
여기서 a=1000라면 a+1은 1001이 되지 않고 c언어에서는 1004됩니다.. why? > a가 정수형 포인터 변수이고 하나의 정수가 4바이트로 표현이되는거라면 *(a+1)은 그 다음 정수의 주소가 되도록 합니다.. 이것을 포인터 arithmetic이라 부릅니다.
밑의 코드를 보면서 이해해 봅시다.
#include <stdio.h>
int main() {
int data[] = { 1,2,3 };
int* p = &data[0];
printf("%d %x\n", p, p);
printf("%d %x\n", p+1, p+1);
printf("%d %x\n", p+2, p+2);
}
====================================================
11533208 affb98
11533212 affb9c
11533216 affba0
결괏값 역시 4씩 늘어나는것을 알 수 있습니다. 다양한 변수형을 적용 시켜 봅시다.
#include <stdio.h>
int main() {
int data[] = { 1,2,3 };
char data2[] = { 'a','b','c' };
long long data3[] = { 1,2,3 };
int* p = &data[0];
char* q = &data2[0];
long long* r = &data3[0];
printf("%d %x\n", p, p);
printf("%d %x\n", p+1, p+1);
printf("%d %x\n\n", p+2, p+2);
printf("%d %x\n", q, q);
printf("%d %x\n", q + 1, q + 1);
printf("%d %x\n\n", q + 2, q + 2);
printf("%d %x\n", r, r);
printf("%d %x\n", r + 1, r + 1);
printf("%d %x\n\n", r + 2, r + 2);
}
======================================================
16120292 f5f9e4
16120296 f5f9e8
16120300 f5f9ec
16120280 f5f9d8
16120281 f5f9d9
16120282 f5f9da
16120248 f5f9b8
16120256 f5f9c0
16120264 f5f9c8
정수형은 4바이트 , 문자형은 1바이트 long long형은 8바이트를 차지하는것을 알 수 있습니다.
'Language > 자료구조' 카테고리의 다른 글
[5] C review < 전화번호부 알고리즘 version2.0 > (0) | 2021.11.22 |
---|---|
[4] C review < 전화번호부 알고리즘 version1.0 > (0) | 2021.11.22 |
[3] C review < 문자열 응용> (0) | 2021.11.16 |
[2] C review < 문자열 > (0) | 2021.11.15 |
[1] C review < 동적메모리 할당 > (0) | 2021.11.15 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!