쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.

Slides:



Advertisements
Similar presentations
1.1 구조체란 1.2 중첩 구조체 1.3 구조체와 배열 1.4 구조체와 포인터 1.5 구조체와 함수 1.6 공용체와 열거형.
Advertisements

1 08 배열. 한국대학교 객체지향연구소 2 C 로 배우는 프로그래밍 기초 2 nd Edition 배열  동일한 자료유형의 여러 변수를 일괄 선언  연속적인 항목들이 동일한 크기로 메모리에 저장되는 구조  동일한 자료 유형이 여러 개 필요한 경우에 이용할 수 있는.
포인터란? 사전적 의미로써 지시자 혹은 가리키는 것으로 풀이할 수 있으나, C프로그래밍 언어에서는 메모리의 주소를 저장하는 변수이다. 포인터 자체가 하나의 변수이기 때문에 포인터도 메모리 내에서 선언이 되며 일반 상수를 저장하는 변수가 아닌 주소값을 저장하는 변수라는 점에서.
ㅎㅎ 구조체 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스 구조체 배열.
ㅎㅎ 구조체 C++ 프로그래밍 기초 : 객체지향의 시작 구조체 사용하기 함수 매개변수로서의 구조체 구조체 포인터와 레퍼런스
슬라이드 1~21까지는 각자 복습! 슬라이드 22부터는 수업시간에 복습
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express Slide 1 (of 27)
Power C++ 제6장 포인터와 문자열.
제 9 장 포인터.
배열, 포인터 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원 E304호,
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express.
제14장 동적 메모리.
Chapter 14 포인터.
쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express.
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
제 9 장 구조체와 공용체.
-Part2- 제3장 포인터란 무엇인가.
윤 홍 란 포인터 윤 홍 란
C 8장. 포인터 #include <stdio.h> int main(void) { int num;
C로 쉽게 풀어쓴 자료구조 © Copyright 생능출판사 2005
자료 구조: Chapter 3 (2)구조체, 포인터
컴퓨터의 기초 제 4강 - 표준 입출력, 함수의 기초 2006년 4월 10일.
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
개정판 누구나 즐기는 C언어 콘서트 제9장 포인터 출처: pixabay.
윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 12. 포인터의 이해.
제 6장. 생성자와 소멸자 학기 프로그래밍언어및실습 (C++).
연산자 대입 연산자 산술 연산자 관계 연산자 논리 연산자 비트 연산자 콤마 연산자 축약 연산자 sizeof 연산자
쉽게 풀어쓴 C언어 Express 제17장 동적메모리와 연결리스트 C Express Slide 1 (of 13)
5장. 참조 타입.
C++ 프로그래밍 년 2학기 전자정보공학대학 컴퓨터공학부.
C 프로그래밍.
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
포인터 활용 포인터 활용.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express.
8장 함수 함수의 필요성 라이브러리 함수와 사용자 정의 함수 함수의 정의, 원형, 호출 배열을 함수 인자로 전달 재귀호출.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express.
컴퓨터 프로그래밍 기초 #02 : printf(), scanf()
14장. 포인터와 함수에 대한 이해.
11장. 1차원 배열.
C 8장. 포인터 #include <stdio.h> int main(void) { int num;
처음으로 배우는 C 프로그래밍 제4부 복합 데이터 형 제 8 장 배열, 주소, 포인터.
13. 포인터와 배열! 함께 이해하기 IT응용시스템공학과 김 형 진 교수.
3장 상수 변수 기본 자료형 키워드와 식별자 상수와 변수 기본 자료형 형변환 자료형의 재정의.
쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express Slide 1 (of 22)
상수와 기본 자료형.
19. 함수 포인터와 void 포인터.
3장. 변수와 연산자 교안 : 전자정보통신 홈페이지 / 커뮤니티/ 학술세미나
포인터 1차원 배열과 포인터 2차원 배열과 포인터 문자열 배열과 포인터 포인터 배열
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
2장. 변수와 타입.
제 1 강.
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
컴퓨터 프로그램 제2,3장 간단한 C 프로그램 김 문 기.
컴퓨터 프로그래밍 기초 - 5th : 조건문(if, else if, else, switch-case) -
컴퓨터 프로그래밍 기초 - 8th : 함수와 변수 / 배열 -
8주차: Strings, Arrays and Pointers
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
제 6 장 함수(functions).
7주차: Functions and Arrays
컴퓨터 프로그래밍 기초 - 9th : 배열 / 포인터 -
Summary of Pointers and Arrays
Numerical Analysis Programming using NRs
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
어서와 C언어는 처음이지 제21장.
개정판 누구나 즐기는 C언어 콘서트 제13장 동적 메모리 출처: pixabay.
13. 포인터와 배열! 함께 이해하기.
Pointers summary.
2019 2학기 9장 배열과 포인터 1. 주소, 주소연산자(&) 2. 포인터, 역참조연산자(*) 3. 배열과 포인터.
Presentation transcript:

