13차시 구조체와 리스트 처리 입출력과...
TRANSCRIPT
13차시: 구조체와 리스트 처리 입출력과 운영체제
• 프로그래밍 및 실험
• 제 13주
• 동국대학교 조영석
이 문서는 나눔글꼴로 작성되었습니다. 설치하기
2
Chapter 10. 구조체와 리스트 처리
10.1 자기참조 구조체
- 자기 자신과 같은 형의 구조체를 포인트하는 포인터 멤버 필드를 갖는 구조체 - 동적 자료구조(dynamic data strutures)
(예) struct list { int data; struct list *next; } a;
next : NULL 또는 다음 list 원소의 메모리 주소를 가짐. NULL 은 list 의 끝.
a
↑
data next → link(연결)
3
- node의 작성
struct list a, b, c;
a.data = 1;
b.data = 2;
c.data = 3;
a.next = b.next = c.next = NULL;
↑ NULL
1 a
↑ NULL
2 b
↑ NULL
3 c
4
- node의 연결
a.next = &b;
b.next = &c;
- 연결된 원소의 자료 검색
a.next -> data : 2 (b.data)
b.next -> data : 3 (c.data)
a.next -> next -> data : 3 (c.data)
↑
1 a
↑
2 b
↑
3 c
═
5
10.2 선형 연결 리스트(Linear linked-lists)
- 구조체 자료들이 순차적으로 연결됨.
↑
1
↑
2
↑
3
═
↑
head
6
(예) "list.h"
#include <stdio.h> #include <stdlib.h>
typedef char DATA;
struct linked_list {
DATA d;
struct linked_list *next;
} ;
typedef struct linked_list ELEMENT;
typedef ELEMENT *LINK;
- 위의 명세들(typedef)은 기억장소를 할당받지 않음.
변수가 선언될 경우에만 기억장소를 할당함.
7
- 기억장소의 동적할당
(예)
LINK head;
head = malloc(sizeof(ELEMENT));
• ELEMENT type의 기억장소가 동적으로 할당된 후 그 주소가 head에 저장됨.
- linear linked - list의 작성 예
• 'n', 'e', 'w'를 저장하는 linear linked-list
head = malloc(sizeof(ELEMENT));
head
↑ ↑
8
head -> d = 'n';
head -> next = NULL;
head -> next = malloc(sizeof(ELEMENT));
head -> next -> d = 'e';
head -> next -> next = NULL;
head
↑ n ↑
head
↑ n ↑ ═
head
↑ n ↑ e ↑ ═
9
head -> next -> next = malloc(sizeof(ELEMENT));
head -> next -> next -> d = 'w';
head -> next -> next -> next = NULL;
head
↑ n ↑ e ↑ w ↑ ═
10
10.3 리스트 연산
- 기본연산
• 리스트 생성
• 원소 개수 세기
• 원소 탐색
• 두 리스트의 결합
• 원소 삽입
• 원소 삭제
11
(예) 문자열의 list 변환 - recursion(list는 재귀적으로 정의됨.)
#include "list.h"
LINK string_to_list(char s[]) { LINK head;
if (s[0] == '\0')
return NULL;
else { head = malloc(sizeof(ELEMENT));
head -> d = s[0];
head -> next = string_to_list(s + 1);
return head; } }
12
문자열 : s
A : call w/ s
B : call w/ s+1
C : call w/ s+2
a b c \0
a b c \0
head
↑ a ↑ ?
head
↑ b ↑ ?
head
↑ c ↑ ?
b c \0
c \0
13
D : call w/ s+3
return NULL;
C' :
B' :
A' :
head
↑ c ↑
\0
═ head
↑ b ↑ c ↑ ═
head
↑ a ↑ b ↑ c ↑ ═
14
- (예) 문자열의 list 변환 : repetition(반복)
#include "list.h"
LINK s_to_l(char s[]) { LINK head = NULL, tail; int i;
if (s[0] != '\0') { head = malloc(sizeof(ELEMENT)); /* 1st element */ head -> d = s[0]; tail = head;
for (i = 1; s[i] != '\0'; ++i) { tail -> next = malloc(sizeof(ELEMENT)); tail = tail -> next; tail -> d = s[i]; } tail -> next = NULL; } return head; }
15
• list w/ one element
• 두번째 element 첨부
• tail의 갱신
head
tail
↑
↑
a ↑ ?
head
tail
↑
↑
a ↑ ? ↑ ?
head
tail
↑
↑
a ↑ b ↑ ?
16
• 세번째 element 첨부
• tail의 갱신
• '\0'를 발견
head
tail
↑
↑
a ↑ b ↑ ? ↑ ?
head
tail
↑
↑
a ↑ b ↑ c ↑ ?
head
tail
↑
↑
a ↑ b ↑ c ↑
〓
17
10.4 리스트 처리 함수
- 리스트의 원소의 수를 세는 함수
• 재귀 version
int count(LINK head)
{
if (head == NULL)
return 0; else
return (1 + count(head -> next));
}
18
• for loop 사용
int count(LINK head)
{
int cnt = 0;
for ( ; head != NULL; head = head -> next)
++ cnt;
return cnt;
}
19
- 리스트의 원소를 출력
• 재귀 version
void print_list(LINK head)
{
if (head == NULL)
printf("\nNULL");
else {
printf("\n%c --> ", head -> d);
print_list(head -> next);
}
}
20
- 문자열 "abc"를 list로 바꾸고 그 list를 출력
#include "list.h"
LINK string_to_list(char []); void print_list(LINK); void count(LINK);
void main() { LINK h;
h = string_to_list("abc");
printf("The resulting list is \n");
print_list(h);
printf("\nNumber of elements : %d", count(h));
}
(실행결과)
The resulting list is
a --> b --> c --> NULL
Number of elements : 3
21
- 두 list의 결합
void concatenate(LINK a, LINK b)
{
assert(a != NULL);
if (a -> next == NULL)
a -> next = b;
else
concatenate(a -> next, b);
}
22
- 새로운 원소의 삽입 : 고정된 시간 안에 삽입가능.
(c.f. array : 배열의 길이에 비례)
• 삽입전
void insert(LINK p1, LINK p2, LINK q) { assert(p1 -> next == p2);
p1 -> next = q;
q -> next = p2; }
P1
P2
...
q
A ↑ C ↑
B ↑
...
〓
23
• 삽입 후
P1
P2
...
q
A ↑ C ↑
B ↑
...
24
- 원소의 삭제
• 삭제 전
/* temp = p -> next; */
p -> next = p -> next -> next;
/* free(temp); */
• 삭제 후
P
... A ↑ C ↑ B ↑ ...
P
... A ↑ C ↑ B ↑ ...
temp
25
- 리스트의 삭제 : 재귀호출
void delete_list(LINK head) {
if (head != NULL) {
delete_list(head -> next); free(head);
} }
26
Chapter 11. 입출력과 운영체제
11.1 출력함수 printf()
11.2 입력함수 scanf() 교재 pp. 511~520을 정독할 것.
11.3 fprintf(), fscanf(), sprintf(), sscanf()
- fprintf() : printf()의 file vresion
int fprintf(FILE *fp, const char *format, ... );
• FILE : stdio.h에서 정의
file의 현재 상태를 나타내는 member들을 가지는
특별한 구조체.
• fp가 point하는 file에 내용을 write함.
27
- fscanf() : scanf()의 file version
int fscanf(FILE *fp, const char *format, ...);
▪ fp가 point하는 file에서 내용을 read함.
- stdin, stdout, stderr
▪ stdio.h에 정의되어 있는 file pointer
▪ stdin : standard input
fscanf(stdin, ...) == scanf( ... )
▪ stdout : standard output
fprintf(stdout, ...) == printf( ... )
▪ stderr : standard error
fprintf(stderr, ...) == printf( ... )
28
- sprintf() : printf()의 문자열 version
▪ int sprintf(char *s, const char *format, ...);
s(문자열)에 format에서 정의된 대로 출력
- sscanf() : scanf()의 문자열 version
▪ int sscanf(const char *s, const char *format, ...),
s(문자열)에서 format에 정의된 대로 입력
29
(예) char str1[] = "1 2 3 go", str2[100], tmp[100];
int a, b, c;
sscanf(str1, "%d%d%d%s", &a, &b, &c, tmp);
sprintf(str2, "%s %s %d %d %d\n", tmp, tmp, a, b, c);
printf("%s", str2);
(실행결과)
a b c tmp
go go 1 2 3
1 2 3 g o \0 • • •
30
11.4 fopen()과 fclose()
- file : 문자들의 stream
- file의 특징
• 이름을 가짐
• 열리고(open) 닫힘(close)
• 읽혀지고, 씌여지고, 첨부될수 있음
• open 된 후 access가 가능 함
• 우발적인 오용은 막기위해 open하는 목적은 밝혀야 함.
(읽기 : "r", 쓰기 : "w", 첨부 : "a")
31
(예)
#include <stdio.h>
int main( ) { int a, sum = 0; FILE *ifp, *ofp; ifp = fopen("my_file", "r"); ofp = fopen("output_file", "w");
...
}
• "my_file"을 읽기 전용으로 open 하고
"output_file"을 쓰기 전용으로 open
32
(예)
while (fscanf(ifp, "%d", &a) == 1)
sum = sum + a;
fprintf(ofp, "The sum is %d.\n", sum);
fclose(ifp);
fclose(ofp);
33
• open mode
• 읽을수 없거나 쓸수 없는 file(존재하지 않는 file)을 open 하는 경우 fopen() 함수는 NULL을 return함.
모드 의 미
"r" 읽기 위해 문서 파일 열기
"w" 쓰기 위해 문서 파일 열기
"a" 첨부하기 위해 문서 파일 열기
"rb" 읽기 위해 이진 파일 열기
"wb" 쓰기 위해 이진 파일 열기
"ab" 첨부하기 위해 이진 파일 열기
모드 의 미
"r+" 읽기와 쓰기 위해 문서 파일 열기
"w+" 쓰기와 읽기 위해 문서 파일 열기
• • •
34
(예) copy a file to another
#include <stdio.h> main() { FILE *infile, *outfile; int ch;
printf("This program copies one file to another.\n");
infile = fopen("Old_File.txt", "r"); outfile = fopen("New_File.txt", "w");
while ((ch = getc(infile)) != EOF) putc(ch, outfile);
fclose(infile); fclose(outfile); }
35
(예) copy a file to another
#include <stdio.h> void CopyFile(FILE *infile, FILE *outfile); main() { FILE *infile, *outfile; printf("This program copies one file to another.\n"); infile = fopen("Old_File.txt", "r"); outfile = fopen("New_File.txt", "w"); CopyFile(infile, outfile); fclose(infile); fclose(outfile); }
void CopyFile(FILE *infile, FILE *outfile) { int ch; while ((ch = getc(infile)) != EOF) { putc(ch, outfile); } }
36
11.5 예제 : 파일에서의 한 줄 띄어쓰기 #include <stdio.h> #include <stdlib.h> void double_space(FILE *, FILE *); void print_info(char *); void main(int argc, char **argv) { FILE *ifp, *ofp; if (argc != 3) { print_info(argv[0]); exit(1); } ifp = fopen(argv[1], "r"); ofp = fopen(argv[2], "w"); double_space(ifp, ofp); fclose(ifp); fclose(ofp); }
37
void double_space(FILE *ifp, FILE *ofp) { int c; while((c = getc(ifp)) != EOF) { putc(c, ofp); if(c == '\n') putc('\n', ofp); /* double space */
} } void print_info(char *pgm_name) { printf("\n%s%s%s\n\n%s%s\n\n",
"Usage", pgm_name, "The contents of infile will be" "double-spaced", "and written to outfile."); }