1-5 포인터와 연산
1. 포인터와 포인터와의 산술 연산
- 주소는 정수 타입의 상수이므로 근본적으로는 산술 연산 가능
- 덧셈과 곱셈 그리고 나눗셈에 의한 연산은 할 수 없는데 이는 잘못된 메모리 참조로 인한
프로세스의 비정상 종료를 최소화하기 위함 - 피연산자를 포인터로 하는 연산자는 오직 뺄셈만 가능
- 뺄셈의 결과는 정수 타입의 값이며 이 값은 두 위치 사이의 차(거리)를 의미
#include <stdio.h>
int str_length(const char *str)
{
char *p = str;
while(*p++)
/* nothing */;
return (p - str) -1;
}
void main()
{
printf("length of hello = %d\n", str_length("hello"));
}
2. 포인터와 정수의 산술 연산
- 피연산자가 포인터와 정수인 경우에는 뺄셈과 덧셈만 가능
- 포인터와 정수와의 연산 결과는 포인터(주소)이며 그 값은 포인터가 가리키는 객체의 크기의 정수배
#include <stdio.h>
typedef struct {
int x, y;
} Point;
void main()
{
char *pChar = 0; printf(" pChar + 1 = %d\n", pChar + 1);
char *pShort = 0; printf(" pShort + 1 = %d\n", pShort + 1);
int *pInt = 0; printf(" pInt + 1 = %d\n", pInt + 1);
long *pLong = 0; printf(" pLong + 1 = %d\n", pLong + 1);
float *pFloat = 0; printf(" pFloat + 1 = %d\n", pFloat + 1);
double pDouble = 0; printf(" pDouble + 1 = %d\n", pDouble + 1);
Point *pPoint = 0; printf(" pPoint + 1 = %d\n", pPoint + 1);
}
- 이와 같이 연산되는 이유는 배열과 같이 연속된 형태의 메모리에서 다음 원소에 올바르게 접근할 수 있도록 하기 위함
3. 포인터와 산술 연산 정리
- 포인터 - 포인터 = 정수(Gap)
- 포인터 + 정수 = 포인터
- 포인터 - 정수 = 포인터(배열의 시작 주소로 부터, 다음의 원소를 자동으로 계산하기 위해)
주소(Address)란? CPU가 특정 메모리에 접근하기 위해 부여한 양의 정수(0을 포함)
임의의 배열 arr의 인덱스 i가 있다고 가정하자.
arr[i] == *(arr + i) => *(arr + sizeof(*arr) * i)
^------- 컴파일러가 알아서 수행함
1-6 배열 포인터
1. 배열의 이름과 주소 연산자
- 배열의 이름은 첫 번째 원소의 시작 주소로 해석(상수)
2. 주소 연산자의 유무
- 배열의 이름에 주소 연산자를 사용하는 것과 하지 않은 것은 완전히 다른 의미
- 아래의 코드는 컴파일러에 따라 다른 오류를 출력함
- C 컴파일러(Visual Studio 2013 기준): warning C4047: '초기화 중' : 'int *의 간접 참조 수준이 'int (*)[3]과(와) 다릅니다.
- C++ 컴파일러(Visual Studio 2013 기준): error C2440: '초기화 중' : 'int (*)[3]에서 'int *'(으)로 변환할 수 없습니다.
void main()
{
int arr[3];
int *p1 = arr; //OK
int *p2 = &arr; //ERROR
}
3. 배열 포인터(Pointer to Array)
- 배열 타입의 주소를 저장하는 포인터를 배열 포인터라고 한다.
- 배열의 타입은 '타입[길이]'
- 배열 포인터의 선언 방법 : 원소의_타입(*변수명)[길이];
void main()
{
int arr[3];
int *p1 = arr; //OK
// int *p2 = &arr; // Warning in C, Error in C++
int(*p2)[3] = &arr;
}
1-7 포인터 배열
1. 포인터 배열
- 원소의 타입을 포인터로 하는 배열을 의미
#include <stdio.h>
void main()
{
char *msg[] = { "hello", "hi", "bye" };
int i;
for(i = 0; i < 3; i++)
printf("msg[%d] = %s\n", i, msg);
}
2. 배열 포인터의 사용
- 명령행의 옵션이 main 함수의 배열 포인터로 전달
#include <stdio.h>
void main(int argc, char *argv[])
{
int i;
for(i = 0; i < argc; i++)
printf("argv[%d] = %s\n", argv[i]);
}
1-8 2차원 배열과 포인터
1. 2차원 배열과 포인터
- 2차원 배열은 원소가 1차원 배열인 1차원 배열임
- 2차원 배열을 가리키는 포인터의 선언은 배열 포인터를 사용해야 함
- 배열 포인터 선언 방법 : 원소의_타입(*변수명)[열의길이];
- 2차원 배열에 대한 포인터는 이중 포인터가 아님
void main()
{
int arr1[6] = { 1, 2, 3, 4, 5, 6 };
int *p1 = arr1;
int arr2[2][3] = { { 1, 2, 3 }. { 4, 5, 6 } };
int(*p2)[3] = arr2;
}
2. 2차원 배열을 사용한 함수 호출
- 포인터를 사용하지 않고 2차원 배열을 함수의 인자로 사용하는 방법
#include <stdio.h>
void display(int arr[][3], int row)
{
int i, j;
for(i = 0; i < row; i++){
for(j = 0; j < 3; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
}
void main()
{
int arr[2][3] = { { 1, 2, 3 }. { 4, 5, 6 } };
display(arr, 2);
}
- 포인터를 사용한 방법
#include <stdio.h>
void display(int(*arr)[3], int row)
{
int i, j;
for(i = 0; i < row; i++){
for(j = 0; j < 3; j++)
printf("%d ", arr[i][j]);
printf("\n");
}
}
void main()
{
int arr[2][3] = { { 1, 2, 3 }. { 4, 5, 6 } };
display(arr, 2);
}
3. 2차원 배열에서의 첨자 연산
- arr[i][j] = (*(arr + i))[j] = *(*(arr + i) + j)
반응형
'Software' 카테고리의 다른 글
Secure Cordng C - Coding Style (0) | 2018.07.20 |
---|---|
Secure Cordng C - 포인터의 개념과 이해 #3 (0) | 2018.07.18 |
Secure Cordng C - 포인터의 개념과 이해 #1 (0) | 2018.07.09 |
DSP란 무엇인가? (1) | 2016.11.21 |
ROM BIOS란? (0) | 2016.05.18 |