구조체와포인터 -...
Transcript of 구조체와포인터 -...
Intelligence Networking and Computing Lab.
구조체와 포인터 - 1
부산대학교 전기컴퓨터공학부
김종덕 ([email protected])
본 강의 자료는 문정욱 교수님의 강의 자료를 활용하여 작성하였습니다.
구조체란?
❖ 예: 학생관리 프로그램의 각 학생에 대
한 기록(record)
▪ 한 학생에 대한 자료들을 한 곳에 모아서 관
리하면 편리
▪ 한 학생의 이름, 학번, 나이, 전화번호, 전공 등
❖ 구조체는 여러 자료형 변수들의 집합
체이다.
❖ C의 구조체 구문 구조
▪ 요소(Element), 멤버(Member)/필드(Field)
▪ 구조체를 구성하는 변수
❖ 구조체는 새로운 자료형(Type)의 하나
❖ C의 구조체 정의 및 활용 예 1
2
struct Declaration :
struct name(optional) {type1 member1;type2 member2;...typen membern;
};
#include <stdio.h>int main(void){
struct student {int id;char *pname;double points;
};
struct student s1, s2;
s1.id = 1;s1.pname ="Choi";s1.points = 9.9;
s2.id = 2;s2.pname ="Park";s2.points = 0.1;
printf("[%d:%s] = %lf\n", s1.id,s1.pname, s1.points);
printf("[%d:%s] = %lf\n", s2.id,s2.pname, s2.points);
return 0;}
새로운 Type을 선언하는 것
새로운 Type의 이름은?
변수의 선언
구조체에서 요소/멤버/필드를접근할 때는 ‘.’ 연산자를 사용
Intelligence Networking and Computing Lab.
구조체 정의 및 변수 선언 방법 2
❖ 다음 A,B,C 3개의 코드는 본질적으로 동일함
▪ A는 구조체 정의선언과 해당 구조체 변수 선언을 분리한 것
▪ B는 구조체 정의선언과 해당 구조체 변수 선언을 동시에
▪ C는 구조체의 이름을 제거한 것
• 해당 구조체를 가지는 또 다른 변수를 선언 시에 불편할 수 있음
❖ 구조체를 큰 프로그램의 전반에서 사용할 경우 위와 같은 변수 선언
이 불편할 수 있음 이 경우 이후에 설명하는 typedef을 많이 사용3
#include <stdio.h>int main(void){
struct student {int id;char *pname;double points;
};
struct student s1, s2;
...}
#include <stdio.h>int main(void){
struct student {int id;char *pname;double points;
} s1, s2;
...}
#include <stdio.h>int main(void){
struct {int id;char *pname;double points;
} s1, s2;
...}
A B C
Intelligence Networking and Computing Lab.
구조체의 활용
❖ Student 구조체의 print를 위해 별도의 함수를 만들기로 하고 좌측의 프로그램을 우
측과 같이 수정하였더니 Syntax Error가 발생하였다. 그 이유가 무엇일까?
❖ 해결책은?
4
#include <stdio.h>int main(void){
struct student {int id;char *pname;double points;
};
struct student s1, s2;
s1.id = 1;s1.pname ="Choi";s1.points = 9.9;
s2.id = 2;s2.pname ="Park";s2.points = 0.1;
printf("[%d:%s] = %lf\n", s1.id,s1.pname, s1.points);
printf("[%d:%s] = %lf\n", s2.id,s2.pname, s2.points);
return 0;}
#include <stdio.h>void print_student(struct student s){
printf("[%d:%s] = %lf\n", s.id, s.pname, s.points);
}int main(void){
struct student {int id;char *pname;double points;
};
struct student s1, s2;
s1.id = 1;s1.pname ="Choi";s1.points = 9.9;
s2.id = 2;s2.pname = "Park";s2.points = 0.1;
print_student(s1);print_student(s2);return 0;
}
typedef
❖ typedef : Type에 별명(aliase)을 부
여하는 기능
❖ 주로 복잡한 type 이름을 간단하
게 표시하는 경우에 많이 사용
▪ 아래 코드는 unsigned int라는 type에
uint32라는 새로운 별명을 부여
▪ 배열에 대한 typedef도 가능함. 단 작성
방식에 유의할 것
❖ 구조체에 typedef이 많이 사용됨
5
int main(void){
typedef unsigned int uint32;typedef int * pint32;typedef int aint3[3];
unsigned int a; uint32 b;// T(a) == T(b)
int * pa;pint32 pb;// T(pa) == T(pb)
int aa[3]; aint3 bb;// T(aa) == T(bb)
}
#include <stdio.h>typedef struct student {
int id;char *pname;double points;
} STUD;
void print_student(STUD s){
printf("[%d:%s] = %lf\n", s.id, s.pname, s.points);
}int main(void){
STUD s1;struct student s2;
s1.id = 1;s1.pname ="Choi";s1.points = 9.9;
s2.id = 2;s2.pname = "Park";s2.points = 0.1;
print_student(s1);print_student(s2);return 0;
}
Intelligence Networking and Computing Lab.
구조체 변수의 초기화
❖ 구조체 변수도 초기화 가능
▪ 배열의 초기화와 유사
▪ 멤버/필드 변수의 자료형과 초기화하는 값의 자료형은 일치하여야 함
6
typedef struct student {int id;char *pname;double points;
} STUD;
int main(void){
STUD s1 = {1, "Choi", 9.9};struct student s2 = {2, "Park", 0.1};. . .
}
Intelligence Networking and Computing Lab.
구조체 변수에 대한 포인터
❖ 구조체 변수의 주소 값과 메모리 크기는 어떻게 될까?
❖ 구조체 변수에 대한 포인터와 관련 연산
7
typedef struct student {int id;char *pname;double points;
} STUD;
int main(void){
STUD s1 = {1, "Choi", 9.9};printf("%p, %d\n", &s1, sizeof(s1));. . .
}
int main(void){
STUD s1 = {1, "Choi", 9.9};STUD *pStudent = &s1;
*pStudent.id = 3; // Error(*pStudent).id = 4; // okpStudent->id = 5; // Good. . .
}
‘.’ 연산자의 우선 순위가 ‘*’연산자의 우선 순위 보다 높다.
연산자 사용방법 결과
. 구조체변수.요소/멤버/필드 요소/멤버/필드 변수
-> 구조체주소->요소/멤버/필드 요소/멤버/필드 변수
기능적으로는 문제가 없으나 연산자를 2개 사용
연산자를 하나만 사용하며 구조체 포인터에서 일반적으로 쓰임
자료형과 메모리에 대한 이해
❖ 우측의 STUD와 STUD2는 같은
Member 또는 Element를 가지는 구조
체이나 그 순서에 차이가 있다.
❖ 어떤 컴퓨터에서 sizeof()를 이용하여
두 구조체의 크기를 비교하였더니 우
측 아래와 같이 STUD는 16Bytes,
STUD2는 24Bytes로 서로 다른 크기를
가진다.
❖ 이러한 구조체 크기 차이의 원인은 무
엇일까?
❖ 결과로부터 double 자료형은 어떤 메
모리 주소에서 시작할 수 있는지 유추
해보라
▪ 0x00000? : double의 경우 ?에 가능한 숫자는?
▪ int나 pointer 자료형은?
▪ short 자료형의 경우는?
8
typedef struct student {int id;char *pname;double points;
} STUD;
typedef struct student2 {int id;double points;char *pname;
} STUD2;
int main(void){
STUD s1 = {1, "Choi", 9.9};STUD2 s2 = {2, 0.1, "Park"};printf("%p, %d\n", &s1, sizeof(s1));printf("%p, %d\n", &s2, sizeof(s2));return 0;
}
0061FF20, 160061FF08, 24
출력 결과
구조체 변수에 대한 Assignment 연산
❖ C 언어의 경우 배열에 대해서
Assignment를 할 수 없음 !!!
❖ 구조체 변수에 대해서 Assignment
를 할 수 있을까?
▪ 전통(?) C 언어에서는 지원하지 않았으
나 현재는 가능하며 실제 값들이
모두 복사된다.
• 메모리의 내용이 그대로 복사
• 허용되기는 하지만 남용하지 않아야 하
며 일반적인 경우 비추천
9
int main(void){
STUD s1 = {1, "Choi", 9.9};STUD s3;
s3 = s1; . . .
}
int main(void){
int aN1[]={1, 2, 3};int aN2[3];
aN2 = aN1;. . .
}
Assignment 연산과 메모리 처리
❖ 1)의 = 연산은 실질적으로 몇 Byte
의 메모리 복사로 이어질까?
▪ sizeof(double) 8
❖ 2)의 = 연산은 실질적으로 몇 Byte
의 메모리 복사로 이어질까?
▪ sizeof(double *) 4
❖ 구조체 변수는 Assignment 가능
❖ 1)의 = 연산은 실질적으로 몇 Byte
의 메모리 복사로 이어질까?
▪ sizeof(STUD) 16
❖ 2)의 = 연산은 실질적으로 몇 Byte
의 메모리 복사로 이어질까?
▪ sizeof(STUD *) 4
10
int main(void){
STUD s1 = {1, "Choi", 9.9};STUD s3;STUD *ps;
s3 = s1; // 1)ps = &s1; // 2). . .
}
int main(void){
double d1 = 3.8;double d3;double *pd1;
d3 = d1; // 1)pd1 = &d1; // 2). . .
}
Array and Pointer : ex) char str[] vs. char *str
❖ Case 1) 함수 내의 변수인 경우
▪ 아래에서 str1과 str2를 비교하라.
• 두 변수의 자료형은?
• 두 변수의 크기는?
▪ 두 변수는 동일한가?
▪ 아래와 같은 코드가 가능한가?
❖ Case 2) 함수 인자인 경우
▪ 아래 두 함수의 인자 char str[]과 char
*str은 실질적으로 동일하다 !!!
▪ 아래 코드는 문제 없이 동작
11
#include <stdio.h>int main(void){
char str1[] = "Hello";char *str2 = "Hello";. . .
}
#include <stdio.h>void print_str(char *str){
while (*str != '\0')putchar(*str++);
}void print_str2(char str[]){
while (*str != '\0')putchar(*str++);
}int main(void){
char str1[] = "Hello";print_str(str1);print_str2(str1);return 0;
}
#include <stdio.h>int main(void){
char str1[] = "Hello";while (*str1 != '\0')
putchar(*str1++);return 0;
} C 언어의 포인터는 어려워…
구조체 변수와 함수의 인자
❖ 함수 인자의 관점에서 배열은 포
인터와 실질적/결과적으로 동일함!
▪ 배열의 경우 배열의 주소가 매개 변수
로 복사되는 것이며 배열이 새로운 배
열로 복사되는 것이 아님
❖ 구조체 변수와 함수의 인자?
▪ 우측의 코드에서 print_student()와
print_student2() 함수의 인자/매개변수
전달 과정을 비교해 보라.
12
#include <stdio.h>typedef struct student {
int id;char *pname;double points;
} STUD;
void print_student(STUD s){
printf("[%d:%s] = %lf\n", s.id, s.pname, s.points);
}
void print_student2(STUD *ps){
printf("[%d:%s] = %lf\n", ps->id, ps->pname, ps->points);
}
int main(void){
STUD s1 = {1, "Choi", 9.9};STUD s2 = {2, "Park", 0.1};
print_student(s1);print_student2(&s2);return 0;
}
구조체 변수와 함수의 인자❖ 다음 코드에 대한 물음에 답하라
▪ 위 // 1)의 sum() 호출에 의해 배열 a의 내용이 변
하는가?
▪ 우측 // 3)의 print_student()에의해 구조체 s1의
내용이 변하는가?
▪ 우측 // 5)의 print_student2()에의해 구조체 s2의
내용이 변하는가?
❖ 다음 코드에 대해 물음에 답하라.
13
#include <stdio.h>int sum(int n[10]);
int main(void){
int a[10]={1,2,3,4,5,6,7,8,9,10};printf("Array Sum = %d\n",sum(a)); // 1)printf("Array Sum = %d\n",sum(a)); // 2)return 0;
}
int sum(int n[10]){
int i,s=0;for (i=0; i<10; i++) {
s = s+n[i];n[i] = s;
}return s;
}
#include <stdio.h>typedef struct student {
int id;char *pname;double points;
} STUD;void print_student(STUD s){
printf("[%d:%s] = %lf\n", s.id, s.pname, s.points);
s.id = 3;}void print_student2(STUD *ps){
printf("[%d:%s] = %lf\n", ps->id, ps->pname, ps->points);
ps->id = 4;}int main(void){
STUD s1 = {1, "Choi", 9.9};STUD s2 = {2, "Park", 0.1};print_student(s1); // 3)print_student(s1); // 4)print_student2(&s2); // 5)print_student2(&s2); // 6)return 0;
}
Intelligence Networking and Computing Lab.
구조체 변수와 함수의 인자
❖ C언어에서 구조체 변수와 배열 변수의 대입 및 함수 인자 처리 과정
에 차이가 있음에 유의하라
▪ 초창기 C 언어의 경우 구조체 변수 역시 배열 변수와 유사한 제약이 있었음
❖ 메모리 복사는 CPU의 효율을 떨어뜨리는 연산임
▪ 메모리 복사를 줄이는 것이 좋음
❖ 구조체 변수를 인자로 할 경우 “구조체 복사”가 좋을까? 아니면 “구
조체 포인터” 사용이 좋을까?
▪ 포인터의 경우 메모리 복사 부하를 최소화하는 장점
• 다만 함수 내에서 원하지 않는 구조체 내용 변경 등의 Side Effect가 발생할 수도 있음
14
Intelligence Networking and Computing Lab.
구조체의 배열
❖ 구조체에 대한 배열도 가능함. 구조체 배열 변수와 그 초기화 예
15
#include <stdio.h>typedef struct student {
int id;char *pname;double points;
} STUD;
void print_student(STUD s){
printf("[%d:%s] = %lf\n", s.id, s.pname, s.points);}
void print_student2(STUD *ps){
printf("[%d:%s] = %lf\n", ps->id, ps->pname, ps->points);}
int main(void){
STUD pnuecs[2] = { {1, "Choi", 9.9}, {2, "Park", 0.1} };
print_student(pnuecs[0]);print_student2(&pnuecs[1]);
return 0;}