C 8장. 포인터 #include <stdio.h> int main(void) { int num; printf(“Please enter an integer: "); scanf("%d", &num); if ( num < 0 ) printf("Is negative.\n"); printf("num = %d\n", num); return 0; }
학습목표 ■ 포인터란 무엇인지 알아보고, 포인터를 선언하고 사용하는 방법을 알아본다. ■ 포인터를 사용할 때 주의사항을 알아본다. ■ 포인터 연산에 대하여 알아본다. ■ 배열과 포인터의 관계에 대하여 알아본다. ■ 문자열 상수와 문자열 포인터에 대하여 알아본다. 8장. 포인터
목차 8장. 포인터 포인터의 기본 배열과 포인터의 관계 포인터와 문자열 포인터란 포인터 사용 시 주의사항 포인터의 연산 포인터로서의 배열 배열의 원소를 가리키는 포인터 배열과 포인터의 차이점 포인터와 문자열 문자열 상수 문자열 포인터 const 포인터 8장. 포인터
포인터의 개념(1/2) 포인터의 기본 주소(address)를 저장하는 변수 포인터 변수의 크기(주소의 크기)는 시스템에 따라 다르다. 8장. 포인터
포인터의 개념(2/2) 포인터의 기본 포인터 변수는 다른 변수를 가리키는 변수이다. 포인터는 주소를 이용해서 특정 변수에 접근할 수 있도록 도와준다. 8장. 포인터
포인터의 기본 포인터 포인터의 선언(1/2) char*는 char형 변수의 주소, int*는 int형 변수의 주소, double*는 double형 변수의 주소를 저장한다. char*형 변수는 char형 변수를 가리키고, int*형 변수는 int형 변수를 가리키고, double*형 변수는 double형 변수를 가리킨다. 8장. 포인터
포인터의 선언(2/2) 포인터의 기본 포인터 변수의 크기는 포인터 변수가 가리키는 변수의 데이터형에 관계없이 항상 같다. 8장. 포인터
포인터 변수와 포인터형의 크기 포인터의 기본 포인터 8장. 포인터 01: /* Ex08_01.c */ 02: #include <stdio.h> 03: 04: int main(void) 05: { 06: char *pc; 07: int *pi; 08: double *pd; 09: 10: printf("pc의 크기 : %d\n", sizeof(pc)); 11: printf("pi의 크기 : %d\n", sizeof(pi)); 12: printf("pd의 크기 : %d\n", sizeof(pd)); 13: 14: printf("char* 의 크기 : %d\n", sizeof(char*)); 15: printf("short* 의 크기 : %d\n", sizeof(short*)); 16: printf("int* 의 크기 : %d\n", sizeof(int*)); 17: printf("float* 의 크기 : %d\n", sizeof(float*)); 18: printf("double*의 크기 : %d\n", sizeof(double*)); 19: 20: return 0; 21: } 포인터 변수의 선언 포인터 변수 크기 구하기 포인터 형의 크기 구하기 8장. 포인터
포인터의 기본 포인터 포인터의 사용(1/3) 포인터를 사용하려면 주소 구하기 연산자(address-of operator)와 간접 참조 연산자(indirection operator)가 필요하다. 8장. 포인터
포인터의 사용(2/3) 포인터의 기본 주소 구하기 연산자 : & 다음에 나오는 변수의 주소를 구하는 데 사용 & 연산자는 반드시 변수명 앞에만 사용할 수 있으며, 상수나 수식에는 사용할 수 없다. 8장. 포인터
포인터의 기본 포인터 포인터의 사용(3/3) 간접 참조 연산자 : 포인터 변수가 가리키는 변수에 접근해서 값을 읽어오거나 변경하는 데 사용 * 연산자는 반드시 포인터 변수 앞에만 사용할 수 있다. 8장. 포인터
포인터 변수의 선언 및 사용 예 포인터의 기본 포인터 8장. 포인터 01: /* Ex08_02.c */ 02: #include <stdio.h> 03: 04: int main(void) 05: { 06: int x; 07: int *p; 08: 09: p = &x; 10: *p = 10; 11: 12: printf("*p = %d\n", *p); 13: printf("x = %d\n", x); 14: 15: printf("p = %p\n", p); 16: printf("&x = %p\n", &x); 17: 18: printf("&p = %p\n", &p); 19: 20: return 0; 21: } int형 변수의 선언 int*형 변수의 선언 p는 x의 주소 저장 p가 가리키는 변수에 접근 8장. 포인터
이중 포인터 포인터의 기본 포인터 변수의 주소를 저장하는 포인터 변수 이중 포인터가 가리키는 포인터를 이용해서 변수에 접근하려면 **처럼 두 번 간접 참조를 해야 한다. 8장. 포인터
포인터의 기본 포인터 사용시 주의 사항 포인터형과 변수의 데이터형 포인터 변수의 데이터형이 반드시 포인터 변수가 가리키는 변수의 데이터형과 일치해야 한다. 8장. 포인터
잘못된 포인터(1/2) 포인터의 기본 포인터도 변수이므로 반드시 초기화해야 한다. 포인터 사용시 주의 사항 잘못된 포인터(1/2) 포인터도 변수이므로 반드시 초기화해야 한다. 포인터 변수를 초기화하지 않고 사용하면 실행 에러가 발생한다. 널 포인터 : 포인터가 다른 변수를 가리키지 않을 때는 NULL(0)로 초기화한다. 8장. 포인터
잘못된 포인터(2/2) 포인터의 기본 포인터를 안전하게 사용하려면 우선 포인터가 널 포인터인지를 검사한다. 포인터 사용시 주의 사항 잘못된 포인터(2/2) 포인터를 안전하게 사용하려면 우선 포인터가 널 포인터인지를 검사한다. 8장. 포인터
포인터와 +, - 연산(1/2) 배열과 포인터의 관계 포인터의 연산 포인터와 +, - 연산(1/2) p+N은 p가 가리키는 데이터형 N개 크기만큼 증가된 주소가 연산의 결과이다. p-N은 p가 가리키는 데이터형 N개 크기만큼 감소된 주소가 연산의 결과이다. 8장. 포인터
포인터와 +, - 연산(2/2) 배열과 포인터의 관계 ‘포인터-포인터’ 연산은 두 포인터의 차를 구하는 데 사용된다. 포인터의 연산 포인터와 +, - 연산(2/2) ‘포인터-포인터’ 연산은 두 포인터의 차를 구하는 데 사용된다. 8장. 포인터
포인터의 더하기, 빼기 예(1/2) 배열과 포인터의 관계 포인터의 연산 8장. 포인터 01: /* Ex08_03.c */ 02: #include <stdio.h> 03: 04: int main(void) 05: { 06: char ch; 07: char *pc = &ch; 08: 09: int n; 10: int *pi = &n; 11: 12: double d; 13: double *pd = &d; 14: 15: int arr[3]; 16: int i; 17: 18: for(i = 0 ; i < 3 ; i++) 19: printf("pc+%d = %p\n", i, pc+i); 20: char*형 변수의 선언 int*형 변수의 선언 double*형 변수의 선언 char*형에 정수를 더하는 연산 8장. 포인터
포인터의 더하기, 빼기 예(2/2) 배열과 포인터의 관계 포인터의 연산 8장. 포인터 21: for(i = 0 ; i < 3 ; i++) 22: printf("pi+%d = %p\n", i, pi+i); 23: 24: for(i = 0 ; i < 3 ; i++) 25: printf("pd+%d = %p\n", i, pd+i); 26: 27: for(i = 0 ; i < 5 ; i++) 28: printf("&arr[%d]-&arr[0] = %d\n", i, &arr[i]-&arr[0]); 29: 30: return 0; 31: } int*형에 정수를 더하는 연산 double*형에 정수를 더하는 연산 포인터의 차를 구하는 연산 8장. 포인터
포인터와 ++, -- 연산(1/2) 배열과 포인터의 관계 포인터의 연산 포인터와 ++, -- 연산(1/2) 포인터에 대한 증감 연산(++, --)도 포인터형에 의해 연산의 결과가 결정된다. 8장. 포인터
포인터의 증가 연산자 이용 예 배열과 포인터의 관계 포인터의 연산 8장. 포인터 01: /* Ex08_04.c */ 02: #include <stdio.h> 03: 04: int main(void) 05: { 06: int arr[5] = {10, 20, 30, 40, 50}; 07: int *p = &arr[0]; 08: int i; 09: 10: for(i = 0 ; i < 5 ; i++, p++) 11: printf("%d\n", *p); 12: 13: return 0; 14: } int *형 변수의 선언 포인터 변수의 증가 연산 8장. 포인터
포인터로서의 배열(1/2) 배열과 포인터의 관계 인덱스 없이 배열명만 사용하면 배열의 시작 주소를 의미한다. 배열의 시작 주소를 구할 때는 & 없이 배열명만 사용한다. 배열명은 포인터인 것처럼 사용할 수 있다. 인덱스를 사용하는 대신 배열의 시작 주소로 포인터 연산을 하면 배열의 특정 원소에 접근할 수 있다. 8장. 포인터
포인터로서의 배열(2/2) 배열과 포인터의 관계 *(arr+i)는 arr[i]를 의미한다. 배열의 시작 주소에서 int i개 크기만큼 증가된 주소에 있는 값 8장. 포인터
포인터로서의 배열의 사용 예(1/2) 배열과 포인터의 관계 포인터로서의 배열 8장. 포인터 01: /* Ex08_05.c */ 02: #include <stdio.h> 03: 04: int main(void) 05: { 06: int arr[5] = {10, 20, 30, 40, 50}; 07: int i; 08: 09: for(i = 0 ; i < 5 ; i++) 10: { 11: printf("&arr[%d] = %p, ", i, &arr[i]); 12: printf("arr+%d = %p\n", i, arr+i); 13: } 14: 15: for(i = 0 ; i < 5 ; i++) 16: { 17: printf("arr[%d] = %d, ", i, arr[i]); 18: printf("*(arr+%d) = %d\n", i, *(arr+i)); 19: } int 배열의 선언 및 초기화 포인터의 차를 구하는 연산 배열 원소의 주소 구하기 배열 원소의 값 구하기 8장. 포인터
포인터로서의 배열의 사용 예(2/2) 배열과 포인터의 관계 포인터로서의 배열 8장. 포인터 20: 21: return 0; 22: } 8장. 포인터
배열의 원소를 가리키는 포인터(1/2) 배열과 포인터의 관계 배열의 시작 주소로 초기화된 포인터를 이용해서 배열의 모든 원소에 접근할 수 있다. 포인터 변수를 배열 이름인 것처럼 사용할 수 있다. 8장. 포인터
배열의 원소를 가리키는 포인터(2/2) 배열과 포인터의 관계 배열의 원소를 가리키는 포인터는 배열의 어떤 원소든지 가리킬 수 있다. 포인터가 배열의 원소가 아닌 일반 변수를 가리킬 때도 *(p+i) == p[i]는 항상 성립한다. 8장. 포인터
포인터를 배열처럼 사용하는 경우(1/2) 배열과 포인터의 관계 포인터로서의 배열 8장. 포인터 01: /* Ex08_06.c */ 02: #include <stdio.h> 03: 04: int main(void) 05: { 06: int arr[5] = {10, 20, 30, 40, 50}; 07: int * p = arr; 08: int i; 09: 10: for(i = 0 ; i < 5 ; i++) 11: { 12: printf("arr+%d = %p, ", i, arr+i); 13: printf("p+%d = %p\n", i, p+i); 14: } 15: 배열의 시작 주소로 초기화된 포인터 배열 원소의 주소 구하기 8장. 포인터
포인터를 배열처럼 사용하는 경우(2/2) 배열과 포인터의 관계 포인터로서의 배열 8장. 포인터 16: for(i = 0 ; i < 5 ; i++) 17: { 18: printf("arr[%d] = %d, ", i, arr[i]); 19: printf("p[%d] = %d\n", i, p[i]); 20: } 21: 22: return 0; 23: } 배열 원소의 값 구하기 8장. 포인터
배열과 포인터의 차이점 배열과 포인터의 관계 배열이 메모리에 할당되고 나면, 배열의 시작 주소를 변경할 수 없다. 포인터 변수는 값을 변경할 수 있으므로, 포인터 변수에 보관된 주소는 변경할 수 있다. 8장. 포인터
문자열 상수(1/3) 포인터와 문자열 문자열 리터럴은 문자열 리터럴의 주소를 의미한다. 문자열 리터럴은 다른 리터럴과는 달리 메모리에 보관해두고 사용한다. 8장. 포인터
문자열 상수(2/3) 포인터와 문자열 문자열 리터럴은 메모리에 보관하지만 변수처럼 값을 변경할 수는 없다. 값을 읽어볼 수만 있고 변경할 수 없는 특별한 메모리 영역에 할당 문자열 리터럴의 내용을 변경하려고 하면 실행 에러 발생 8장. 포인터
포인터와 문자열 문자열 상수 문자열 상수(3/3) char*형 변수 p가 문자열 리터럴을 가리킬 때, 문자열 리터럴의 내용은 변경할 수 없지만, char*형 변수에 다른 문자열 리터럴의 주소를 대입할 수는 있다. 8장. 포인터
문자열 리터럴의 의미 포인터와 문자열 실행 에러 발생! 문자열 상수 8장. 포인터 01: /* Ex08_07.c */ 02: #include <stdio.h> 03: #include <string.h> 04: 05: int main(void) 06: { 07: char *p = "abcde"; 08: 09: printf("p = %s\n", p); 10: printf("p = %p\n", p); 11: printf("p = %p\n", "abcde"); 12: 13: p[0] = 'A'; 14: strcpy(p, "hello"); 15: 16: return 0; 17: } 문자열 리터럴의 주소로 초기화된 포인터 실행 에러 발생! 실행 에러 발생 8장. 포인터
문자열의 대입 포인터와 문자열 문자 배열에는 문자열을 직접 대입할 수 없다. 문자열 상수 문자열의 대입 문자 배열에는 문자열을 직접 대입할 수 없다. 문자열의 내용을 변경하려면 = 연산자 대신 strcpy 함수를 이용해야 한다. 8장. 포인터
문자열의 비교 포인터와 문자열 문자열의 내용을 비교할 때 == 연산자를 사용하면 안된다. 문자열 상수 문자열의 비교 문자열의 내용을 비교할 때 == 연산자를 사용하면 안된다. 문자열의 내용을 비교하려면 == 연산자 대신 strcmp 함수를 이용해야 한다. 8장. 포인터
포인터와 문자열 문자열 포인터 문자열 포인터(1/2) char*형 변수에는 문자열 리터럴의 주소를 저장할 수도 있고, 문자 배열의 주소를 저장할 수도 있다. char*형 변수가 문자열 리터럴를 가리키는지 문자 배열을 가리키는지에 따라, 실행 에러가 발생할 수도 있다. 8장. 포인터
문자열 포인터(2/2) 포인터와 문자열 변경 가능한 문자열을 가리킬 때는 char*형을 사용한다. 변경할 수 없는 문자열을 가리킬 때는 const char*형을 사용한다. 8장. 포인터
const 포인터 포인터와 문자열 포인터 변수를 선언할 때도 const 키워드를 사용할 수 있다. 8장. 포인터
const 키워드가 데이터형 앞에 있는 경우 포인터와 문자열 포인터가 가리키는 변수의 값을 읽어볼 수만 있고 변경할 수 없다. 포인터 변수 자신의 값(주소)은 변경할 수 있다. 8장. 포인터
const 키워드가 포인터 변수명 앞에 있는 경우 포인터와 문자열 const 포인터 const 키워드가 포인터 변수명 앞에 있는 경우 포인터 변수 자신의 값(주소)을 변경할 수 없다. 포인터가 가리키는 변수의 값은 변경할 수 있다. 8장. 포인터
const 키워드가 양쪽 모두에 있는 경우 포인터와 문자열 포인터가 가리키는 변수의 값도 변경할 수 없고 포인터 변수 자신의 값(주소)도 변경할 수 없다. 8장. 포인터
포인터의 기본 학습정리 포인터 : 다른 변수의 주소를 저장하는 변수 포인터의 선언 : 데이터 형, *, 변수명이 필요하다. int * p; 포인터의 사용 : 변수의 주소를 구할 때는 주소 구하기 연산자 &를 이용하고, 포인터가 가리키는 변수에 접근할 때는 간접 참조 연산자 *를 이용한다. int *p = &x; *p = 10; 포인터 사용 시 주의사항 : 포인터 변수는 포인터가 가리키는 변수의 데이터 형과 일치하도록 선언해야 한다. 잘못된 포인터를 사용하는 것은 위험하므로, 포인터가 가리키는 변수가 없을 때는 NULL을 저장한다. 8장. 포인터
포인터와 배열의 관계 학습정리 포인터로서의 배열 : 배열의 이름은 배열의 시작 주소이므로 포인터처럼 사용할 수 있다. arr[i]는 *(arr + i)와 같다. 배열의 원소를 가리키는 포인터 : 배열의 원소를 가리키는 포인터는 배열처럼 사용할 수 있다. *(p + i)는 p[i]와 같다. 배열과 포인터의 차이점 : 배열의 시작 주소는 변경할 수 없지만 포인터에 저장된 주소는 변경할 수 있다. 8장. 포인터
포인터와 문자열 학습정리 문자열 리터럴 : 문자열 리터럴의 주소를 의미 char *p = "abcde"; p에는 "abcde"의 주소 저장 문자열 포인터 : 문자열 포인터가 문자열 리터럴을 가리킬 때는 문자열의 내용을 변경할 수 없지만, 문자열 포인터가 문자 배열을 가리킬 때는 문자열의 내용을 변경할 수 있다. const 포인터 : 포인터를 선언할 때 const의 위치에 따라서 의미가 다르다. const char *p = str1; p가 가리키는 str1의 내용을 변경할 수 없다. char * const p = str1; p에 저장된 주소를 변경할 수 없다. const char * const p = str1; p가 가리키는 문자열도 변경할 수 없고 p도 변경할 수 없다. 8장. 포인터
8장. 포인터 수고하셨습니다. 질문 있습니까? NEXT Chapter 9장. 구조체