쉽게 풀어쓴 C언어 Express 제11장 포인터 C Express

이번 장에서 학습할 내용 이번 장에서는 포인터의 기초적인 지식을 학습한다. 포인터란? 변수의 주소 포인터의 선언 간접 참조 연산자 포인터 연산 포인터와 배열 포인터와 함수

포인터란? 포인터(pointer): 주소를 가지고 있는 변수 1004 1005 1003 1006 1002 1001 1007 영화관 1003 1006 1002 1001 포인터(pointer) 1007

메모리의 구조 변수는 메모리에 저장됨 메모리는 바이트 단위로 액세스 가능 0번지, 100번지

변수와 메모리 변수의 크기에 따라서 차지하는 메모리 공간이 다름 char 형: 1바이트; int 형: 4바이트; … 10 69 int i = 10; char c = 69; float f = 12.3F; 10 69 12.3 변수값 변수명 i c f 주소

주소 연산자 & &i &c &f & : 변수의 주소를 계산하는 연산자 변수 i의 주소: &i 69 10 12.3 i c f 변수값 변수명 i c f 주소 &i &c &f

변수의 주소 int main(void) { int i = 10; char c = 69; float f = 12.3F; printf("i의 주소: %u\n", (unsigned)&i); // 변수 i의 주소 출력 printf("c의 주소: %u\n", (unsigned)&c); // 변수 c의 주소 출력 printf("f의 주소: %u\n", (unsigned)&f); // 변수 f의 주소 출력 return 0; } i의 주소: 1245024 c의 주소: 1245015 f의 주소: 1245000

포인터 변수 int i = 10; int *p; // 정수 포인터 변수 선언 p = &i; // p는 i를 가리킴 int *p = &i; // 정수 포인터 변수 선언 및 초기화

포인터 변수 pc pf pd A 36.5 3.141592 d f c char c = 'A'; // char 형 변수 c float f = 36.5F; // float 형 변수 f double d = 3.141592; // double 형 변수 d char *pc = &c; // char 형을 가리키는 포인터 변수 pc float *pf = &f; // float 형을 가리키는 포인터 변수 pf double *pd = &d; // double 형을 가리키는 포인터 변수 pd pc pf pd A 36.5 3.141592 d f c

간접 참조 연산자 * * : 포인터가 가리키는 대상을 참조하는 연산자 int i = 10; int *p = &i; printf("%d", *p);

& 연산자와 * 연산자

포인터 예제 i p 3000 #include <stdio.h> int main(void) { int i = 3000; int *p = &i; // 변수와 포인터 연결 printf("i = %d\n", i); // 변수의 값 출력 printf("&i = %u\n", (unsigned)&i); // 변수의 주소 출력 printf("*p = %d\n", *p); // 포인터를 통한 간접 참조 값 출력 printf("p = %u\n", (unsigned)p); // 포인터의 값 출력 return 0; } 3000 i p i = 3000 &i = 1245024 *p = 3000 p = 1245024

포인터 예제 x y p 10 20 #include <stdio.h> int main(void) { int x = 10, y = 20; int *p; p = &x; printf("p = %u\n", (unsigned)p); printf("*p = %d\n\n", *p); p = &y; printf("*p = %d\n", *p); return 0; } 20 y p 10 x p = 1245052 *p = 10 p = 1245048 *p = 20

포인터 예제 i = 10 i = 20 #include <stdio.h> int main(void) { int i = 10, *p; p = &i; printf("i = %d\n", i); *p = 20; return 0; } i = 10 i = 20

포인터 사용시 주의점 초기화되지 않은 포인터를 사용하면 안 됨 NULL 포인터: 아무것도 가리키고 있지 않는 포인터 int *p; // p는 초기화되어 있지 않음 *p = 100; // 위험! NULL 포인터: 아무것도 가리키고 있지 않는 포인터 #define NULL 0 아무것도 가리키고 있지 않을 경우, 포인터를 NULL로 설정 p = NULL; p = 0; if (p == NULL) … // p가 아무것도 가리키지 않으면 if (p == 0) … if (!p) … if (p != NULL) … // p가 무엇이든 가리키고 있으면 if (p != 0) … if (p) …

포인터 사용시 주의점 i pd 포인터의 타입과 변수의 타입은 일치해야 함 double * int #include <stdio.h> int main(void) { int i; double *pd; pd = &i; // double 형 포인터에 int 형 변수의 주소 대입 // 형변환: int *  double * -- C: warning, C++: error *pd = 36.5; return 0; } pd double * i int

포인터 연산 포인터++, 포인터--, 포인터 ± 정수: 포인터가 가리키는 대상의 크기(포인터 타입의 크기)만큼 증감/덧셈/뺄셈 수행 포인터 타입 ++연산 후 증가되는 값 char 1 short 2 int 4 float double 8 101 100 p++ 102 104 p: int* 101 100 p++ 102 104 108 p: double * 101 100 p-- 102 104 96 p: int* 101 100 p + 2 102 104 108 p: int* 101 100 p-- 102 104 92 p: double * 101 100 p + 2 102 104 116 p: double *

포인터 연산 char *pc int *pi  pi - 1 pc - 2  pc - 1  pc   pi pc + 1  96  pi - 1 97 pc - 2  98 pc - 1  99 pc  100  pi pc + 1  101 pc + 2  102 103 104  pi + 1 105 106 107 108  pi + 2 109 110 111 char *pc int *pi

포인터 연산 #include <stdio.h> int main(void) { char *pc; int *pi; double *pd; pc = (char*)10000; pi = (int*)10000; pd = (double*)10000; printf("증가 전 pc = %d, pi = %d, pd = %d\n", (int)pc, (int)pi, (int)pd); pc++; pi++; pd++; printf("증가 후 pc = %d, pi = %d, pd = %d\n", (int)pc, (int)pi, (int)pd); return 0; } 증가 전 pc = 10000, pi = 10000, pd = 10000 증가 후 pc = 10001, pi = 10004, pd = 10008

간접 참조 연산자와 증감 연산자 *p++  *(p++) : p를 나중에 증가 v = *p++;  v = *p; p++; // p를 나중에 증가 v = (*p)++;  v = *p; (*p)++; // *p를 나중에 증가 v = *++p;  ++p; v = *p; // p를 먼저 증가 v = ++*p;  ++(*p); v = *p; // *p를 먼저 증가

간접 참조 연산자와 증감 연산자 i = 10, pi = 0012FF60 i = 11, pi = 0012FF60 #include <stdio.h> int main() { int i = 10; int *pi = &i; printf("i = %d, pi = %p\n", i, pi); (*pi)++; *pi++; return 0; } i = 10, pi = 0012FF60 i = 11, pi = 0012FF60 i = 11, pi = 0012FF64

포인터의 형변환 #include <stdio.h> int main() { char buffer[8]; double *pd; int *pi; pd = (double*)buffer; // char *  double * *pd = 3.14; printf("%f\n", *pd); pi = (int*)buffer; // char *  int * *pi = 123; *(pi + 1) = 456; printf("%d %d\n", *pi, *(pi + 1)); return 0; } 명시적으로 포인터 타입 변경 가능 double d, *pd = &d; int *pi = (int*)pd; (주의: 위험) 3.140000 123 456

포인터와 배열 배열과 포인터는 아주 밀접한 관계를 가지고 있음 배열을 포인터처럼 사용 가능 배열의 이름은 배열을 가리키는 포인터로 사용 가능 int a[5]; a  &a[0] a + 1  &a[1] *(a + 1)  a[1] 포인터를 배열처럼 사용 가능 포인터에 인덱스 표기법 사용 가능 int a[5], *p = a; p[1]  *(p + 1)  a[1] 배열 포인터

포인터와 배열 #include <stdio.h> int main() { int a[] = { 10, 20, 30, 40, 50 }; printf("&a[0] = %u\n", (unsigned)&a[0]); printf("&a[1] = %u\n", (unsigned)&a[1]); printf("&a[2] = %u\n", (unsigned)&a[2]); printf("a = %u\n", (unsigned)a); return 0; } &a[0] = 1245008 &a[1] = 1245012 &a[2] = 1245016 a = 1245008

배열을 포인터처럼 사용 #include <stdio.h> int main(void) { int a[] = { 10, 20, 30, 40, 50 }; printf("a = %u\n", (unsigned)a); printf("a + 1 = %u\n", (unsigned)(a + 1)); printf("*a = %d\n", *a); printf("*(a + 1) = %d\n", *(a + 1)); return 0; } a = 1245008 a + 1 = 1245012 *a = 10 *(a + 1) = 20

포인터를 배열처럼 사용 #include <stdio.h> int main() { a[0]=10 a[1]=20 a[2]=30 p[0]=10 p[1]=20 p[2]=30 a[0]=60 a[1]=70 a[2]=80 p[0]=60 p[1]=70 p[2]=80 #include <stdio.h> int main() { int a[] = { 10, 20, 30, 40 }; int *p; p = a; printf("a[0]=%d a[1]=%d a[2]=%d \n", a[0], a[1], a[2]); printf("p[0]=%d p[1]=%d p[2]=%d \n\n", p[0], p[1], p[2]); p[0] = 60; p[1] = 70; p[2] = 80; printf("p[0]=%d p[1]=%d p[2]=%d \n", p[0], p[1], p[2]); return 0; }

포인터와 배열의 유사점 int a[5]; int a[5], *p = a; *(a + i)  a[i] a  a + 0  &a[0] int *p; p[i]  *(p + i) &p[i]  p + i int a[5], *p = a; a[i] ≡ p[i] ≡ *(a + i) ≡ *(p + i) &a[i] ≡ &p[i] ≡ a + i ≡ p + i

포인터와 배열의 차이점 배열 이름은 상수 함수의 인자에서는 배열처럼 선언된 것도 실제로는 포인터 int a[5], *p; p = a; // O, p = &a[0] p++; // O Cf.) int n; n = 3; n++; // O a = p; // X a++; // X Cf.) int n; 3 = n; 3++; // X sizeof a : 20 sizeof p : 4 (또는 8) 함수의 인자에서는 배열처럼 선언된 것도 실제로는 포인터 void f(int a[10]) { int *p; … }  void f(int *a) { int *p; … } a = p; // O a++; // O sizeof a : 4 (또는 8)

포인터의 관계 연산과 산술 연산 p, q가 같은 타입의 포인터이고 n이 정수일 경우 !p, p == NULL, p != NULL p == q, p != q p > q, p >= q, p < q, p <= q p ± n, p++, p-- p - q : 연산 결과는 정수 p + q : 허용되지 않음 int a[5], *p = a + 1, *q = a + 5; p == q : 0 (False) p < q : 1 (True) p + 2 : &a[3] q – p : 4 (5 – 1) p – q : -4 (1 – 5) int *r = (p + q) / 2; // X int *r = p + (q – p) / 2; // O  p + 2  &a[3] a[0] a[1] a[2] a[3] a[4] a[5] p p+2 q

포인터 사용의 장점 인덱스 표기법보다 빠름 인덱스 표기법 사용 포인터 사용 int get_sum1(const int a[ ], int n) { int i, sum = 0; for (i = 0; i < n; i++) sum += a[i]; return sum; } int get_sum2(const int *p, int n) { const int *end = p + n; int sum = 0; while (p < end) sum += *p++; return sum; } 인덱스 표기법 사용 포인터 사용

배열 역순 출력 #include <stdio.h> void print_reverse(const int a[ ], int n); int main( ) { int a[ ] = { 10, 20, 30, 40, 50 }; print_reverse(a, sizeof a / sizeof a[0]); return 0; } void print_reverse(const int a[ ], int n) { const int *p = a + n - 1; // 마지막 원소를 가리키도록 초기화 while (p >= a) printf("%d\n", *p--); // *(p--) 50 40 30 20 10

인자 전달: call-by-value x y 1 1  2 형식인자는 실인자와 별도로 존재 함수 호출 시 실인자의 값 복사  메모리 사용과 실행 속도 측면에서 비효율적임 형식인자를 변경해도 실인자는 바뀌지 않음  부작용(side effect)이 없음 C는 call-by-value 방식만 지원 x = 1; f(x); // x = 1 void f(int y) { y++; } 1 x 1  2 y

인자 전달: call-by-reference 형식인자는 실인자는 동일 함수 호출 시 실인자의 값을 복사하지 않음  메모리 사용과 실행 속도 측면에서 효율적임 형식인자를 변경하면 실인자도 바뀜  부작용(side effect)이 있음 C++는 call-by-value와 call-by-reference 방식 모두 지원 x = 1; f(x); // x = 2 void f(int &y) { y++; } x ≡ y 1  2

포인터 인자 포인터 인자를 사용하면 call-by-value 방식에서도 call-by-reference 효과 유발 가능 side effect 유발 가능 실인자가 배열인 경우: 시작 포인터를 형식인자로 전달 int a[5]; f(a)  f(&a[0]) x = 1; f(&x); // x = 2 void f(int *p) { (*p)++; } 1  2 x 100 p

swap 함수 &a 100 &b 200 <swap> <main> a b #include <stdio.h> void swap(int *px, int *py); int main() { int a = 100, b = 200; printf("a=%d b=%d\n", a, b); swap(&a, &b); return 0; } void swap(int *px, int *py) { int tmp; printf("*px=%d *py=%d\n", *px, *py); tmp = *px; *px = *py; *py = tmp; } <main> 100 &a 200 &b <swap> px py a b a=100 b=200 *px=100 *py=200 *px=200 *py=100 a=200 b=100

scanf() 함수 변수에 값을 저장하기 위하여 변수의 주소 전달

인자를 통해 2개 이상의 결과 반환 #include <stdio.h> // 기울기와 y절편 계산 int get_line_parameter(int x1, int y1, int x2, int y2, float *slope, float *yintercept) { if (x1 == x2) return -1; *slope = (float)(y2 - y1) / (float)(x2 - x1); *yintercept = y1 - (*slope) * x1; return 0; } int main(void) { float s, y; if (get_line_parameter(3, 3, 6, 6, &s, &y) == -1) printf("에러\n"); else printf("기울기는 %f, y절편은 %f\n", s, y); 기울기와 y절편을 인자를 통해 반환 기울기는 1.000000, y절편은 0.000000

배열 인자 #include <stdio.h> void sub(int b[ ], int n); int main( ) { int a[3] = { 1, 2, 3 }; printf("%d %d %d\n", a[0], a[1], a[2]); sub(a, 3); return 0; } void sub(int b[ ], int n) { b[0] = 4; b[1] = 5; b[2] = 6; 1 2 3 4 5 6

포인터 반환 int *f(int x, int y) { int result; result = x + y; return &result; } // (X) local auto 변수 주소 반환 … int *p = f(3, 4); int n = *p; // 존재하지 않는 메모리 참조 int g = 1; int *f( ) { return &g; } // global static 변수 주소 반환 … int *p = f( ); int n = *p; // n = 1 *f( ) = 2; // g = 2 int *f( ) { static int s = 1; return &s; } // local static 변수 주소 반환 … int *p = f( ); int n = *p; // n = 1 int *f(int *q) { *q = 1; return q; } // 포인터 인자 반환 … int n; int m = *f(&n); // n = 1, m = 1