Presentation is loading. Please wait.

Presentation is loading. Please wait.

구조체, 포인터 활용 컴퓨터시뮬레이션학과 2014년 봄학기 담당교수 : 이형원 E304호,

Similar presentations


Presentation on theme: "구조체, 포인터 활용 컴퓨터시뮬레이션학과 2014년 봄학기 담당교수 : 이형원 E304호,"— Presentation transcript:

1 구조체, 포인터 활용 컴퓨터시뮬레이션학과 2014년 봄학기 담당교수 : 이형원 E304호, hwlee@inje.ac.kr

2 쉽게 풀어쓴 C언어 Express 제13장 구조체 C Express

3 구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다.
이번 장에서 학습할 내용 구조체는 서로 다른 데이터들을 하나로 묶는 중요한 도구입니다. 구조체의 개념, 정의, 초기화 방법 구조체와 포인터와의 관계 공용체와 typedef

4 자료형의 분류 자료형 (data type) 기초 자료형 파생 자료형 사용자 정의 자료형 char int float double
void 배열 포인터 구조체 공용체 typedef enum

5 구조체의 필요성 학생에 대한 데이터를 하나로 모으려면? int number;
char name[10]; double grade; 와 같이 개별 변수로 나타낼 수 있지만 묶을 수가 있나?

6 구조체를 사용하면 변수들을 하나로 묶을 수 있습니다.
구조체의 필요성 int number; char name[10]; double grade; 구조체를 사용하면 변수들을 하나로 묶을 수 있습니다.

7 구조체와 배열 구조체 vs 배열 같은 타입의 집합 다른 타입의 집합

8 중간 점검 1. 구조체와 배열의 차이점을 이야기해보라.
2. 복소수, 날짜, 화면의 좌표, 사각형 등을 표현하는데 필요한 데이터를 나열 해보라.

9 구조체 선언 구조체 선언 형식 struct 태그 { 자료형 멤버1; 자료형 멤버2; ... };

10 구조체 선언 구조체 선언은 변수 선언은 아님

11 구조체 선언의 예 // x값과 y값으로 이루어지는 화면의 좌표 struct point { int x; // x 좌표
int y; // y 좌표 }; // 사각형 struct rect { int x; int y; int width; int grade; }; // 복소수 struct complex { double real; // 실수부 double imag; // 허수부 }; // 직원 struct employee { char name[20]; // 이름 int age; // 나이 int gender; // 성별 int salary; // 월급 }; // 날짜 struct date { int month; int day; int year; };

12 구조체 변수 선언 구조체 정의와 구조체 변수 선언은 다르다.

13 구조체의 초기화 중괄호를 이용하여 초기값을 나열한다. struct student { int number;
char name[10]; double grade; }; struct student s1 = { 24, "Kim", 4.3 };

14 .기호는 구조체에서 멤버를 참조할 때 사용하는 연산자입니다.
구조체 멤버 참조 구조체 멤버를 참조하려면 다음과 같이 .연산자를 사용한다. s1.number = 26; // 정수 멤버 strcpy(s1.name, "Kim"); // 문자열 멤버 s1.grade = 4.3; // 실수 멤버 .기호는 구조체에서 멤버를 참조할 때 사용하는 연산자입니다. .

15 예제 #1 … struct student { int number; char name[10]; double grade; };
int main(void) { struct student s; s.number = ; strcpy(s.name,"홍길동"); s.grade = 4.3; printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf(“학점: %f\n", s.grade); return 0; } 구조체 선언 구조체 변수 선언 구조체 멤버 참조 학번: 이름: 홍길동 학점:

16 예제 #2 struct student { int number; char name[10]; double grade; };
int main(void) { struct student s; printf("학번을 입력하시오: "); scanf("%d", &s.number); printf("이름을 입력하시오: "); scanf("%s", s.name); printf("학점을 입력하시오(실수): "); scanf("%lf", &s.grade); printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf("학점: %f\n", s.grade); return 0; } 학번을 입력하시오: 이름을 입력하시오: 홍길동 학점을 입력하시오(실수): 4.3 학번: 이름: 홍길동 학점: 구조체 선언 구조체 변수 선언 구조체 멤버의 주소 전달

17 예제 #3 #include <math.h> struct point { int x; int y; };
int main(void) { struct point p1, p2; int xdiff, ydiff; double dist; printf("점의 좌표를 입력하시오(x y): "); scanf("%d %d", &p1.x, &p1.y); scanf("%d %d", &p2.x, &p2.y); xdiff = p1.x - p2.x; ydiff = p1.y - p2.y; dist = sqrt(xdiff * xdiff + ydiff * ydiff); printf("두 점사이의 거리는 %f입니다.\n", dist); return 0; } 점의 좌표를 입력하시오(x y): 10 10 점의 좌표를 입력하시오(x y): 20 20 두 점사이의 거리는 입니다. p2 (x,y) p1 (x,y)

18 중간 점검 1. 구조체 안에 선언된 각각의 변수들을 ______이라고 한다.
2. 구조체의 선언에 사용하는 키워드는 _______이다. 3. 구조체의 태그는 왜 필요하며, 태그를 사용하는 경우과 사용하지 않은 경 우가 어떻게 다른가? 4. 구조체의 선언만으로 변수가 만들어지는가? 5. 구조체의 멤버를 참조하는 연산자는 무엇인가?

19 구조체를 멤버로 가지는 구조체 struct date { // 구조체 선언 int year; int month; int day;
}; struct student { // 구조체 선언 int number; char name[10]; struct date dob; // 구조체 안에 구조체 포함 double grade; }; struct student s1; // 구조체 변수 선언 s1.dob.year = 1983; // 멤버 참조 s1.dob.month = 03; s1.dob.day = 29;

20 예제 #include <stdio.h> struct point { int x; int y; };
struct rect { struct point p1; struct point p2; int main(void) { struct rect r; int w, h, area, peri;

21 예제 printf("왼쪽 상단의 좌표를 입력하시오: "); scanf("%d %d", &r.p1.x, &r.p1.y);
w = r.p2.x - r.p1.x; h = r.p2.x - r.p1.x; area = w * h; peri = 2 * w + 2 * h; printf("면적은 %d이고 둘레는 %d입니다.\n", area, peri); return 0; } 왼쪽 상단의 좌표를 입력하시오: 1 1 오른쪽 상단의 좌표를 입력하시오: 6 6 면적은 25이고 둘레는 20입니다.

22 구조체 변수의 대입과 비교 같은 구조체 변수까리 대입은 가능하지만 비교는 불가능하다. struct point { int x;
int y; }; int main(void) { struct point p1 = {10, 20}; struct point p2 = {30, 40}; p2 = p1; // 대입 가능 if( p1 == p2 ) // 비교 -> 컴파일 오류!! printf("p1와 p2이 같습니다.") if( (p1.x == p2.x) && (p1.y == p2.y) ) // 올바른 비교 }

23 중간 점검 1. 구조체의 변수끼리 허용되는 연산에는 어떤 것들이 있는가? 2. 구조체 태그와 구조체 변수의 차이점은 무엇인가?
3. 구조체 멤버로 구조체를 넣을 수 있는가? 4. 구조체는 배열을 멤버로 가질 수 있는가?

24 구조체 배열 구조체를 여러 개 모은 것

25 구조체 배열 구조체 배열의 선언 struct student { int number; char name[20];
double grade; }; int main(void) { struct student list[100]; // 구조체의 배열 선언 list[2].number = 27; strcpy(list[2].name, "홍길동"); list[2].grade = 178.0; }

26 구조체 배열의 초기화 구조체 배열의 초기화 struct student list[3] = {
{ 1, "Park", }, { 2, "Kim", }, { 3, "Lee", } };

27 구조체 배열 예제 #define SIZE 3 struct student { int number; char name[20];
double grade; }; int main(void) { struct student list[SIZE]; int i; for(i = 0; i < SIZE; i++) printf("학번을 입력하시오: "); scanf("%d", &list[i].number); printf("이름을 입력하시오: "); scanf("%s", list[i].name); printf("학점을 입력하시오(실수): "); scanf("%lf", &list[i].grade); } for(i = 0; i< SIZE; i++) printf("학번: %d, 이름: %s, 학점: %f\n", list[i].number, list[i].name, list[i].grade); return 0; 학번을 입력하시오: 이름을 입력하시오: 홍길동 학점을 입력하시오(실수): 4.3 학번을 입력하시오: 이름을 입력하시오: 김유신 학점을 입력하시오(실수): 3.92 학번을 입력하시오: 이름을 입력하시오: 이성계 학점을 입력하시오(실수): 2.87 학번: , 이름: 홍길동, 학점: 학번: , 이름: 김유신, 학점: 학번: , 이름: 이성계, 학점:

28 중간 점검 1. 상품 5개의 정보를 저장할 수 있는 구조체의 배열을 정의해보라. 상품은 번호와 이름, 가격을 멤버로 가진다.

29 구조체와 포인터 구조체를 가리키는 포인터 포인터를 멤버로 가지는 구조체 순서로 살펴봅시다.

30 구조체를 가리키는 포인터 구조체를 가리키는 포인터 struct student *p;
struct student s = { , "홍길동", 4.3 }; p = &s; printf("학번=%d 이름=%s 학점=%f \n", s.number, s.name, s.grade); printf("학번=%d 이름=%s 학점=%f \n", (*p).number,(*p).name,(*p).grade);

31 -> 연산자 -> 연산자는 구조체 포인터로 구조체 멤버를 참조할 때 사용 struct student *p;
struct student s = { , "홍길동", }; p = &s; printf("학번=%d 이름=%s 키=%f \n", s.number, s.name, s.grade); printf("학번=%d 이름=%s 키=%f \n", (*p).number,(*p).name,(*p).grade); printf("학번=%d 이름=%s 키=%f \n", p->number, p->name, p->grade);

32 -> 연산자 ==

33 예제 // 포인터를 통한 구조체 참조 #include <stdio.h> struct student {
int number; char name[20]; double grade; }; int main(void) { struct student s = { , "홍길동", 4.3}; struct student *p; p = &s; printf("학번=%d 이름=%s 키=%f \n", s.number, s.name, s.grade); printf("학번=%d 이름=%s 키=%f \n", (*p).number,(*p).name,(*p).grade); printf("학번=%d 이름=%s 키=%f \n", p->number, p->name, p->grade); return 0; } 학번= 이름=홍길동 학점=

34 포인터를 멤버로 가지는 구조체 struct date { int month; int day; int year; };
struct student { int number; char name[20]; double grade; struct date *dob;

35 포인터를 멤버로 가지는 구조체 int main(void) { struct date d = { 3, 20, 1980 };
struct student s = { , "Kim", 4.3 }; s.dob = &d; printf("학번: %d\n", s.number); printf("이름: %s\n", s.name); printf("학점: %f\n", s.grade); printf("생년월일: %d년 %d월 %d일\n", s.dob->year, s.dob->month, s.dob->day); return 0; } 학번: 이름: Kim 학점: 생년월일: 1980년 3월 20일

36 구조체와 함수 구조체를 함수의 인수로 전달하는 경우 구조체의 복사본이 함수로 전달되게 된다.
만약 구조체의 크기가 크면 그만큼 시간과 메모리가 소요된다. int equal(struct student s1, struct student s2) { if( strcmp(s1.name, s2.name) == 0 ) return 1; else return 0; }

37 구조체와 함수 구조체의 포인터를 함수의 인수로 전달하는 경우 시간과 공간을 절약할 수 있다. 원본 훼손의 가능성이 있다.
int equal(struct student const *p1, struct student const *p2) { if( strcmp(p1->name, p2->name) == 0 ) return 1; else return 0; } 포인터를 통한 구조체의 변경을 막는다.

38 구조체를 반환하는 경우 복사본이 반환된다. struct student make_student(void) {
struct student s; printf("나이:“); scanf("%d", &s.age); printf("이름:“); scanf("%s", s.name); printf("키:“); scanf("%f", &s.grade); return s; } 구조체 s의 복사본이 반환된다.

39 예제 #include <stdio.h> struct vector { float x; float y; };
struct vector get_vector_sum(struct vector a, struct vector b); int main(void) { struct vector a = { 2.0, 3.0 }; struct vector b = { 5.0, 6.0 }; struct vector sum; sum = get_vector_sum(a, b); printf("벡터의 합은 (%f, %f)입니다.\n", sum.x, sum.y); return 0; }

40 예제 struct vector get_vector_sum(struct vector a, struct vector b) {
struct vector result; result.x = a.x + b.x; result.y = a.y + b.y; return result; } 벡터의 합은 ( , )입니다.

41 공용체 공용체(union) 같은 메모리 영역을 여러 개의 변수가 공유 공용체를 선언하고 사용하는 방법은 구조체와 아주 비슷
union example { char c; // 같은 공간 공유 int i; // 같은 공간 공유 };

42 예제 #include <stdio.h> union example { int i; char c; }; 공용체 선언
int main(void) { union example v; v.c = 'A'; printf("v.c:%c v.i:%i\n", v.c, v.i ); v.i = 10000; printf("v.c:%c v.i:%i\n", v.c, v.i); } 공용체 선언 공용체 변수 선언. char 형으로 참조. int 형으로 참조. v.c:A v.i:65 v.c:ꠕ v.i:10000

43 ip 주소 예제 #include <stdio.h> union ip_address {
unsigned long laddr; unsigned char saddr[4]; }; int main(void) { union ip_address addr; addr.saddr[0] = 1; addr.saddr[1] = 0; addr.saddr[2] = 0; addr.saddr[3] = 127; printf("%x\n", addr.laddr); return 0; } 7f000001

44 공용체에 타입 필드 사용 #include <stdio.h> #include <string.h>
#define STU_NUMBER 1 #define REG_NUMBER 2 struct student { int type; union { int stu_number; // 학번 char reg_number[15]; // 주민등록번호 } id; char name[20]; };

45 공용체에 타입 필드 사용 void print(struct student s) { switch(s.type)
case STU_NUMBER: printf("학번 %d\n", s.id.stu_number); printf("이름: %s\n", s.name); break; case REG_NUMBER: printf("주민등록번호: %s\n", s.id.reg_number); default: printf("타입오류\n"); }

46 공용체에 타입 필드 사용 int main(void) 학번: 20070001 이름: 홍길동 {
struct student s1, s2; s1.type = STU_NUMBER; s1.id.stu_number = ; strcpy(s1.name, "홍길동"); s2.type = REG_NUMBER; strcpy(s2.id.reg_number, " "); strcpy(s2.name, "김철수"); print(s1); print(s2); } 학번: 이름: 홍길동 주민등록번호: 이름: 김철수

47 중간 점검 공용체의 선언에 사용하는 키워드는 _______이다. 공용체에 할당되는 메모리의 크기는 어떻게 결정되는가?

48 열거형 열거형(enumeration)이란 변수가 가질 수 있는 값들을 미리 열거해놓은 자 료형
(예) 요일을 저장하고 있는 변수는 { 일요일, 월요일, 화요일, 수요일, 목요일, 금요일, 토요일 } 중의 하나의 값만 가질 수 있다.

49 열거형의 선언 enum days { SUN, MON, TUE, WED, THU, FRI, SAT }; 태그 이름 값들을 나열
열거형 변수 선언 enum days today; today = SUN; // OK!

50 열거형이 필요한 이유 다음과 같이 프로그램을 작성할 수 있다. 되도록 오류를 줄이고 가독성을 높여야 된다.
int today; today = 0; // 일요일 today = 1; // 월요일 되도록 오류를 줄이고 가독성을 높여야 된다. 0보다는 SUN라는 기호상수가 더 바람직하다. 의미를 쉽게 알 수 있기 때문이다. today에 9와 같은 의미없는 값이 대입되지 않도록 미리 차단하는 것도 필요하다.

51 열거형 초기화 enum days { SUN, MON, TUE, WED, THU, FRI, SAT }; // SUN=0, MON=1, ... enum days { SUN=1, MON, TUE, WED, THU, FRI, SAT }; // SUN=1, MON=2, ... enum days { SUN=7, MON=1, TUE, WED, THU, FRI, SAT=6 };// SUN=7, MON=1, ... 값을 지정하기 않으면 0부터 할당

52 열거형의 예 enum colors { white, red, blue, green, black };
enum boolean { false, true }; enum levels { low, medium, high }; enum car_types { sedan, suv, sports_car, van, pickup, convertible };

53 예제 #include <stdio.h>
enum days { SUN, MON, TUE, WED, THU, FRI, SAT }; char *days_name[] = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" }; int main(void) { enum days d; d = WED; printf("%d번째 요일은 %s입니다\n", d, days_name[d]); return 0; } 3번째 요일은 wednesday입니다

54 열거형과 다른 방법과의 비교 정수 사용 기호 상수 열거형 switch(code) { case 1:
printf("LCD TV\n"); break; case 2: printf("PDP TV\n"); } #define LCD 1 #define PDP 2 case LCD: case PDP: enum tvtype { LCD, PDP }; enum tvtype code; 컴퓨터는 알기 쉬우나 사람은 기억하기 어렵다. 기호 상수를 작성할 때 오류를 저지를 수 있다. 컴파일러가 중복이 일어나지 않도록 체크한다.

55 중간 점검 1. 열거형의 선언에 사용하는 키워드는 _______이다. 2. 열거형은 어떤 경우에 사용되는가?
3. 열거형에서 특별히 값을 지정하지 않으면 자동으로 정수상수값이 할당되 는가?

56 typedef의 개념

57 typedef typedef은 새로운 자료형(type)을 정의(define) C의 기본 자료형을 확장시키는 역할
typedef old_type new_type;

58 typedef의 예 typedef unsiged char BYTE;
BYTE index; // unsigned int index;와 같다. typedef int INT32; typedef unsigned int UINT32; INT32 i; // int i;와 같다. UINT32 k; // unsigned int k;와 같다.

59 구조체로 새로운 타입 정의 구조체로 새로운 타입을 정의할 수 있다. struct point { int x; int y; };
typedef struct point POINT; POINT a, b;

60 예제 #include <stdio.h> typedef struct point { int x; int y;
POINT translate(POINT p, POINT delta); int main(void) { POINT p = { 2, 3 }; POINT delta = { 10, 10 }; POINT result; result = translate(p, delta); printf("새로운 점의 좌표는(%d, %d)입니다.\n", result.x, result.y); return 0; }

61 예제 POINT translate(POINT p, POINT delta) { POINT new_p;
new_p.x = p.x + delta.x; new_p.y = p.y + delta.y; return new_p; } 새로운 점의 좌표는 (12, 13)입니다.

62 typedef과 #define 비교 이식성을 높여준다.
코드를 컴퓨터 하드웨어에 독립적으로 만들 수 있다 (예) int형은 2바이트이기도 하고 4바이트, int형 대신에 typedef을 이용한 INT32나 INT16을 사용하게 되면 확실하게 2바이트인지 4바이트인지를 지 정할 수 있다. #define을 이용해도 typedef과 비슷한 효과를 낼 수 있다. 즉 다음과 같이 INT32를 정의할 수 있다. #define UINT32 unsigned int typedef float VECTOR[2];// #define으로는 불가능하다. 문서화의 역할도 한다. typedef을 사용하게 되면 주석을 붙이는 것과 같은 효과

63 중간 점검 1. typedef의 용도는 무엇인가? 2. typedef의 장점은 무엇인가?
3. 사원을 나타내는 구조체를 정의하고 이것을 typedef을 사용하여서 employee라는 새로운 타입으로 정의하여 보자.

64 실습: 평점이 높은 학생 찾기 어느 학교나 학기가 끝나면 학과 내에서 가장 평점이 높은 학생을 선발하 여서 장학금을 수여한다. 가장 평점이 높은 학생을 찾아서 학생의 이름과 학번, 평점을 화면에 출력하는 프로그램을 작성하여 보자.

65 실행 결과 평점이 가장 높은 학생은 (이름: 홍길동, 학번: , 평점: )입니다.

66 힌트 학생에 대한 정보는 구조체를 이용하여서 표현한다. 학생들이 여러 명이므로 구조체의 배열을 사용하는 것이 좋겠다.
struct student { int number; char name[20]; double grade; }; struct student list[] = { { , “홍길동", 4.2 }, { , “김철수", 3.2 }, { , “김영희", 3.9 } };

67 소스 #include <stdio.h> struct student { int number;
char name[20]; double grade; }; struct student list[] = { { , "홍길동, 4.2 }, { , "김철수, 3.2 }, { , "김영희, 3.9 }

68 소스 int main(void) { struct student super_stu; int i, size;
size = sizeof(list)/sizeof(list[0]); super_stu = list[0]; for(i=1; i< size; i++) { if( list[i].grade > super_stu.grade ) super_stu = list[i]; } printf("평점이 가장 높은 학생은 (이름%s, 학번%d, 평점%f)입니다\n", super_stu.name, super_stu.number, super_stu.grade);

69 도전문제 학생들에 대한 정보를 사용자로부터 받게끔 프로그램을 수정하라.
최대 평점의 학생을 찾는 부분을 함수 get_max_stu()로 독립시켜서 전체 프로그램을 다시 작상하여 보자. 은행 입출금 시스템을 간단히 구현하고 여기에 로그인 기능을 추가하여 보 자.

70 Q & A

71 쉽게 풀어쓴 C언어 Express 제14장 포인터 활용 C Express

72 이중 포인터 이중 포인터(double pointer) : 포인터를 가리키는 포인터
int i = 10; // i는 int형 변수 int *p = &i; // p는 i를 가리키는 포인터 int **q = &p; // q는 포인터 p를 가리키는 이중 포인터

73 이중 포인터 이중 포인터의 해석

74 이중 포인터 p i q *q // 이중 포인터 프로그램 #include <stdio.h> int main(void)
이중포인터 100 200 300 i // 이중 포인터 프로그램 #include <stdio.h> int main(void) { int i = 100; int *p = &i; int **q = &p; *p = 200; printf("i=%d *p=%d **q=%d \n", i, *p, **q); **q = 300; return 0; } i=200 *p= **q=200 i=300 *p= **q=300

75 예제 #2 #include <stdio.h> void set_pointer(char **q);
char *proverb="All that glisters is not gold."; int main(void) { char *p="zzz"; set_pointer(&p); printf("%s \n", p); return 0; } void set_pointer(char **q) *q = proverb; 포인터 p의 값을 함수에서 변경하려면 주소를 보내야 한다. All that glisters is not gold.

76 중간 점검 double형 포인터를 가리키는 이중 포인터 dp를 선언하여 보자.
char c; char *p; char **dp; p = &c; dp =&p;와 같이 정의되었을 때 **dp 은 무엇을 가리키는가?

77 포인터 배열 포인터 배열(array of pointers): 포인터를 모아서 배열로 만든것

78 정수형 포인터 배열 int a = 10, b = 20, c = 30, d = 40, e = 50;
int *pa[5] = { &a, &b, &c, &d, &e };

79 2차원 배열에 문자열을 저장 char fruits[4 ][10] = { "apple", "blueberry",
"orange", “melon" };

80 문자형 포인터 배열 char *fruits[ ] = { "apple", "blueberry", "orange", “melon"
};

81 문자열 배열 // 문자열 배열 #include <stdio.h> int main(void) { int i, n;
char *fruits[ ] = { "apple", "blueberry", "orange", "melon" }; n = sizeof(fruits)/sizeof(fruits[0]); // 배열 원소 개수 계산 for(i = 0; i < n; i++) printf("%s \n", fruits[i]); return 0; } apple blueberry orange melon

82 중간 점검 double형의 포인터 10개를 가지는 배열을 정의하여 보자.
래그드 배열이 일반적인 2차원 배열보다 좋은 점은 무엇인가?

83 배열 포인터 배열 포인터(a pointer to an array)는 배열을 가리키는 포인터

84 예제 #include <stdio.h> int main(void) {
int a[5] = { 1, 2, 3, 4, 5 }; int (*pa)[5]; int i; pa = &a; for(i=0 ; i<5 ; i++) printf("%d \n", (*pa)[i]); return 0; } 배열 포인터 1 2 3 4 5

85 함수 포인터 함수 포인터(function pointer): 함수를 가리키는 포인터 int (*pf)(int, int);

86 함수 포인터의 해석

87 함수 포인터의 사용 int sub(int, int); // 함수 원형 정의
int (*pf)(int, int); // 함수 포인터 정의 ... pf = sub; // 함수의 이름을 함수 포인터에 대입 result = pf( 10, 20); // 함수 포인터를 통하여 함수 호출

88 fp1.c // 함수 포인터 #include <stdio.h> // 함수 원형 정의
int add(int, int); int sub(int, int); int main(void) { int result; int (*pf)(int, int); // 함수 포인터 정의 pf = add; // 함수 포인터에 함수 add()의 주소 대입 result = pf(10, 20); // 함수 포인터를 통한 함수 add() 호출 printf("10+20은 %d\n", result); pf = sub; // 함수 포인터에 함수 sub()의 주소 대입 result = pf(10, 20); // 함수 포인터를 통한 함수 sub() 호출 printf("10-20은 %d\n", result); return 0; }

89 fp1.c int add(int x, int y) { return x+y; } int sub(int x, int y)
10+20은 30 10-20은 -10

90 함수 포인터의 배열 int (*pf[5]) (int, int);

91 함수 포인터의 배열 int (*pf[5]) (int, int);

92 함수 포인터 배열 // 함수 포인터 배열 #include <stdio.h> // 함수 원형 정의
void menu(void); int add(int x, int y); int sub(int x, int y); int mul(int x, int y); int div(int x, int y); void menu(void) { printf("=====================\n"); printf("0. 덧셈\n"); printf("1. 뺄셈\n"); printf("2. 곱셈\n"); printf("3. 나눗셈\n"); printf("4. 종료\n"); }

93 함수 포인터 배열 int main(void) { int choice, result, x, y; 함수 포인터 배열
// 함수 포인터 배열을 선언하고 초기화한다. int (*pf[4])(int, int) = { add, sub, mul, div }; while(1) menu(); printf("메뉴를 선택하시오:"); scanf("%d", &choice); if( choice < 0 || choice >=4 ) break; printf("2개의 정수를 입력하시오:"); scanf("%d %d", &x, &y); result = pf[choice](x, y); // 함수 포인터를 이용한 함수 호출 printf("연산 결과 = %d\n",result); } return 0; 함수 포인터 배열 선언

94 함수 포인터 배열 int add(int x, int y) { return x + y; }
int sub(int x, int y) return x - y; int mul(int x, int y) return x * y; int div(int x, int y) return x / y; ===================== 0. 덧셈 1. 뺄셈 2. 곱셈 3. 나눗셈 4. 종료 메뉴를 선택하시오:2 2개의 정수를 입력하시오:10 20 연산 결과 = 200 메뉴를 선택하시오:

95 함수 인수로서의 함수 포인터 함수 포인터도 인수로 전달이 가능하다.

96 예제 다음과 같은 수식을 계산하는 프로그램을 작성하여 보자. 여기서 f(k)는 다음과 같은 함수들이 될 수 있다.

97 예제 #include <stdio.h> #include <math.h>
double f1(double k); double f2(double k); double formula(double (*pf)(double), int n); int main(void) { printf("%f\n", formula(f1, 10)); printf("%f\n", formula(f2, 10)); } double formula(double (*pf)(double), int n) int i; double sum = 0.0; for(i = 1; i < n; i++) sum += pf(i) * pf(i) + pf(i) + 1; return sum;

98 예제 double f1(double k) { return 1.0 / k; } double f2(double k)
return cos(k);

99 중간 점검 int 값을 반환하고 double 값을 인수로 받는 함수의 포인터 pf를 선언하여 보자.
1번의 함수 포인터를 통하여 3.0을 인수로 하여 함수를 호출하는 문장을 작성하라.

100 다차원 배열과 포인터 2차원 배열 int m[3][3]
1행->2행->3행->...순으로 메모리에 저장(행우선 방법)

101 2차원 배열과 포인터 배열 이름 m은 &m[0][0] m[0]는 1행의 시작 주소 m[1]은 2행의 시작 주소 ...

102 2차원 배열의 해석

103 multi_array.c #include <stdio.h> int main(void) {
printf("m = %p\n", m); printf("m[0] = %p\n", m[0]); printf("m[1] = %p\n", m[1]); printf("m[2] = %p\n", m[2]); printf("&m[0][0] = %p\n", &m[0][0]); printf("&m[1][0] = %p\n", &m[1][0]); printf("&m[2][0] = %p\n", &m[2][0]); return 0; } m m[0] m[1] m[2] 10 20 30 40 50 60 70 80 90 m[0][0] m[0][1] m[0][2] m[1][0] m[1][1] m[1][2] m[2][0] m[2][1] m[2][2] m = m[0] = m[1] = m[2] = &m[0][0] = &m[1][0] = &m[2][0] =

104 2차원 배열과 포인터 연산 2차원 배열 m[][]에서 m에 1을 더하거나 빼면 어떤 의미일까?

105 포인터를 이용한 배열 원소 방문 행의 평균을 구하는 경우
double get_row_avg(int m[][COLS], int r) { int *p, *endp; double sum = 0.0; p = &m[r][0]; endp = &m[r][COLS]; while( p < endp ) sum += *p++; sum /= COLS; return sum; }

106 포인터를 이용한 배열 원소 방문 전체 원소의 평균을 구하는 경우
double get_total_avg(int m[][COLS]) { int *p, *endp; double sum = 0.0; p = &m[0][0]; endp = &m[ROWS-1][COLS]; while( p < endp ) sum += *p++; sum /= ROWS * COLS; return sum; }

107 중간 점검 m[10][10]에서 m[0]의 의미는 무엇인가? m[10][10]에서 (m+1)의 의미는 무엇인가?

108 const 포인터 const를 붙이는 위치에 따라서 의미가 달라진다.

109 예제 #include <stdio.h> int main(void) {
char s[] = "Barking dogs seldom bite."; char t[] = "A bad workman blames his tools"; const char * p=s; char * const q=s; //p[3] = 'a'; p = t; q[3] = 'a‘; //q = t; return 0; } p가 가리키는 곳의 내용을 변경할 수 없다. 하지만 p는 변경이 가능하다. q가 가리키는 곳의 내용은 변경할 수 있다. 하지만 q는 변경이 불가능하다.

110 volatile 포인터 volatile은 다른 프로세스나 스레드가 값을 항상 변경할 수 있으니 값을 사 용할 때마다 다시 메모리에서 읽으라는 것을 의미

111 void 포인터 순수하게 메모리의 주소만 가지고 있는 포인터 가리키는 대상물은 아직 정해지지 않음
(예) void *vp; 다음과 같은 연산은 모두 오류이다. *vp; // 오류 *(int *)vp; // void형 포인터를 int형 포인터로 변환한다. vp++; // 오류 vp--; // 오류

112 vp.c #include <stdio.h> int main(void) {
int a[] = { 10, 20, 30, 40, 50 }; void *vp; vp = a; // 가능 vp = &a[2]; // 가능 //*vp = 35; // 오류 //vp++; // 오류 *(int *)vp = 35; // 가능 return 0; }

113 중간 점검 void형 포인터 vp를 int형 포인터 ip로 형변환하는 문장을 작성하라.

114 main() 함수의 인수 지금까지의 main() 함수 형태 외부로부터 입력을 받는 main() 함수 형태
int main(void) { .. } int main(int argc, char *argv[]) { .. }

115 인수 전달 방법 C: \cprogram> mycopy src dst

116 main_arg.c c:\cprogram\mainarg\Debug>mainarg src dst
#include <stdio.h> int main(int argc, char *argv[]) { int i = 0; for(i = 0;i < argc; i++) printf("명령어 라인에서 %d번째 문자열 = %s\n", i, argv[i]); return 0; } c:\cprogram\mainarg\Debug>mainarg src dst 명령어 라인에서 0번째 문자열 = mainarg 명령어 라인에서 1번째 문자열 = src 명령어 라인에서 2번째 문자열 = dst c:\cprogram\mainarg\Debug>

117 비주얼 C++ 프로그램 인수 입력 방법 [프로젝트]->[main_arg.exe 속성] 선택

118 mile2km.c c:\cprogram\mainarg\Debug>mainarg 10
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { double mile, km; if( argc != 2 ){ printf("사용 방법: mile2km 거리\n"); return 1; } mile = atof(argv[1]); km = * mile; printf("입력된 거리는 %f km입니다. \n", km); return 0; c:\cprogram\mainarg\Debug>mainarg 10 입력된 거리는 km입니다. c:\cprogram\mainarg\Debug>

119 중간 점검 C>main arg1 arg2 arg3와 같이 실행시킬 때 argv[0]가 가리키는 것은?
C>main arg1 arg2 arg3와 같이 실행시킬 때 argc의 값은?

120 실습: 이분법으로 근 구하기 2차식의 경우에는 공식이 있지만 일반적인 n차식의 경우 공식이 존재하지 않는다.
이때 사용할 수 있는 방법이 이분법(bisection)이다

121 이분법 구간 [a, b]에서 근을 가지는 것이 확실하면 구간 [a, b]의 중점 m을 구하 여 구간 [a, m]과 구간 [m, b]로 나눈다. 각각의 구간에서 다시 f(a)와 f(b)의 부호를 조사하여 근이 어떤 구간에 위 치하는지를 결정한다. 다시 그 구간에 대하여 동일한 과정을 되풀이한다.

122 실행 결과 다음과 같은 함수에 대하여 근을 구한다. 함수 포인터를 받는 get_root()를 작성한다.
double get_root(double (*fp)(double), double a, double b); a의 값을 입력하시오 -200 b의 값을 입력하시오 200 값은

123 예제 소스 #include<stdio.h> #include <math.h>
#define ESP 0.001 double get_root(double (*f)(double), double a, double b); double func(double x) { return (x)*(x)*(x) + (x)*(x) + (x) + 7; } void main() double x0,x1; double r; printf("a의 값을 입력하시오"); scanf("%lf",&x0); printf("b의 값을 입력하시오"); scanf("%lf",&x1); r = get_root(func, x0, x1); printf("값은 %f\n", r); return 0;

124 예제 소스 double get_root(double (*f)(double), double x0, double x1) {
float x2; int i = 1; double f1,f2,f0; do x2=(x0+x1)/2; f0=f(x0); f1=f(x1); f2=f(x2); if(f0*f2<0) x1=x2; else x0=x2; i++; } while(fabs(f2)>ESP); return x2; } 부호가 다르면 f2의 절대값이 무시할 만큼 작아지면, 즉 0에 가까워지면

125 도전문제 사용자로부터 함수를 입력받도록 프로그램을 수정할 수 있는가? 다항식의 최고차수는 3으로 제한하도록 하자.

126 Q & A


Download ppt "구조체, 포인터 활용 컴퓨터시뮬레이션학과 2014년 봄학기 담당교수 : 이형원 E304호,"

Similar presentations


Ads by Google