l  보조기억장치의 특성 : 매체, 용량, 저장 장치, 접근 속도

l  접근하는 방식에 따라 직접 접근 기억장치 / 순차 접근 기억장치 구분

l  이동식 모터와 헤드 가진 기계식 장치

l  헤드가 원하는 데이터의 위치에 도달하기 위한 탐색시간, 데이터 전송 시간으로 인해 접근 속도 느림

l  탐색시간이 전송시간보다 길어 레코드나 블록으로 데이터 저장

 

1절  자기디스크

l  자기디스크는 원형 플래터 위에 자성으로 데이터 표현

l  플래터 : 하나의 중심 축에 여러 장 원판 쌓여 있는 형태

l  디스크 제어 레지스터가 메모리 매핑 입출력을 통해 직접 액세스 할 수 있음

l  디스크에 저장된 데이터는 디스크와 메모리 간의 블록 전송을 통해서만 엑세스 가능

l  디스크의 입출력 대역폭과 저장 공간을 고려해야 함

l  주기억장치 속도는 나노급, 보조기억장치 속도는 메가급이라 속도 차이 고려해야 함

l  디스크를 시스템에 연결하는 방식에는 IDE, SATA, SCSI, 광 채널, SAS 등 있음

 

1.     디스크의 구성

n  플래터 : 자성 재료로 덮인 두 표면. 비휘발성 저장 공간 제공

n  트랙 : 데이터가 기록되는 플래터 상의 위치. 섹터로 나누어짐

n  실린더 : 서로 다른 플래더에 있는 트랙이 형성하는 집단. 동심축에서 같은 거리에 있는 트랙 집합

n  섹터 : 트랙에서 주소가 지정되는 최소 단위 영역. 디스트 포맷하는 동안 설정됨

n  블록 크기는 여러 개의 섹터로 이루어짐

n  데이터 읽어오고 쓰는 순서

1)    헤드를 해당 트랙으로 이동

2)    데이터를 저장

3)    원하는 데이터가 저장된 섹터의 주소를 찾아감

 

2.     데이터 접근 시간

n  탐색시간 : 원하는 데이터가 저장된 트랙을 찾는데 걸리는 시간

n  회전 지연 시간 : 원하는 데이터 있는 섹터에 디스크 헤드가 도달하는 시간

n  데이터 전송시간 : 헤드가 데이터를 읽기 위한 시간

n  데이터 접근 시간 : 탐색시간 + 회전시간 + 전송시간

접근 시간은 실런더의 수, 데이터 밀도, 회전 속도와 비례

영향을 주는 다른 요인 : 출력 처리하는 CPU time, 주기억장치 경쟁, 제어기 경쟁, 체크섬 블록 교정, 버스 경쟁, 스케줄링 큐

 

3.     디스크 처리량

n  초당 데이터 처리 능력

n  데이터 크기를 데이터 전달 시간으로 나눈 값

 

4.     시스템 버스의 종류

1)    병렬 ATA(PATA)

u  기억장치 연결하는 표준 인터페이스

u  데이터 경로를 여러 개로 분산시켜 성능을 높이는 병렬 구조 특성 때문에 40개의 핀으로 구성된 복잡한 구조의 커넥터와 케이블 사용

u  장치 및 케이블 소형화 하는데 불리

u  신호의 누락, 오류 발생 할 여기 큼

u  안정성과 속도 저하

u  직렬 ATA로 대체됨

 

2)    직렬 ATA(SATA)

u  APTA에 비해 빠른 전송 지원

u  핫 스왑 지원 : 전원이 켜진 상태에서도 하드디스크 드라이브를 교체할 수 있는 기능

메인보드 및 운영체제에서 AHCI 규격 지원해야 가능

 

3)    SCSI

u  스카시

u  직렬 방식으로 컴퓨터 주변기기를 연결할 때 사용하는 표준 인터페이스

u  출력버스 접속하는데 필요한 기계적 전기적 요구 사항과 모든 주변기기 장치 중심으로 명령어 집합에 대한 규격

u  주변기기의 번호만 각각 지정해주면 자료 충돌 없이 주변 기기 제어 가능

 

4)    광채널

u  광섬유 케이블에 의해 전송된 광신호로 입출력자료를 실행

u  원거리 & 고속 정보 전송 가능

u  케이블, 접속 기구 등의 공간도 줄어 듬

 

5)    SAS

u  주기억장치로 데이터 송/수진할 수 있는 점 대 점 직렬 프로토콜

u  병렬 SCSI 버스 기술 대체함

 

2절  자기테이프

l  자기 테이프는 구멍 뚫린 천공카드에서 데이터 읽어 테이프상에 저장

l  백업 용도로 사용(저렴)

l  분류

운영 모드, 블록 모드, 스트리밍 모드

기록 시 고정헤드 사용, 이동식 헤드 사용

l  원판 모양 장치 릴 자기테이프 드라이버

l  블록 주소 : 제어 비트 포함 4바이트

l  블록 : 레코드로 구성. 레코드와 레코드 간에는 일정한 갭이 있어 레코드를 구분 -> IRG

l  블록 사이의 갭 : IBG

 

3절  광기억장치

l  레이저를 이용하여 데이터 기록

1.     CD-ROM

n  데이터 추가, 수정, 삭제 불가능

n  레이저 장치로 레이저 광선을 쏘아 CD-ROM의 구멍들을 읽어 비트 신호 만듦

n  표준 규격의 CD-ROM은 약 650MB 용량

n  동작 원리

(1)   디스크 표면에 홈을 파 미끄러움 방지

(2)   홈에 레이저 빔 쏴서 반사되는 빛 광센서로 검출

(3)   검출된 빛을 디지털 신호로 변환

(4)   데이터의 엑세스는 순차적 방식 사용

 

2.     DVD

n  CD와는 다른 포멧으로 저장 -> UDF로 저장

n  싱글 레이어 : 용량 4.7GB / 듀얼 레이어 : 8.5GB

듀얼 레이어는 DVD 기록 장치가 듀얼 레이어 지원해야 정상적으로 구울 수 있음

n  Digital Versatile Disc

 

3.     Flash Drive

n  USB 포트에 꽂아 쓰는 플래시 메모리

 

4절  레이드

1.     개요

n  데이터 저장 가상화 기술

n  데이터 중복성, 성능 향상 등을 위해 물리적 디시크 드라이브를 마치 1개의 디스크처럼 결합

상대적으로 저렴한 DISK를 다수 개 연결해서 성능 맞추자~ 는 발상

n  신뢰성은 떨어지지만 가격이 저렴

 

2.     구성 방식

1)    RAID-0

u  최소 드라이브 개수 : 2 / 최대 용량 : 디스크 수 * 디스크 용량

u  스트라이프 방식

u  데이터를 블록으로 나누어 블록 별로 다른 디스크에 저장

u  I/O 로드가 1/4가 되어 속도가 4!

u  동일한 용량의 하드를 사용해야 함

큰 용량 + 작은 용량 묶으면 작은 용량의 하드디스크로 하향으로 묶임

u  드라이브 하나라도 고장 나면 전체 디스크 배열이 고장 날 수 있음

u  디스크 추가할수록 위험 증가

 

2)    RAID-1

u  최소 드라이브 개수 : 2, 최대 용량 : 디스크 용량

u  미러링 방식

u  저장되는 모든 데이터는 N개의 물리적 디스크에 각각 저장 -> 모든 데이터는 복제됨

데이터 손실이나 유실 방지하기 위한 목적으로 사용

u  하나 고장 나도 안전

u  드라이브 두 개에 동일한 데이터 써야 되기 때문에

전체 용량의 절반 밖에 못쓴다는 단점

쓰기 성능이 나쁘지만 다른 방식보단 우수하다 ㅋㅋㅋㅋ 뭐지

 

3)    RAID-2

u  최소 드라이브 개수 : 3, 최대 용량 : (디스크 수 -1) * 각 디스크 용량

u  오류 정정 부호(ECC)를 기록하는 전용의 하드디스크 이용

u  비트 단위에 해밍코드 적용

u  하나의 멤버 디스크 고장 나도 ECC 이용해 정상적으로 작동 하지만 추가 연산 필요

è 입출력 속도 매우 나쁨

è 병목 현상!

u  ECC 기록용 디스크 수명이 다른 디스크에 비해 짧아져 지금은 쓰지 않음

 

4)    RAID-3

u  최소 드라이브 수 : 3, 최대 용량 : (디스크 수 -1) * 각 디스크 용량

u  데이터는 바이트 단위로 쪼개져 모든 디스크에 균등하게 분산 저장됨

u  패리티 정보가 별도의 전용 디스크에 저장

u  한 개 드라이브 고장 나는 것을 허용

u  순차적 쓰기 성능과 순차적 읽기 성능 우수

u  패리티 디스크에 장애가 발생하면 복구 불가능

u  임의 쓰기 성능 나쁘고 임의 읽기 성능은 좋음

 

5)    RAID-4

u  최소 드라이브 개수 : 3 최대 용량 : (디스크 수 -1) * 디스크 용량

u  모든 파일을 블록으로 쪼개고 각 블록은 여러 디스크에 저장되지만 불균등함

u  패리티를 처리하는 별도의 디스크 사용

u  동시 트랜잭션 사용량이 많은 시스템에서 읽기 속도 중요한 데 이런데 적합

u  읽기 성능은 좋지만 쓰기 성능은 나쁨

 

6)    RAID-5

u  최소 드라이브 개수 : 3, 최대 용량 : (디스크 수 -1) * 디스크 용량

u  블록 어느 정도 불균등하게 분산 저장

u  패리티 정보가 모든 디스크에 나눠 저장됨

u  한 개의 드라이브 고장 나도 운영 상 문제는 없음

u  ECC 드라이브를 분산시켜 병목현상 방지

u  ECC 알고리즘 때문에 RAID-0보다 성능 떨어짐

u  디스크 재구성이 매우 느리고 쓰기 성능도 패리티 정보 끊임없이 갱신해야 돼서 빠르지 않음

 

7)    RAID-6

u  최소 드라이브 개수 : 3, 최대 용량 (디스크 수 -2) * 디스크의 용량

u  데이크 블록은 모든 디스크에 분산 저장 항상 균등하지는 않음

u  패리티 정보 모든 디스크에 나뉘어 저장

u  두 개 드라이브 까지 고장 나는 거 허용

u  읽기 성능 우수

u  쓰기 성능은 패리티 여러 번 갱신해야 해서 RAID-5보다 나쁨

u  디스크 재구성하는 동안 성능이 매우 나빠질 수 있음

 

8)    RAID 1+0

u  최소 드라이브 개수 : 4, 최대 용량 : 디스크 수 / (RAID-1로 묶는 디스크 개수) * 디스크 용량

u  RAID-1방식으로 먼저 묶고 그 다음 RAID-0로 묶는 방식

u  RAID-0의 속도 + RAID-1의 안정성

 

9)    RAID 0+1

u  최소 드라이브 개수 : 4, 최대 용량 : 디스크 수 / (RAID-0로 묶는 디스크 개수) * 디스크 용량

u  RAID-0으로 먼저 묶고 그 다음 RAIN-1로 묶음

u  RAID 1+0보다 기술적으로 단순

확률적으로 안정성 떨어짐, 복구시간 오래 걸림

 

 


01장 컴퓨터 시스템 개요       

* 컴퓨터의 특징

1.     잘 정의된 형식으로 구성된 명령어에 응답한다

2.     사전에 기록된 명령어 목록을 실행한다

3.     대용량 데이터를 신속하게 검색하고 저장한다

* 임베디드 : 프로그램 된 하드웨어가 시스템 내에 들어가서 특정한 기능을 수행하는 것

 

1절  컴퓨터의 역사 및 발전 과정

1.     컴퓨터의 정의

n  산술 및 논리 연산을 수행하는 전자 장치

1)    데이터 : 수집 된 사실

2)    프로세싱 : 의미 있는 결과물을 뽑아내기 위해 사용자 또는 관련 데이터가 제공하는 명령

3)    정보 : 어떤 처리 작업의 마지막 형태 or 최종점. 출력 데이터가 의미가 있는 것

데이터의 입력을 통해 의미 있는 결과물을 출력한 것

4)    정보와 지식의 관계 : 교육, 학습, 숙련 등을 통해 사람이 재활용할 수 있는 정보와 기술

 

2.     컴퓨터의 역사 및 세대별 발전 과정

1)    컴퓨터의 역사

(1)   근대 컴퓨터 이전의 역사

(2)   근대 컴퓨터 이후의 역사

    마크원(MARK-1) “세계 최초의 기계식 컴퓨터” (1924 하워드 에어컨)

-      천공된 종이 테이프를 이용한 자동 순서 제어 계산기 사용

    에니악(ENIAC) "전자식 컴퓨터” (1943-1946 존 모클리 존에커트)

-      내부 구조 10진수 채용 / 외부 프로그램 방식

-      기억 용량 적음

-      최초의 전자식 컴퓨터라고 알려져 있지만 아님

    콜로서스 최초의 컴퓨터로 인정” (1943-1945)    

    에드삭(EDSAC) “최초의 프로그램 내장 컴퓨터” (1949 모리스 윌크스)

-      10진수 사용 / 프로그램 내장

    에드박(EDVAC) “최초의 이진수 사용 프로그램 내장형 컴퓨터” (1949)

-      2진수 사용 / 프로그램 내장

    유니박-1(UNIVAC-1) “최초의 상업용 컴퓨터

 

2)    컴퓨터의 세대별 발전과정

u  구성하는 구성 소자들과 함께 발전

 

(1)   1세대 (1940 ~ 1956)

o  진공관 / 메모리용 마그네틱 드럼 사용

o  프로그램 내장 방식 적용 -> 기계어로 작업 수행

o  입력 : 천공된 종이 카드/ 종이 테이프 -> 결과물 : 인쇄물

o  장점 : 빠른 컴퓨팅 기계 등장, 효율적 방법으로 복잡한 수학문제 풀 수 있게 됨

o  단점 : 특별한 목적으로 설계됨, 컴퓨터 무게크기가 엄청나 이동성 없음

 

(2)   2세대 (1957 ~ 1963)

o  트랜지스터 컴퓨터에 채택-> 진공관보다 작고 빠르고 에너지효율 높음

o  장점 : 어셈블리 언어 사용 -> 프로그램하기 쉬움, 전기 소모량 적음

o  단점 : 에어컨디션 환경 필요, 특별 용도로 한정된 컴퓨터들이 대부분

 

(3)   3세대 (1964 ~ 1975)

o  집적회로 : 트랜지스터를 반도체라 불리는 실리콘 칩에 소형화하여 배치 -> 컴퓨터 속도와 효율 대폭 향상

o  키보드 & 모니터 통해 컴퓨터와 상호작용

o  운영체제와 인터페이스하여 메모리를 모니터링 하는 중앙 프로그램으로 한 번에 여러 응용 프로그램 실행 가능

o  장점 : 다양한 고급 프로그램 언어들이 사용됨, 유지보수 시간 단축

 컴퓨터 크기와 무게 경량화, 소형화 시작

o  단점 : 저장 공간 능력 협소, 큰 프로그램 실행 시 처리 속도 감소

 

(4)   4세대 (1975 ~ 1989)

o  Intel 4004! -> 모든 컴퓨터 구성요소에 단일 칩 배치

o  소형 컴퓨터의 증가로 네트워크 시작! -> 인터넷!!

o  장점 : LSI VLSI 기술 사용으로 처리속도/엑세스 타임 향상, 스토리지 용량 증가

o  단점 : LSI VLSI 집의 와이어링 기술이 어려움, 처리속도 프로그래밍 명령어에 따라 좌우됨

 

(5)   5세대 (1990 ~ 현재)

o  병렬 처리와 초전도체 사용한 인공지능 갖춘 컴퓨터 시스템 출현

o  기술 결합, 융합으로 기술 재탄생

o  자연어를 처리하고 대응할 수 있는 시스템 만들고 스스로 학습하고 구성하는 능력 갖춘 컴퓨터를 만드는 것이 5세대 컴퓨터의 본질

 

2절  컴퓨터의 기본 구조

l  하드웨어 : 전자회로 + 기계장치

출력장치, 중앙처리장치, 기억장치 + 데이터 버스

l  소프트웨어 : 하드웨어 제어하여 작업 수행하는 프로그램

1.     하드웨어의 구성요소

1)    입력장치(Input Device)

u  데이터 및 제어신호를 컴퓨터 또는 전자장치와 같은 정보처리시스템에 제공하기 위해 사용되는 전기전자적인 하드웨어 장치

u  키보드 마우스 스캐너 디카 등등

 

2)    중앙처리장치(CPU)

u  산술, 논리, 제어, 출력 작업 수행

u  프로그램 명령어를 수행하는 컴퓨터 내의 전자회로

u  단일 집적 회로(IC) 침에 들어있는 마이크로프로세서가 대부분.  -> 마이크로컨트롤러 SoC

멀티코어프로세스 : 코어라고 불리는 두 개 이상의 CPU가 포함된 단일 칩

u  컴퓨터 전체의 동작을 제어

u  프로세서 레지스터(명령어 저장), 산술논리연산장치(ALU 비교판단연산), 제어부, 내부 버스

 

3)    기억장치(Memory Device)

u  명령어와 데이터를 저장하는 공간

u  주기억장치(CPU 현재 처리 중인 데이터 or 명령어 저장) / 보조기억장치(주기억장치 용량 확장)

u  RAM, ROM, FLASH 등의 칩 사용

 

4)    출력장치(Output Device)

u  CPU에서 처리되어 전자적으로 생성된 정보를 사용자가 읽을 수 있는 형태로 변환하는 장비

 

2.     소프트웨어의 분류

1)    시스템 소프트웨어

u  컴퓨터를 효과적으로 운영할 수 있도록 컴퓨터 하드웨어 및 응용프로그램 동작을 지시, 제어 및 실행하도록 설계된 컴퓨터 프로그램의 유형

u  하드웨어와 사용자 응용 프로그램 간의 인터페이스

u  운영체제(OS), 장치 드라이버, 펌웨어, 프로그램 언어 번역기, 유틸리티

(1)   운영체제(OS)

o  컴퓨터 하드웨어 및 소프트웨어 리소스를 관리, 공통 서비스 제공

 

(2)   장치 드라이버

o  컴퓨터 장치 및 주변 장치를 작동시키는 시스템 소프트웨어

o  마우스, 키보드, 사운드 카드, 디스플레이 카드, 네트워크 카드, 프린터 등

 

(3)   펌웨어(Firmware)

o  특정 하드웨어 장치에 포함된 소프트웨어. 플래시, ROM, EPROM 메모리칩에 내장된 웅영 소프트웨어 -> 하드웨어의 모든 활동을 직접 관리하고 제어함

o  플래시 메모리에 저장되어 반도체 칩 바꾸지 않아도 업그레이드 가능

o  BIOS DMB USB

 

(4)   프로그램 언어 번역기

o  상위 레벨 언어 소스 코드를 기계어 코드로 변환하는 프로그램

o  컴파일러, 어셈블러, 인터프리터 등

 

(5)   유틸리티 프로그램(Utilities)

o  시스템과 응용 프로그램 사이에서 위치하는 시스템 소프트웨어

o  시스템의 진단, 구성 및 최적화 / 유지관리 하도록 설계

o  컴퓨터 하드웨어, 운영체제, 응용 소프트웨어 관리하는데 필요

o  대체로 OS 번들로 제공

o  윈도우디펜서, 스마트스크린, 클리너, 응급 복구 디스크

 

2)    응용 소프트웨어

u  사무용 소프트웨어 / 멀티미디어 소프트웨어 / 통신용 소프트웨어

u  오피스 제품, 컴퓨터 통신용 웹 브라우저, 멀티미디어 재생기, 그래픽 프로그램, 분석소프트웨어, 협업소프트웨어, 데이터베이스 등

 

3.     프로그래밍 언어의 종류

n  프로그래밍 언어 : 특정 알고리즘이나 계산의 결과값을 출력하기 위해 사용하는 표기법

n  나는 프로그래밍 언어론도 선택했어……

n  초급 / 중급 / 고급 언어로 구분

 

3절  폰 노이만 구조

l  프린스턴 구조!

l  현대 전자 디지털 컴퓨터의 모델

l  특징 3가지

1)    컴퓨터는 4가지 하부 시스템으로 구성

기억장치

산술연산장치

제어장치

출력장치

2)    실행하는 동안 프로그램은 기억장치에 저장됨

3)    프로그램 명령어는 순차적으로 처리

 

4절  컴퓨터의 분류

1.     크기와 용량에 의한 분류

 

2.     사용목적에 의한 분류

 

3.     데이터 처리방식에 의한 분류

 

 

4.     처리방식에 의한 분류

 

 

5절  클라우드 컴퓨팅

l  구성 가능한 컴퓨터 시스템 리소스와 상위 수준 서비스를 누구든지 공유하여 사용할 수 있는 시스템

l  인터넷에 연결된 다른 컴퓨터로 처리하는 기술

l  클라우드 컴퓨팅의 모델

n  사용자의 관점에서 SaaS, IaaS, PaaS 3가지 모델 있음

n  필요한 자원을 하나의 거대한 스토리지 장치에 올려 두고 언제 어디서나 인터넷을 통해 필요한 자원을 올리거나 다운로드 받을 수 있는 공간(승인 필요)

1)    IaaS(Infrastructure as a Service)

u  데이터센터를 구축하는 대신 인터넷을 통해 서버와 스토리지 등 타사의 데이터 센터의 자원을 빌려서 사용할 수 있는 서비스

u  빌려온 인프라에 사용자는 운영체제를 설치하고, 애플리케이션 등을 설치한 다음 원하는 서비스 운영

u  넷플릭스.. 같은거 -> 자체 데이터센터 구축한 다음 서비스 운영하는 데신 AWS IaaS 서비스 이용하는 방식 채택

 

2)    PaaS(Platform as a Service)

u  소프트웨어 서비스 개발할 때 필요한 플랫폼 제공하는 서비스

u  필요한 서비스를 선택해 애플리케이션 개발-> 개발자가 소프트웨어 개발할 때 필요한 API제공

u  고객은 데이터와 응용 프로그램에 대해서만 관리하면 됨

u  세일즈 포스 닷컴 같은 거

 

3)    SaaS(Software as a Service)

u  클라우드 환경에서 운영되는 애플리케이션 서비스

u  모든 서비스가 클라우드에서 이루어지고 웹에서 소프트웨어 빌려 쓸 수 있음

u  구글 앱스, 세일즈 포스 닷컴, MS오피스 365, 드롭박스 등

 

6절  4차 산업혁명의 핵심 기술

1.     사물 인터넷(IoT : Internet of Things)

n  사물 인터넷은 각종 사물에 센서와 통신 기능을 내장하여 인터넷에 연결하는 기술

n  인터넷으로 연결된 사물들이 데이터를 주고받아 스스로 분석하고 학습한 정보를 사용자에게 제공하거나 사용자가 이를 원격 조정할 수 있음

n  가전제품, 모바일 장비, 웨어러블 디바이스 등 다양한 임베디드 시스템

n  자신을 구별할 유일한 IP를 가지고 인터넷으로 연결되어야 함

n  사물인터넷의 발달 & 보안 발달 함께 성장해야 함

 

2.     인공지능

n  기계에 의해 증명된 지능

n  환경을 인식하고 목표를 성공적으로 달성할 기회를 최대화 하는 시스템

n  인간의 학습 능력과 추론 능력, 지각능력, 자연언어의 이해능력 등을 컴퓨터 프로그램으로 실현

n  구글 딥마인드 개발 알파고 같은 거

 

3.     나노기술

n  10억분의 1미터인 나노미터 단위에 근접한 원자, 분자 및 초분자 정도의 작은 크기 단위에서 물질 합성하고, 조립, 제어하고 그 성질을 측정, 규명하는 기술

n  나노 기술 적용으로 성능 개선, 극소형화, 저전력화, 가격 저렴화 등 유리한 기술임

 

4.     자율주행 자동차

n  운전자의 조작 없이 자동차 스스로 주행환경을 인식하여 목표지점까지 운행할 수 있는 자동차

n  무인 자동차

n  생명안전, 공해 저감 경제 개선 견인할 잠재력 있는 기술

 

5.     3D 프린터

n  물질이 함께 첨가되어(액체 분자 또는 분말 입자가 융합되는 등) 3차원 물체를 만들기 위해 컴퓨터 제어 하에 재료가 결합하거나 응고되어 원하는 물건을 만들어내는 프린터

n  3D모델의 디지털 모델 데이터 또는 AMF 파일 같은 다른 전자 데이터 소스를 사용하여 생성

 

6.     빅데이터

n  스마트폰의 혁신, SNS 사용으로 데이터 양이 기하급수적으로 증가

n  데이터를 수집, 가공, 분석하여 고객의 행동 패턴을 파악하고 그에 따른 전략을 수립하기 위한 도구

 

 

08 파일 처리 함수

1절  파일 입출력

l  데이터를 미리 저장한 파일로 입력 받고 결과를 파일로 저장

l  <stdio.h>이 파일 입출력 함수 제공

1.     파일

n  파일 : 디스크나 자기 테이프 등과 같이 보조기억장치에 파일명으로 저장된 물리적 데이터 집합체

n  프로그램 파일 / 데이터 파일로 나뉨

1)    프로그램과 데이터

u  프로그램 : 특정 문제를 해결하기 위해 CPU가 실행할 명령을 모아둔 파일

u  데이터 : 프로그램 파일이 실행되면서 처리할 데이터 or 프로그램 실행 동안 처리한 결과 모아둔 파일

 

2)    파일에 저장된 데이터 형식에 따른 분류

(1)   텍스트 파일 : 파일 내용이 사람이 알고 있는 문자로 표시

사용자가 키보드로 직접 입력해서 만든 프로그램 소스파일/ 메모장에서 작성한 파일

(2)   이진 파일 : 컴퓨터의 특정 프로그램에 의해서만 읽을 수 있는 파일 (exe 파일, 음악/이미지 파일)

 

3)    파일은 접근 방식에 따른 분류

(1)   순차(sequential) 파일

o  데이터를 처음부터 순차적으로 읽거나 씀

o  이미 읽은 데이터를 다시 읽으려면 파일을 닫은 다음 다시 열어야 됨

o  파일의 맨 처음부터 읽어서 원하는 위치까지 이동하여 데이터를 읽어야 함

 

(2)   랜덤(random) 파일

o  파일의 어느 위치든 곧바로 이동하여 읽고 쓰기 가능

o  어떤 파일이든 순처적으로 접근할 수도 있고 임의적으로 접근할 수 도 있음

 

2.     파일 처리 과정

n  파일 포인터 선언 -> 파일 열기 -> 파일 읽기 -> 파일 닫기

1)    파일 포인터 선언

u  FILE 구조체형 포인터 필요 -> ‘파일 포인터라고 함

u  FILE : 헤더파일  stdio.h에 정의된 구조체 자료형. 파일 읽/쓰에 필요한 정보 저장하는 구조체

u  작업 대상인 파일의 정보를 전달하는 인수로 사용

u  파일 포인터가 할당되어 있는 파일에 대해서만 읽/쓰 가능

u  FILE *파일 포인터 변수명

FILE *fp;

 

2)    파일 열기 : fopen( )함수

u  파일을 open하는 작업 -> FILE 구조체를 파일 포인터와 연결

u  운영체제에게 파일 사용하겠다고 요청하는 것

u  파일 포인터 변수명 = fopen(“파일명”, ”모드”);

o  fopen 함수 : “파일명의 파일을 모드에 맞게 open한 후 파일 정보가 든 FILE구조체의 시작주소 반환

o  fopen함수가 반환한 FILE구조체 시작주소를 파일 포인터에 연결해 포인터가 참조하게 함

o  파일 열기 실패 -> NULL 반환

o  모드 : 파일 읽기 (r), 쓰기 (w) 등 지정하고 참조모드 형태모드 조합 !

 

(1)   파일 참조 모드



(2)   파일 형태 모드

 

o  파일명만 명시하면 현재 작업중인 프로젝트 폴더 안에서 파일 찾음

o  절대 경로로 명시하면 절대경로에서 파일 찾음

o  FILE *fp = fopen(:data.txt”, “w”);

                     

(3)   NULL문자 반환

o  파일 열기 실패하면 NULL문자 반환 -> 파일 관련 어떠한 작업도 더 이상 처리 안됨

o  보통 프로그램 강제로 종료하도록 exit(1); 을 함

o  FILE *fp = fopen(“data.txt”, “r”);

if(fp==NULL)

      exit(1);

 

3)    파일 입출력 함수


 

4)    파일 닫기 : fclose( )함수

u  파일 읽/쓰기 끝나면 프로그램 종료 전 반드시 열린 파일 닫아야 함

u  fclose(파일 포인터 변수명);

o  파일 포인터명과 연결된 파일이 닫히고 파일 포인터와의 연결이 해제됨

o  연결 해제된 파일 포인터는 다음 파일 다시 연결해 사용 가능

o  파일 닫기 성공하면 0 반환 / 실패하면 -1 반환 (EOF상수 : END OF FILE)

 

3.     형식을 지정한 파일 입출력

n  형식에 맞추어 읽고 쓰는 fsanf() / fprintf()! 일반 파일 뿐 아니라 장치 파일까지 입출력 할 수 있음

n  기존 파일 내용 프로그램서 읽으려면 파일에 저장된 데이터 형식 순서 알고 그에 맞게 읽어야 함

 

1)    형식을 지정한 파일 출력 : fprintf( )함수

u  fprintf(파일 포인터 변수, “변환명세 포함한 형식 문자열”, 변수명);

o  변수에 저장된 값을 형식문자열에 맞게 변환하여 파일포인터 연결된 파일에 기록

o  변수 대신 상수, 수식 가능

u  파일 포인터 변수명을 stdout으로 지정하면 모니터로 출력됨

int age = 2;

fprintf(fp, “나이 : %d”. age);

fprintf(stdout, “나이 : %d”. age);

 


u  변환 명세 형식 문자열에 빈칸이나 엔터키를 입력하여 데이터 간 구분 필요

 

2)    형식을 지정한 파일 입력 : fscanf( )함수

u  fscanf(파일 포인터 변수, “변환 명세”, &변수명)

파일 포인터에 연결된 파일에서 변환명세에 맞게 데이터를 한 개 읽어 변수명에 저장

파일 포인터 변수명을 stdin으로 지정하면 키보드에서 입력 받음

읽기에 실패하거나 파일의 끝에 도달하면 EOF 반환(성공 0 /실패 -1)

u  변환 명세 끝에 빈칸 / \n X, 일반 문자를 변환명세에 포함 X

u  FILE *fp=fopen(“read.txt”);

fscanf(fp, “%d”, &age);      --->      이러면 안됨       fscanf(fp, “ : %5d ”, &height);

                                                         변환명세에 공백, 일반 문자 X 필드폭 사용 비추

 

3)    파일 추가

u  파일 참조에 추가모드로 파일을 열어 파일의 끝에 자료 추가

u  실행결과와 같은 파일에 새 실행결과를 저장하고 싶을 때 사용

u  open할 파일 없으면 지정한 파일 이름으로 파일 새로 생성

u  fp = fopen(“text.txt”, “a”);

 

4)    파일의 끝 확인

(1)   feof( ) 함수 활용하기

o  책갈피 역할!

o  읽기/쓰기 시작할 위치를 가리키는 파일 위치 지시자(FILE 구조체의 포인터 멤버)

-      파일 위치 지시자 file position indicator -> FPI로 써야지 귀찮아

o  파일 입출력 함수 호출 시 인수로 지정한 파일 포인터가 가리키는 file구조체의 FPI가 가리키는 곳부터 읽기/쓰기 진행

-      파일 닫으면 파일 마지막 데이터 다음에 시스템에 의해 파일 끝 표시하는 특별한 문자 자동으로 저장됨(시스템만 인식 가능 ^Z(ctrl+Z)로 표현)

-      FPI가 이 특별 문자 가리킬 때 읽기 시도 -> 더 이상 읽을 데이터 없으므로 FPI는 파일의 처음 위치로 수정됨

-      FILE 구조체의 특정 플래그가 파일 끝 지났음을 표시 (1로 세팅됨)

-      플래그가 1로 세팅된 경우면 파일에서 더 읽을 자료가 없음을 의미 -> 읽기를 그만둠

 

o  feof(파일 포인터 변수명)

-      파일 포인터 변수명이 가리키는 FILE구조체에서 파일 끝 지났음을 알려주는 플래그를 참조하여 반환 값을 반환

 

o  파일 끝(문자)를 지나갔을 때 0이 아닌 값( = 1) 반환 (도달했을 때가 아님)

-      프로그램 실행을 통해 만들어지는 파일이 상황에 따라 빈 파일 만들어 지기도 함

-      데이터 전혀 없는 빈 파일 끝에는 끝 나타내는 특수문자만 포함

-      빈 파일 열고 feof( )호출하면 0 나오는데, FPI 맨 끝을 가리키기만 함

-> 끝 문자를 지나가지 않았기 때문

 

o  feof( ) 함수 사용의 잘못된 예

1

2

3

4

5

while (!feof(fp))

{

  fscanf(fp, “%d”, &age);

printf(“%2d \n, age);

}

라고 했을 때

      fp 참조 파일에 아무 데이터 없을 때

- 1 ~ 5 : FPI는 특수문자 가리키므로 !feof()는 참 (!0)

- 3 : 조건이 참이라 실행 되지만 안에 읽을 정수 없어서 age에 값 저장 안됨

- 4 : age 초기화 안되어 쓰레기 값 출력

 

 

파일이

20

21

22

 

이렇다면

fp 참조 파일에 3명 나이 저장되어 있을 때 데이터가 개행 문자로 나뉘어져 있다면

- 1 ~ 5 : FPI는 파일의 처음을 가리킴

FPI가 가리키는 곳에서 데이터를 읽고 age에 저장하는 것을 반복하나 파일의 데이터 뒤 개행 문자가 있으므로, 데이터를 읽은 후 개행 문자를 가리키게 됨

처음 20 읽고 저장 -> FPI는 그 뒤 개행 문자 가리킴

개행 문자 무시하고 그 뒤 21 읽고 저장 -> FPI는 그 뒤 개행 문자 가리킴

개행 문자 무시하고 그 뒤 22 읽고 저장 -> FPI는 그 뒤 개행 문자 가리킴

개행 문자를 가리키므로 데이터는 끝났으나 while 조건문 !feof(fp)가 아직 참

while문을 한 번 더 반복 함

- 3 : FPI가 읽은 개행 문자는 읽은 후 무시하고 정수 읽으려 하지만 파일 끝 문자 지나게 되고 읽을 정보 없어서 EOF 반환

- 4 : 이 전에 age 저장되었던 마지막 값을 출력. 같은 나이가 또 출력됨

 

(2)   fscanf( ) 함수의 반환 값을 활용

o  fscanf( ) 함수는 파일 끝에 도달하거나 오류가 나면 EOF 반환

o  파일 읽기 시도 한 후 fscanf( ) 함수 반환 값 확인 해 읽기 성공여부 확인 가능

o  선호하는 방법!

o  while (fscanf(fp, “%d”, &age) !=EOF)

printf(“%2d \n, age);

 

4.     문자 단위 파일 입출력

n  파일에 저장된 모든 데이터는 연속된 바이트로 구성, 어떠한 파일도 바이트 단위로 쓰고 읽기 가능

 

1)    문자 단위로 파일에 쓰기 : fputc( )함수

u  문자 단위로 씀

u  fputc(문자, 파일 포인터 변수명);

문자를 파일 포인터 변수가 가리키는 파일에 씀

fputc(‘a’, fp);

u  fputc(정수, 파일 포인터 변수명);

ASCII 코드 값이 정수에 해당하는 문자 한 개를 파일 포인터 변수가 가리키는 파일에 씀

fputc(67, fp);

 

2)    문자 단위로 파일 읽기 : fgetc( )함수

u  파일에서 문자 한 개를 읽어 반환

u  fgetc(파일 포인터 변수명);

o  반환형을 읽은 문자의 ASCII코드 값이 반환됨 -> int

o  읽기 오류 발생하거나 파일 끝에 도달하면 -1에 해당하는 EOF상수 반환

o  char ch;

FILE *fp = fopen(“data.txt”, “r”);

ch = fgetc(fp);

 

5.     문자열 단위 파일 입출력

n  텍스트 파일에 저장된 내용을 문자열 단위로 입출력 함수 fputs( ), fgets( )

n  puts( ), gets( )와 개행 문자 다루는 데 있어 차이가 있음 ! 주의 필요

1)    문자열 단위 출력 : fputs( )함수

u  문자열 단위로 파일 쓰기

u  자동으로 개행 문자 넣지 않음

u  fputs(문자열 시작 주소, 파일 포인터 변수명);

o  문자열 시작 주소에 저장된 문자열을 파일 포인터에 연결된 파일에 씀

o  문자열의 끝을 나타내는 널문자 파일에 쓰지 않음

o  개행 문자 자동으로 추가 X

o  출력 성공하면 출력한 바이트 수 반환, 실패하면 EOF 반환

u  fputs(“문자열 단위 출력 \n”, fp); 처럼 같이 출력할 문자열에 포함된 개행 문자는 출력

 

2)    문자열 단위 출력 : fgets( )함수

u  파일에 쓰여진 개행 문자까지 문자열에 포함시킴

u  한 번에 읽을 수 있는 문자열 길이 정해져 있어 행이 길면 행 전체를 못 읽을 수도 있음

o  한 행 단위로 읽고 싶으면 최대 입력 문자 수를 충분히 크게 지정

u  fgets(문자열 저장 주소, 최대 입력 문자 수, 파일 포인터 변수명)

o  파일 포인터에 연결된 파일에서 (최대 입력 문자수 – 1)개의 문자 읽은 후 뒤에 널문자(\0) 합친 문자열을 지정한 문자열 저장 주소부터 저장

o  최대 입력한 문자 개수만큼 읽지 않았지만 중간에 개행 문자(\n)읽으면 읽기 쥥단하고 뒤에 널문자 합친 문자열 저장 -> 개행문자도 문자열에 포함

o  파일 끝에 도달하거나 오류 발생시 NULL포인터 반환

 

2절  이진 파일 입출력

l  텍스트 파일은 모든 데이터가 문자열로 변환되어 기록됨

n  fprintf( ) : 정수를 문자로 변환하여 파일에 기록

n  fscanf( ) : 파일에서 문자로 된 숫자를 읽어 정수로 변환하여 변수에 저장

 

l  이진 파일은 수치 데이터가 문자로 변환되지 않고 곧바로 수치로 저장됨

n  수치를 읽을 때 한 개의 수치로 바로 읽음 -> 수치와 문자열 간 변환 과정 없음

n  읽고 쓰기 빠름 / 저장 공간 적게 차지(정수의 경우 언제나 4바이트 이므로)

n  컴퓨터 기종이 다를 경우 수치 표현 방식이 다를 수 있음 -> 내용 달라질 수 있음

 

l  이진 파일은 행으로 분리되지 않음

n  행의 끝 표시할 필요 없음

n  널 문자, 개행 문자 같은 글자들도 특별한 의미 없이 데이터로 취급

n  눈으로 내용을 확인하기 어려우므로 특정 프로그램 사용해야 함

 

l  FILE *fp = fopen(“파일명”, “wb/rb/ab”);

n  형태 모드 주의!

u  wb : 이진 파일 쓰기 전용

u  rb : 이진 파일 읽기 전용

u  ab : 이진 파일 추가 전용

 

1.     이진 파일에 쓰기 : fwirte( ) 함수

n  블록 (block 바이트 단위의 연속된 데이터 집합)으로 파일 씀

u  일정한 크기의 데이터를 통째로 읽거나 쓸 수 있음

n  fwrite( )함수 이용해 만들어진 파일에서 데이터 읽어올 때 블록 크기에 주의해서 정확한 크기의 블록단위로 읽어와야 함

n  fwrite(데이터 시작 주소, 블록 크기, 블록 개수, 파일 포인터 변수명);

u  데이터 시작 주소부터 저장된 (블록 크기 * 블록 개수) 바이트의 데이터를 파일 포인터 변수에 연결된 이진 파일에 쓴 후 파일에 쓴 블록 개수 반환

u  블록 크기 : 바이트 단위 / 블록 개수 : 정수

u  이진 파일에 쓰는 데이터 형은 달라도 됨. 이진 파일에서 읽어올 때 데이터 기록한 순서와 정확이 일치하도록 읽어와야 함

int age[10] = {20,21,22,23,24,25,26,27,28,29}

fwrite(age, sizeof(int), 10, fp);

double height = 175.5;

fwrite(height, sizeof(double), 1, fp);

 

2.     이진 파일에 읽기 : fread( ) 함수

n  이진 파일에서 데이터 블록 읽어 오는 함수

n  fread (데이터 저장 시작 주소, 블록 크기, 블록 개수, 파일 포인터 변수명);

u  파일 포인터 변수에 연결된 파일에서  (블록 크기 * 블록 개수) 바이트의 데이터를 읽어서 시작 주소에 저장 후 읽은 블록 개수 반환

u  블록 크기 : 바이트 단위 / 블록 개수 : 정수

u  데이터 저장 시작 주소에 해당하는 기억장소는 (블록 크기 * 블록 개수) 바이트의 데이터 저장하기에 충분한 기억장소여야 함

 

n  int age[10];

FILE *8fp = fopen(“data.bin”, “rb”);

fread(age, sizeof(int), 10, fp);

 

3절  파일의 임의 접근

l  임의 접근 : 파일 읽기/ 쓰기를 순서대로 X -> 임의의 위치에서 바로 읽기/쓰기 할 수 있는 접근 방식

l  파일 위치 지시자 조작하는 함수로 읽기 쓰기 시작 위치 조정 -> 커서

 

1.     파일 위치 지시자 이동하기 : fseek( ) 함수

n  fseek(파일 포인터 변수명, 오프셋, 기준점)

u  파일 위치 지시자가 기준점으로부터 오프셋만큼 떨어진 곳을 가리키게 함

u  읽기 쓰기 시작 위치 = (기준점 + 오프셋) 바이트 위치

u  이동에 성공하면 0 반환, 실패하면 0이 아닌 값 반환

 

n  기준점

u  SEEK_SET : 0. 파일의 시작 지점 의미

u  SEEK_CUR : 1. 파일의 현재 지점 의미

u  SEEK_END : 2. 파일의 끝 지점 의미

 

n  오프셋 : long형 정수. 기준점 이전이면 음수 / 기준점 이후면 양수 사용

 

n  fseek(fp, 100, SEEK_SET);

 fseek(fp, 100, SEEK_CUR);

 fseek(fp, -100, SEEK_END);


 

2.     rewind( ) 함수

n  rewind(포인터 변수명)

파일 포인터에 연결된 파일의 다음 읽기/쓰기 위치를 파일의 시작 지점으로 이동

= fseek(fp, 0, SEEK_SET);

 

3.     ftell( ) 함수

n  현재 파일의 읽기/ 쓰기 위치 알려줌 (파일 위치 지시자(FPI)가 가리키는 곳을 알려줌)

n  파일의 시작 위치가 상대적으로 0

현재 FPI가 가리키는 곳이 파일의 시작위치로부터 몇 바이트 떨어져 있는지 반환

n  ftell(파일 포인터 변수명)

position = ftell(fp);


1절  구조체

1.     구조체

n  사용자 정의 자료형!

n  다양한 자료형의 여러 값을 하나의 단위로 묶어 편리하게 관리하고 사용

n  여러 가지 다른 관련된 데이터들을 하나로 묶어 정의


 

2.     구조체의 개념

n  자료형이 다른 값들을 묶어서 관리할 수 있는 사용자 정의 자료형

n  대입문에서 편리 : 구조체 변수 간의 대입으로 한 개의 대입문으로 대입 끝(원소 하나하나 접근X)


3.     구조체의 정의와 변수의 선언

n  구조체형 변수에 선언하려면 사용하기 전

템플릿(미리 사용할 구조체의 형태)을 먼저 정의 구조체 변수를 선언

 

1)    구조체의 정의

u  구조체 멤버(필드) : 구조체를 구성하는 원소

o  배열의 기본 구성단위인 배열 원소에 해당

o  배열원소와 달리 자료형이 서로 달라도 됨

-      배열은 모든 원소가 같은 자료형 -> 기억장소 크기가 같음

-      구조체는 구성하는 멤버가 자료형이 서로 달라도 됨 -> 멤버마다 기억장소 크기 다름

u  구조체의 정의 : 구조체의 구조를 컴파일러에게 알려주는 것

o  템플릿을 정의하는 것! 기억장소를 할당 받는 것이 아님! -> 선언

o  struct : 구조체 예약어.

o  구조체 태그명 : int같은 자료형에 해당한다고 보면 됨. 식별자 생성규칙 따름

o  구조체 정의 마지막에 반드시 “; ”  붙임

o  구조체 태그명과 멤버 명은 달라야 함

o  구조체를 정의하는 위치에 따라 구조체를 자료형으로 사용할 수 있는 범위 결정됨

struct student_info

{         

char name[10];

int grade;

double score[4];

};

- struct : 구조체 표시 예약어

- 구조체 태그명 : 사용자 정의 구조체 자료형 이름

- 자료형 멤버 : 멤버는 선언문 형태로 순서대로 명시

- 멤버 : 변수, 배열, 이미 정의된 다른 구조체 등

- 끝에 반드시 “ ; ” 붙여야 됨

 

2)    구조체 변수 선언

u  구조체에 실제 데이터 저장하기 위해 기억장소를 할당 받는 것

u  struct 구조체 태크명 구조체 변수명;

u  선언 시 주의사항

o  구조체 태그명 앞에 struct 붙이지 않으면 오류 발생

u  선언 위치에 따른 분류

o  지역 변수 : 함수 안에 선언

o  전역 변수 : 함수 밖에 선언

o  정적 변수 : struct 앞에 static 붙임

u  구조체 변수의 선언 위치

o  구조체 템플릿을 정의 한 후 선언

o  구조체 템플릿 정의하면서 동시에 선언 가능

o  구조체 태그명 생략하면 자료형의 이름이 없는 결과 -> 인수나 반환값으로 사용X

 

3)    구조체 멤버 참조

u  멤버 연산자 “ . (dot) ” : 구조체 안의 특정 멤버들을 참조할 때 소속을 밝히는 것

u  구조체 변수명.멤버명

o  구조체 변수명.멤버명; 전체가 한 개의 변수처럼 사용됨

o  scanf( )함수에서 입력값 저장 주소 구하는 & 사용법 : '&구조체 변수명.멤버명

stud.grade = 1;

scanf(“%d”, &stud.name[2]); //배열 원소에 직접 닫닫

scanf(“%d”, stud.name); //배열이름이 포인터!


4)    구조체 변수의 초기화

u  구조체도 변수! 초기화 가능

u  { } 안에 구조체 멤버의 초기값을 “ , (쉼표)”로 구분하여 나열, 순서대로~

 

(1)   구조체 변수를 선언하면서 동시에 초기화하기

o  struct 구조체 태그명 구조체 변수명 = {멤버 초기값1, … 멤버 초기값n};

struct student_info stud01 = { “박보검”, 4, {4.7 , 4.5, 4.3, 4.1}};

o  선언문 끝난 후에는 구조체 변수에 { }를 이용하여 초기화 할 수 없음

멤버 별로 각각 초기화

stud01.grade = 3;

 stud01.score[3] = 4.1; 처럼

 

(2)   구조체 정의, 선언, 초기화 한번에 하기

o  struct 구조체 태그명 ( 자료형 멤버; ,,, 자료형 멤버n; ) } 구조체 변수명 = { 초기값 들 };

o  구조체 변수명 앞에 static 붙이면 정적 변수 됨

struct student_info { 

char name[10];

int grade;

double score[4];

} static stud = = { “박보검”, 4, {4.7 , 4.5, 4.3, 4.1}};

 

5)    구조체 간의 대입

u  같은 구조체형일 경우 하나의 대입문으로 모든 멤버 간 대입 처리

u  구조체형 변수끼리는 구조체 단위로 대입문 사용

(1)   같은 구조체형 변수 간의 대입

o  구조체 변수명 1 = 구조체 변수명 2;

o  struct TV tv1 = {“lg”, 2020, 1900000}, tv2;

tv2 = tv1; // -> tv2.comp = tv1.comp; tv2.year = tv1. year; tv2.price = tv1. price; 와 같음

(2)   동일한 구조체의 템플릿에서 구조체 태그명이 다른 경우의 대입

o  구조체 테그명이 다르면 대입문 사용 X  à  멤버 변수간 대입은 가능


6)    자료형 이름 재정의 : typedef

u  변수를 선언하거나 캐스팅할 때 사용하는 자료형의 이름을 원하는 대로 정의해 사용 가능

u  자료형의 재정의!

u  프로그램의 이식성

u  자료형 이름을 짧게 재정의하거나 읽기 쉽게 함

 

(1)   자료형 이름의 재정의 형식

o  typedef 기존 자료형 이름 새로운 자료형 이름;

o  typedef double REAL;             double avg -> REAL avg;

typedef int* INTP;                 int* ptr -> INTP ptr;

typedef struct person PS;        struct person user -> PS user;

귀찮은 것이 줄어들지

 

(2)   주의사항

o  새로운 자료형 생성 X -> 기존 자료형에 별명을 붙인다! (alias 같이)

o  기본 자료형(int, double, … ) + 사용자 정의 자료형 + 이전 typedef로 재정의한 자료형 적용가능

à 일반 변수명 같은 것은 X

o  #define 전처리기 지시자랑 비교, #define은 컴파일전 처리되고, typedef는 컴파일러가 처리

o  구조체 정의하며 곧바로 typedef로 자료형 재정의 가능

typedef struct point { int x, y, z; } POINT;

POINT p1 = {1, 3, 6}; // = typedef struct point p1 = {1, 3, 6}; 와 같다

 

4.     구조체 배열

1)    구조체 배열 선언

u  자료형 명시하는 자리에 struct 구조체 태그명 써줌

(1)   구조체 배열 선언

o  struct 구조체 태그명 구조체 배열명[원소 개수];

struct person user[100]; // person형 구조체 100개 저장할 배열

struct student_info stud[200]; // student_info형 구조체 200개 저장할 배열

 

(2)   구조체 배열의 선언과 동시에 초기화

o  struct 구조체 태그명 구조체 배열명[원소수] = {{멤버 값1 , … }, {멤버 값1,…}… {멤버 값1…}};

struct person user[100]={{“박보검”, “”, 26}, {“서강준”, ””, 26}, .. {“축복의”, ”1993”, 26}};

 

(3)   초기화할 때 주의 사항

o  마지막 멤버들은 생략 가능해도 중간 멤버들은 생략이 안된다! 순서대로~

o  struct person user[100]={{“박보검” }, {“서강준”, ””}, .. {“축복의”, ””, 26}};

맨 끝 값들은 생략되고  이렇게 중간은 안됨

 

2)    구조체 배열 원소와 멤버 참조

u  구조체 배열명[첨자].멤버명

user[0].age=20; / user[99].age=25; / stud[53].score[3] = 4.5;

 

5.     구조체 포인터

n  구조체로 저장된 데이터를 가리키는 구조체 포인터!

n  연결리스트, 트리 같은 자료구조 구현하는데 사용됨

n  다른 포인터들과 같이 4byte!

 

1)    구조체 포인터 선언

(1)   구조체 포인터 선언하기

o  구조체 포인터가 가리키는 곳에 구조체가 있다면 구조체 태그명 명시!

o  struct 구조체 태그명 * 구조체 포인터명;

-      구조체 포인터가 가리키는 곳에 구조체 태그명의 구조체가 있음을 의미

-      struct person *ptr

person형 구조체가 저장된 곳의 시작주소가 ptr에 저장됨

(2)   포인터가 구조체를 가리키게 하기

o  구조체의 시작 주소를 구조체 포인터 변수에 대입

o  구조체 포인터 변수명 = &구조체 변수명;

-      포인터 변수에 구조체 변수의 시작주소를 대입

-      자료형이 일치해야 함! 같은 구조체 태그명!

-      ptr = $stud1;

 

2)    구조체 포인터를 사용한 간접 참조

(1)   *(간접참조연산자) .(멤버연산자) 이용

o  (*구조체 포인터 변수명).멤버명

구조체 포인터 변수가 가리키는 구조체의 멤버!

( )생략하면 오류 발생 -> 간접참조연산자 * 보다 멤버 연산자 . 이 우선순위가 높음

o  (*ptr).age=20;.

scanf(“%s”, (*ptr).name);          scanf(“%d”, &(*ptr).age);

scanf(“%s”, ptr à name);        scanf(“%d”, &ptr à age);

 

(2)   à이용한 포인터

o  구조체 포인터 변수명 à 멤버명

o  printf(“%d”, &ptr à age);

scanf(“%s”, ptr->name);

ptr à age = 30;

6.     함수 간의 구조체 전달

1)    값에 의한 호출

u  함수가 호출되면 매개변수는 구조체에 해당하는 기억 공간 할당 받음 -> 인수의 각 멤버 값이 매개변수 멤버 값으로 복사 됨

u  호출 : 함수명 (구조체 인수명)  à  정의 : 반환형 함수형 (struct 구조체 태그명 매개변수명) { }

 

2)    주소에 의한 호출

u  구조체의 시작 주소 전달! à 매개변수를 포인터로 선언! 매개변수로 구조체 주소번지를 받음

u  호출 : 함수명(&구조체 인수명) 

à  정의 : 반환형 함수명(struct 구조체 태그명 *매개변수명) {

매개변수명 à 멤버명 사용해서 멤버 참조  }

                      scanf(“%s”, ptr à name);             scanf(“%d”, &ptr à age);

 

3)    구조체 배열 전달

(1)   배열 선언 방식

o  함수를 정의할 때 매개변수를 배열로 선언 -> 배열명이 포인터 변수로 사용되는 것

o  호출 : 함수명(구조체 배열명)  à  정의 : 반환형 함수명(struct 구조체 태그명 배열명[]){ }

 

(2)   포인터 선언 방식

o  호출 : 함수명(구조체 배열명)

 à  정의 : 반환형 함수명(struct 구조체 태그명 *포인터 변수명){ }

 

2절  공용체와 열거형

1.     공용체

n  같은 메모리 영역을 여러 개의 변수들이 공유할 수 있게 하는 기능 -> 메모리 절약 위해

n  union 예약어에 공용체 태그 사용

n  멤버들이 같은 공간 공유 -> 동시에 멤버 변수들의 값을 저장할 수 없으면 어떤 순간에는 하나의 멤버만 존재할 수 있음!

n  가장 큰 멤버의 크기만큼 메모리 할당 받음

 

1)    공용체 선언

u  공용체 변수의 크기 = 크기가 가장 큰 멤버의 크기

u  한 공간을 두 개 이상의 변수가 공유하므로 예기치 않은 결과 나올 수 있음

덮어쓴다거나 하는 거지. 두 공간 공유 못하면 뒤에 들어온 애가 맨 앞 메모리 차지함..

u  union 공용체 태그명 { 자료형 멤버명 … } ; //정의

union 공용체 태그명 공용체 변수명; // 선언

 

2)    공용체 변수 초기화

u  공용체 변수 초기화 시 중괄호 사용해 첫 번째 멤버만 초기화

u  첫 번째 멤버 아닌 멤버 초기화 시 멤버연산자로 직접 지정해 초기화

u  union 공용체 태그명 공용체 변수명 = { 123 }; // 첫 번째 멤버 초기화

union 공용체 태그명 공용체 변수명 = {.멤버명 = 123 };

                      공용체 변수명.멤버명 = 123;

 

2.     열거형

n  변수가 가질 수 있는 값들을 나열한 자료형 -> 변수가 가질 수 있는 상수들의 모임

n  열거형으로 선언된 변수는 열거형에 정의된 상수만 값으로 가짐

-> 프로그램에서 가질 수 있는 값을 제한하는 것

 

1)    열거형의 정의와 선언

(1)   열거형의 정의

o  예약어 enum, 사용자가 새로운 자료형을 정의

o  enum 열거형 태그 { 열거형 변수에 저장 가능한 기호화된 정수 값들 };

o  enum days {SUN, MON, TUE, THU, FRI, SAT};

 

(2)   열거형의 선언

o  enum 열거형 태그 열거형 변수; // 선언

열거형 변수 = 기호상수 ; // 초기화

enum days today;

today = My_Day;  -- 오류 --> today = MON;

 

2)    기호상수들의 값

u  열거형 안에 들어 있는 상수들은 0에서 시작하여 1씩 증가하는 정수 값. -> 자동으로 설정됨

enum days {SUN, MON, TUE, THU, FRI, SAT};

SUN = 0, MON = 1, … 이런 식

u  값 배정은 변경 가능. 식별자 뒤에 시작하는 숫자를 넣어주면 됨

u  enum days {SUN=1, MON, TUE=5, THU, FRI, SAT=3};

SUN =1 이므로 MON =2로 자동 설정됨

TUE =5 이므로 THU =6, FRI = 7로 자동 설정됨

SAT = 3 이므로 SAT 3

 

3)    다른 방법과의 비교

u  열거형은 정수 형태의 기호 상수를 정의

특정 숫자 대신 기호를 사용함으로써 프로그램 이해도 향상

변수가 열거된 값 이외의 값을 취하는 것을 막아 오류 감소

 

3절  동적 기억장소 할당

1.     정적 할당과 동적 할당

n  정적 할당은 기억장소 낭비할 수 있음

 

2.     정적 할당

n  전역 변수, 정적 변수! 지역변수도 일종의 정적 할당

n  프로그램 컴파일 할 때 할당 받을 기억장소의 크기를 결정하고 프로그램 실행 시작 전에 이미 정적으로(statically), 고정된 크기로 프로그램 실행 끝까지 기억장소 할당 받음

n  프로그램 실행 끝나면 기억장소 해제됨

n  지역변수 ! 프로그램 실행 동안 함수 호출 되면 스택 영역에 기억장소 받지만 (동적인 것 같지만) 크기가 컴파일 시점에서 이미 결정되어있음! 고정된 크기로 할당 받는 것 -> 정적 할당에 해당

n  정적 할당의 문제점

u  할당된 공간 이상을 사용하는 것이 불가능함 (배열 크기 선언 시 변수가 안됨..)

u  공간을 매우 크게 할당 받으면 메모리 낭비가 심함

 

3.     동적 할당

n  프로그램 실행 동안 기억장소 필요 시점에서 필요한 만큼만 요청하여 할당 받음

n  힙 영역의 일부를 시스템에서 기억장소로 제공

n  주기억장치의 네 가지 영역

    코드 영역

cpu에게 내리는 명령어 코드

    데이터 영역

전역 변수와 정적 변수

    힙 영역

동적으로 할당할 기억 장소

    스택 영역

함수의 매개변수와 지역 변수

 

1)    동적 할당 함수 : malloc() 함수

u  동적으로 기억장소 할당 받아 사용하려면 포인터 변수와 malloc()함수 이용

u  포인터 변수 : 동적으로 할당 받은 기억장소의 시작주소 저장에 사용

u  포인터가 할당 받은 기억장소 가리키게 되면 그 다음부터 포인터 변수를 일반 배열명처럼 또는 실제 포인터 변수로서 활용하여 기억장소 참조!

u  자료형 * 포인터 변수명;

포인터 변수명 = (자료형 *) malloc (기억장소 크기 : byte단위)

o  malloc (기억장소 크기)

-      지정한 크기의  기억장소 할당 받아 시작 주소 반환

-      #include<stdlib.h> 추가

-      보통 malloc( sizeof (자료형)*필요 개수)식으로 자료형의 크기를 연산해서 씀

int a[20] 배열이면 sizeof(int)*20을 써주는 것!

이식성을 위해서걍 상수 20 이렇게 하면 시스템마다 크기가 다를 수 있음

-      힙 영역에 할당 가능한 기억장소 없으면 malloc()함수는 NULL매크로 상수 반환

-> 반드시 요청 후 할당 여부 확인! 권장

o  (자료형 *)

-      동적 할당 기억장소의 시작주소를 저장한 자료형의 포인터로 캐스팅함

-      malloc()함수가 할당 받은 기억장소 시작 주소를 void형 포인터로 반환하기에 캐스팅!

-      기억장솨를 용도에 맞게 저장할 자료형 공간으로 캐스팅해야 함

 

2)    동적 할당 기억장소 해제 함수 : free() 함수

u  지역변수는 함수 실행 끝나면 자동으로 기억장소가 해제됨 -> 자유상태

u  동적으로 할당 받은 기억 장소는 함수 실행 끝나도 자동으로 해제되지 않음

u  자유 상태 되도록 직접 해지!

u  free(포인터 변수명);

free(ptr); // ptr = (int*)malloc(sizeof(int));로 할당 받은 기억장소 해제

free(ch); // ptr = (int*)malloc(sizeof(chat)*10));로 할당 받은 기억장소 해제(char형 배열 10개짜리)

 

3)    동적 할당 관련 함수

 

 


1절 배열

l  프로그램의 효율성을 위해서는 처리할 자료에 따라 적합한 자료구조를 찾는 것이 중요.

l  자료구조 : 응용 프로그램에서 처리할 자료를 조직화하고 저장하는 방법

l  배열 : 자료형이 같은 여러 개의 연속된 기억공간에 같은 이름(배열명)으로 저장

                      자료형이 같은 것만 저장 가능

                      배열의 크기에 맞게 주기억장치의 연속된 기억장소에 저장됨

                      배열의 원소 / 첨자(인덱스)

 

1.     1차원 배열

n  일렬로 연속된 구조로 자료 저장

n  특정 원소 한개를 명시하기 위해 원소가 배열에 저장된 순서에 따라 1개씩 증가하는 첨자 1개 사용

1)    1차원 배열의 선언과 배열 원소

(1)   1차원 배열의 선언

o  자료형 배열명 [배열 원소의 수];

o  배열 원소 수와 상관 없이 배열에 저장되는 모든 값의 자료형이 같아야 함

o  배열 원소 수 = 배열의 크기 -> 정수형 상수만 가능

 

(2)   1차원 배열의 초기화

o  자료형 배열명[배열 원소 수] = {초깃값 목록};

o  Int b[5] = {1,2,3,4,5}; : 배열 원소에 {} 순서대로 저장됨

o  Int c[10] = {0}; : {}안에 초기값 개수가 배열원소 수보다 적으면 나머지 원소는 0으로 초기화 됨

o  Int d[ ]={1,2,3,4,5}; : 배열 원소 수 명시하지 않으면 {} 안 개수가 배열 원소 수로 결정 됨

o  초깃값 명시하지 않으면서 [ ]안 원소 수 생략하면 오류 발생

o  { }안 초기값 배열이 배열 원소 수보다 많으면 오류 발생

 

(3)   1차원 배열의 원소 참조

o  배열명[첨자]

-       첨자 : 0 ~ (배열의 원소 수 -1) 범위의 정수

-       배열에 저장된 첫 번째 원소 인덱스 : 0

-       마지막 원소 인덱스 : (배열 원소 수-1)

-       c[2]++ : 배열 c의 세 번째 원소에 저장된 값을 1 증가

 

2.     1차원 배열의 입출력

u  배열 원소 단위로 입출력하거나 저장

u  반복문 이용

u  Scanf( )를 사용해 입력값 저장할때 &배열명[첨자]로 하나씩 입력

 

1)    2차원 배열의 선언과 배열 원소

(1)   2차원 배열의 선언

o  자료형 배열명[행 개수][열 개수];

 

(2)   2차원 배열의 초기화

o  자료형 배열명[행수][열수] = {{1행 초기값 목록},{2행 초기값 목록}, … };

o  행의 개수는 생략할 수 있어도, 열의 개수는 생략할 수 없음

-       열의 개수로 행수를 간주함

 

(3)   2차원 배열 원소의 참조

o  행 첨자, 열 첨자 필요

o  배열명 [행 첨자][열 첨자]

 

2)    2차원 배열의 입출력

u  입출력과 대입문에서 배열 원소 단위로 처리

u  이중으로 중첩된 반복문으로 표현

 

3)    2차원 배열의 입력 : 행 단위 입력과 열 단위 입력

u  한 행씩 차례로 입력 or 한 열씩 차례로 입력

u  Scanf( )를 사용해 입력값 저장할때 &배열명[행첨자][열첨자]로 주소 명시

 

(1)   행 단위 입력

o  배열 원소 입력받을 때 행 첨자 같고 열 첨자만 변함

o  열 첨자 안쪽 for문 제어변수 , 행 첨자 바깥쪽 for문 제어변수

 

(2)   열 단위 입력

o  배열 원소 입력받을 때 열 첨자 같고 행 첨자만 변함

o  행 첨자 안쪽 for문 제어변수 , 열 첨자 바깥쪽 for문 제어변수

 

3.     Char형 배열을 이용한 문자열 처리

n  문자열 처리 방법 : (1) char형 배열 (2) char형 포인터. string 자료형을 지원하지 않음

 

1)    char형 배열을 이용한 문자열 처리

u  문자열 상수 : " "로 묶어 놓은 연속된 문자들

o  끝에 자동으로 null(\0)문자 포함됨

o  " " 안의 문자 수 + 1 BYTE

u  char형 배열로 배열 안에 한 글자씩 넣어야 함

 

(1)   문자열 저장할 때 배열 선언

o  문자열의 길이 : 널문자 이 전까지의 문자 개수

o  배열 크기 지정 : 배열 원소 개수 + 1 (널문자 포함)

 

(2)   scanf() / printf() 를 이용한 문자열의 입출력

o  char 1차원 배열에 저장된 문자열 출력하거나 배열로 문자열 입력 받을 때 배열명만 명시

o  배열명 자체가 배열의 시작 주소!

o  기억장소 구하기 위해 배열명 앞에 & 사용할 필요 없음

-       배열의 한 원소에 접근할 시 & 붙여야 함

-       Scanf(%s, array); O / printf(%s, array);

-       Scanf("%c, &array[2]);

 

(3)   문자열 전용 입력 함수 : gets()

o  공백을 포함하는 문자열 입력받음

o  문자열만 받으므로 변환명세(%s)필요 없음

o  gets(char 1차원 배열명);

 

(4)   문자열 전용 출력 함수 : puts()

o  문자열을 출력한 후 자동 개행

o  puts(char 1차원 배열명);

 

(5)   문자열에 포함된 문자의 처리

o  배열의 특정 원소의 값을 직접 입력받을 때 원소의 해당 주소를 구하기 위한 주소 연산자 사용

o  scanf(“%c, &array[2]);

o  printf(%c, array[3[);

 

(6)   문자열의 끝을 의미하는 널문자의 중요성

o  배열에 널문자 포함하지 않으면 문제는 발생하지 않지만 결과 예측 X

o  문자열 단위로 출력할 때 문자열이 저장되어 있는 첫 기억장소부터 차례대로 출력하고 널문자를 만날 때 까지 출력

o  문자열 처리 시 문자열 끝에 널문자 반드시 포함하도록 처리해야 함

 

2)    char 2차원 배열을 이용한 여러 개의 문자열 처리

u  배열명 뒤 행 첨자만 명시 : 해당 행에 저장된 문자열 의미 -> 해당 행의 시작 주소에 해당함

u  char 2차원 배열에 저장된 문자열의 입출력

o  scanf(“%s”, 배열명[행 첨자]); : (행 첨자 + 1)째 행의 문자열 입력

o  printf(“%s”, 배열명[행 첨자]); : (행 첨자 + 1)째 행의 문자열 출력

o  gets(배열명[행 첨자]); : 엔터키 이 전까지의 문자열을 (행 첨자 + 1) 째 행에 입력

o  puts(배열명[행 첨자]); : (행 첨자 + 1) 째 행의 문자열 출력 후 개행

u  char 1차원 배열명 : 문자열의 시작 주소

u  char 2차원 배열명 : 전체 배열의 시작 주소

u  2차원 배열명[행 첨자] : (행 첨자 + 1)째 행의 시작 주소. 열에 대한 첨자 생략으로 같은 행 문자열을 의미

u  배열 원소를 입력 받을 때 scanf(%c, &array[2][4]); 처럼 & 붙여야 됨

 

4.     3차원 배열

n  배열 선언 : , , 열 개수

 

5.     배열 원소를 함수로 전달하기

n  배열 원소 함수로 전달 시 값에 의한 호출 / 주소에 의한 호출 둘 다 사용 가능

n  배열 전체를 함수로 전달 시 주소에 의한 호출만 사용 가능

n  함수 호출 : 함수명 (배열명[첨자])

n  함수 정의 : 반환자료형 함수명 (자료형) { }

 

2절 포인터

l  포인터 변수 : 데이터가 저장된 주기억장치의 주소만 저장

 

1.     포인터

1)    주기억장치의 주소

u  주기억장치 : CPU가 실행할 명령어 코드와 처리할 데이터를 저장하기 위한 기억장치

u  프로그램의 코드와 데이터가 주기억장치에 저장된 후 CPU가 프로그램의 코드를 실행하여 데이터 처리

u  메모리 : 바이트 단위로 나뉨. 각 바이트에는 주소 지정됨

o  주소 : 변수가 위치하는 곳

o  & : 변수의 주소를 가져오는 연산자

u  %p : 주소값 나타낼 때 사용하는 변환명세. 16진수로 표현

u  변수의 메모리 할당 : 임의의 위치에 자료형만큼의 byte가 부여됨

u  배열의 메모리 할당 : 임의의 위치에 연속해서 자료형만큼 byte가 부여됨

o  배열 이름 : 전체 배열의 주소(배열이름 자체가 배열의 주소를 나타냄) & 배열의 첫 번째 주소

o  &a[0] = a (&a X)

 

2)    포인터의 개념과 필요성

(1)   참조 불가능한 변수 간접적으로 참조 가능

o  호출된 함수에서는 자신을 호출한 함수의 지역 변수를 직접 참조할 수 없음

o  포인터로 간접적으로 참조함

(2)   프로그램의 성능 개선, 기억공간 효율적으로 사용

o  크기가 큰 배열이나 구조체를 함수에 인수로 전달할 때 값 복사를 하게 되면 메모리 낭비가 큼

o  배열이나 구조체의 시작 주소만 인수로 전달하고 함수에서는 포인터를 이용해 배열과 구조체를 참조하면 메모리 절약 가능

o  동적 할당과 포인터는 트리나 연결리스트 같은 자료구조 구현에 유용

-       동적 할당 : 프로그램 실행하면서 필요한 만큼의 기억 공간을 할당 받아 사용하고 나중에 필요 없어진 것 해제하는 것

 

3)    포인터를 사용하기 위한 세 가지 과정

(1)   포인터 변수도 일반 변수처럼 선언해야 사용 가능

(2)   포인터 변수에는 가리키고 싶은 기억장소의 주소를 대입

(3)   * 연산자 : 포인터 변수에 저장된 주소를 이용해 다른 기억장소를 참조할 때 사용(*p : 포인터 변수 p가 가리키는 곳에 있는 것)

 

2.     포인터의 사용

n  사용하기 전에 선언하고, 선언 후 변수에 가리킬 곳 주소 대입, 간접 연산자 이용해 참조

1)    포인터 변수 선언

u  자료형 *포인터 변수명; / 자료형 *포인터 변수명, *포인터 변수명 ;

u  * : 간접 참조 연산자 / 선언 할 때는 단순히 포인터 변수임을 표시

u  자료형 : 포인터 변수가 가리키는 기억장소에 저장될 자료의 형

o  포인터 변수가 차지하는 기억장소 크기 : 일반적으로 4BYTE (32Bit)

o  포인터 변수 크기는 컴파일러에 따라 다름

char *p;

-       char형 포인터 변수 p 선언

-       p가 가리키는 곳에 저장될 값의 자료형이 char

 

 

2)    주소 연산자 &와 주소 대입

u  포인터 변수에는 가리킬 변수가 위치한 기억장소의 주소를 저장 -> 변수의 주소값(번지)을 저장

u  &변수명 : &로 변수의 실제 주기억장치 번지를 구함

u  포인터 변수명 = &변수명; 포인터 변수에 변수의 주소값(번지)을 대입

u  주소 연산자 &

o  주소 구하는 연산자. 주기억장치에서의 번지수를 구함

o  일반 변수 , 포인터 변수 등에 사용 가능

o  상수에는 사용할 수 없음

 

3)    간접 연산자 *

u  * : 간접 참조 연산자 / 역참조 연산자

o  피연산자인 주소 값을 이용해 주소로 찾아가 참조

 

(1)   일반 변수의 직접 참조

o  변수명을 사용하여 변수를 직접 참조

o  var = 100;

printf(%d, var);

 

(2)   포인터 변수의 직접 참조

o  포인터 변수에 저장된 주소를 읽어오거나 포인터 변수에 새로운 주소를 저장할 수 있음

o  포인터가 가리키는 곳의 내용을 참조할 수 없음

o  int var = 100;

int *ptr = &var; // ptr var의 주소를 대입함. ptr에는 var의 주소 번지가 저장됨

printf(%d, ptr); // ptr에 들어있는 var의 주소값을 출력함. ptr을 직접 참조한 것

 

(3)   포인터 변수의 간접 참조

o  *를 사용 (~가 가리키는 곳!)

o  포인트 변수에 저장된 주소에 해당하는 기억장소를 참조

 

4)    포인터 변수와 일반 변수 비교

(1)   변수의 두 가지 의미 : 저장된 값 / 기억장소

 

(2)   포인터 변수와 일반 변수의 차이 요약

double grade = 4.0;

è double형 변수 선언

double *ptr = &grade;

è double형 변수를 가리킬 포인터 변수 선언

&grade=100이라고 가정.

 

printf(%lf, grade);

è 4.000000 출력

printf(%lf, *ptr);

è 4.000000 출력. ptr이 가리키는 곳의 값을 가져옴

 

 

printf(%lf, grade +1 );

è 5.000000 출력. 변수에 저장된 값과 1을 더함

printf(%u, ptr+1 );

è 108 출력. double형 포인터 다음 번지를 출력한 것.

ptr(100) + 8(double형 크기)

 

 

*ptr += 1;

è ptr이 가리키는 곳의 값을 1 증가시킴

printf(%lf, *ptr)

è 5.000000 출력

 

o  포인터 변수 p가 있을 때

p – 1 : p 기준 하나 앞 메모리 주소 / p + 1 : p기준 하나 뒤 메모리 주소

하나 앞 뒤의 기준은 p가 가리키는 변수의 자료형에 따라 달라짐

 

5)    간접 연산자, 가감 연산자, 증감 연산자의 우선 순위

u  ++, -- > 간접 연산자(*) > +, -

(1)   *p + 1 : *p 1을 더함.  à p가 가리키는 곳의 값과 숫자 1을 더함

(2)   *(p + 1) : (p + 1)을 먼저 수행한 후 * 적용 à p가 가리키는 곳 하나 뒤의 장소를 간접 참조

(3)   *p1++ : p++ 수행 후 * 적용 à *(p + 1) 과 같이 p 다음 장소 참조

(4)   (*p)-- : *를 먼저 적용하여 p가 가리키는 곳의 값이 1 감소

 

3.     포인터와 배열

n  포인터에 대한 가감 연산 à 배열 참조할 때 사용

n  배열명 : 배열의 시작 주소 ! a = &a[0]

n  배열의 원소를 참조하는 방법

-> 배열명(배열의 시작 주소)에 대한 덧셈 연산 : 배열명과 첨자 사용

-> 간접 연산자 이용 : *(array + 1)

1)    배열명은 배열의 시작 주소

u  배열명 : 주기억장치 주소인 상수 값. 배열 시작위치 알리는 포인터 상수

u  배열명 array = 배열 시작 주소 = 첫 원소의 시작 주소 (&array[0])

주소 값 그대로 라는 것!

*array는 주소값 100이 가리키는 곳에 있는 내용물 이란 거겠지

u  배열명은 포인터 상수이기에 포인터에 대한 가감 연산 가능

*(array + i) : *(array는 포인터 상수 + 자료형의 크기 * i) == array[i]

array[0] == *(array +0) array는 주소값. 주소값 + 0 이므로 변화한 거 없음

array[1] == *(array +1)   array[2] == *(array +2)

 

2)    포인터 변수를 이용한 배열 원소 참조

u  포인터 변수를 마치 배열명처럼 사용할 수 있음

o  배열명[첨자]’가 내부적으로는 ‘*(배열명+첨자)’로 처리 됨

배열명이 배열의 시작 위치인 포인터 상수이므로! *(array + 1)!!

o  반대로! 특정 포인터 변수가 배열 시작 위치를 가리키는 상태라면 포인터 변수명[첨자]’도 가능

o  포인터 변수명[첨자]’는 내부적으로 ‘*(포인터 변수명+첨자)’로 처리될 것

포인터 변수명 = 배열명;           

è ptr = array;

배열명[첨자] = *(배열명 + 첨자)

è array[1] = *(array + 1)

포인터 변수명[첨자] = *(포인터 변수명 + 첨자)

è ptr[2] = *(ptr + 2)

 

array[0] = *(array + 0) = *(ptr + 0) = ptr[0]

array[i] = *(array + i) = *(ptr + i) = ptr[i]

 

4.     포인터와 함수

n  포인터를 사용하지 않는 코드보다 가독성 떨어지고 처리과정도 복잡하고 실행 시간 오류도 많이 발생할 수 있음. 그래도 장점이 있다!

 

1)    포인터를 이용한 주소에 의한 호출

u  주소에 의한 호출 방식

o  함수 호출 시 인수의 주소를 전달하고 호출된 함수는 전달 된 주소를 포인터 매개변수에 저장

o  포인터 매개변수가 인수를 가리키게 되어 호출된 함수에서는 포인터 매개변수의 간접참조 이용해 인수 참조

u  호출 : 함수명(&인수명); 정의 : 반환형 함수명(자료형 * 포인터 변수명)

포인터 변수가 인수를 가리키게 되고, 포인터 변수명의 자료형은 전달받는 인수 자료형과 동일

u  값에 의한 호출: 인수와 매개변수가 서로 다른 기억장소 차지 -> 이름이 같아도 서로 다른 변수

u  주소에 의한 호출: 매개변수가 인수를 가리키는 포인터 변수

-> 간접 참조로 인수 기억장소 참조 가능

-> 다른 장소에 선언 된 변수를 다른 블록 안에서 참조해 변경 가능하다는 것!

 

2)    배열을 함수의 매개변수로 사용하는 경우

u  함수를 호출하면서 배열을 통째로 전달하는 것은 불가능

u  포인터를 이용해 함수 간에 배열을 전달하는 방식으로 전달

정의된 함수 내에서 포인터 변수[i]’ 또는 *(포인터 변수명 + i)로 원소 참조

u  int ages[50];

convert(ages);

void convert(int *years){ *years , *(years + 1) 등으로 배열 ages 참조 가능}

 

5.     포인터와 문자열

n  문자열 처리 방법! char형 배열 / char형 포인터

1)    char형 배열과 char형 포인터를 이용한 문자열 저장

u  C언어에서는 문자열형 포인터 사용 불가능!(문자열형 자료형이 없지..일단)

à char형 포인터로 선언

u  char str1[10] = “language”;

                      

배열의 크기에 해당하는 기억장소에 초기값으로 지정한 문자열 상수가 저장되고 바로 뒤에 문자열 끝을 나타내는 널문자가 저장됨

 

u  char *str2=“language”;

(초기값인 문자열 상수의 길이 + 1)개의 문자를 저장할 수 있는 공간에 문자열과 문자열 끝을 나타내는 널문자가 저장되며 이 문자열이 저장된 기억장소의 시작 주소가 str2에 저장됨

 

 

(1)   char형 배열을 이용한 문자열 처리

o  char형 배열은 문자열 끝을 의미하는 널문자가 포함되도록 배열 원소 수를 저장할 최대 문자 수 보다 1 많게 선언해야 함

o  str1은 배열의 시작 주소인 포인터 상수

-> str1 =” aaa”;처럼 대입문을 이용해 내용 수정 불가능

o  문자열 내용을 새로운 문자열로 변경하고 싶다면 #include <string.h> 하고 strcpy() 함수 사용. strcpy(str1, “aaa”);

 

(2)   char형 포인터를 이용한 문자열 처리

o  char형 포인터는 문자열 복사, 수정 등을 처리할 때 문자열의 끝에 언제나 널문자 포함되게 해야 함

o  선언하면서 초기화 한다면 언제나 문자열 끝에 자동으로 널문자 포함됨 -> 배열처럼 원소 수에 신경 쓸 필요 없음

o  문자열 입력, 둘째 문자 입력, 문자열 복사 처리할 때 str2에 동적으로 할당된 기억장소가 있을 때만 가능

o  str2는 포인터 변수이므로 str2=”aaa”;처럼 대입문으로 내용 수정 가능

 

2)    문자열과 관련된 대표적인 함수의 사용

) char s1[10] = “start”; char s2[10] = “end”;

 


1절  함수의 개념

1.     함수란?

n  함수(function) : 특정 작업을 수행하는 명령어들의 모음에 이름을 붙인 것

n  함수를 호출해서 작업 시킬 수 있음

n  함수는 작업에 필요한 데이터를 전달받을 수 있으며, 작업이 완료된 후에는 작업의 결과를 호출자에게 반환

n  특정한 일을 수행하는 코드 블록

n  함수들의 집합 중 main( )함수는 꼭 있어야 함

 

1)    함수의 필요성

u  함수를 이용하면 여러 번 반복 처리되는 단계를 하나로 모아서 필요할 떄 언제든지 호출하여 사용 가능

u  함수는 특정 작업 수행하기 위한 명령어들의 모임!

u  함수 호출 시 컴퓨터는 호출된 함수 안의 명령어들 수행하고 결과 반환

(1)   함수는 서로 구별되는 이름 가짐

(2)   함수는 특정한 작업을 수행

(3)   함수는 입력을 받을 수 있고, 결과를 반환할 수 있음

 

2)    함수의 중요성

u  프로그램을 구성하는 기본적인 구성요소

u  한 번 만들어지면 다른 프로그램에서도 재사용 가능

u  함수를 적절히 사용하면 가독성과 유지관리가 좋아짐

 

3)    함수를 사용하는 이유

(1)   코드의 중복을 막을 수 있음

o  여러 번 호출하여 사용할 수 있기 때문에 소스 코드 중복시킬 필요 없음

o  소스 코드의 양을 줄일 수 있음

 

(2)   한 번 제작된 함수는 다른 프로그램을 제작할 때도 사용 가능

o  소스 코드를 그대로 옮기기만 하면 재사용 가능

 

(3)   복잡한 문제를 단순한 부분으로 분해할 수 있음

o  개발 과정이 쉬워지고, 보다 체계적이고 유지보수 쉬워짐

o  모듈!

 

2.     함수의 종류

1)    라이브러리 함수

u  컴파일러에서 지원하는 함수들

2)    사용자 정의 함수

 

2절  라이브러리 함수

l  라이브러리 함수를 사용하려면 해당 함수의 원형을 포함하고 있는 헤더파일을 프로그램에 포함하도록 #include 지시자를 명시

1.     라이브러리 함수의 호출

n  함수명 정확히 명시

n  함수 실행될 때 필요한 정보인 인수를 개수와 자료형에 맞춰 순서대로 정확히 기술

 

2.     라이브러리 함수의 종류

1)    수학과 관련된 함수 : #include<math.h>가 필요

u  라디안! 180° = π -> 각도 라디안 변환 -> (π * 각도)/180

 

2)    문자와 관련된 함수 : #include<ctype.h>가 필요

 

3)    문자열과 관련된 함수 : #include<string.h>가 필요


 

4)    그 외 범용 함수 : #include<stdlib.h>가 필요

 

3절  사용자 정의 함수

1.     사용자 정의 함수의 호출과 정의

n  사용자 정의 함수 정의

반환형 함수명 (매개변수 선언 목록) {

      함수에서 사용할 변수의 선언부

      함수에서 처리할 명령의 선언부

      return 반환 값;

}

n  매개변수는 일반변수와 다르게 각각 선언

n  매개변수 = 인수와 같은 대입문 효과

n  함수 호출문 = 반환값과 같은 대입문 효과

 

2.     인수와 매개변수에 대한 이해

n  함수는 서로 독립적인 개체로 특정 함수에서 선언한 변수(지역 변수)를 다른 함수에서 마음대로 참조, 출력, 변경할 수 없음

n  호출할 함수에 꼭 지정하고 싶은 값은 그 함수를 호출할 때 인수로 제공

 

3.     함수 원형 선언

1)    함수 호출과 함수 정의의 위치

u  함수는 서로 독립된 개체. 함수 안에 다른 함수 정의할 수 없음

u  함수의 정의가 끝난 후 다른 함수를 정의해야 함

u  함수의 정의는 함수 호출 전에 위치해야 컴파일 오류 안남

u  가독성을 위해 main함수를 맨 앞에 정의하므로, 그 앞에 함수의 원형 선언을 함

 

2)    함수 원형 선언

u  사용자 정의 함수를 함수 호출문 뒤에 정의하려면 원형 선언이 필요

u  프로그램 상단의 main() 함수를 정의하기 전에 둠

u  매개변수 자료형 목록은 언문 형태 or 자료형만 명시하는 형태 둘 다 가능

    (자료형1 매개변수1, 자료형2 매개변수2, … ,자료형n 매개변수n)

int func_large(int x, int y);

-      함수 원형 선언문은 문장의 끝에 반드시 ; 붙여야 함

-      함수의 최초 호출문보다 앞에 선언

 

    (자료형1, 자료형2, … , 자료형n)

int func_large(int, int);

-      매개변수 이름은 생략할 수 있으나 매개변수의 자료형은 반드시 명시

-      자료형은 함수의 정의에 나타나는 자료형과 같아야 함

 

4.     함수의 인수 전달 : 값에 의한 호출

1)    값에 의한 호출과 인수 전달 과정

u  호출할 때 명시한 인수의 값이 전달됨 -> 호출된 함수의 매개변수에 저장됨

u  call of value

u  인수 : 값을 전달하므로 상수, 변수, 수식 가능

u  매개변수 : 값을 저장해야 하므로 변수만 가능

 

2)    값에 의한 호출과 함수 간의 독립성

u  함수 간의 독립성을 보장함

u  함수 실행이 끝나면 함수의 변수에 할당된 기억장소는 모두 해제됨

 

5.     여러 가지 함수의 유형


 

1)    매개변수가 없는 함수

u  매개변수 자리에 void 넣어 매개변수가 없음을 표기

u  괄호만 사용하는 것도 가능, void를 넣어 매개변수가 없음을 명시적으로 표시하자!

 

2)    반환 값이 없는 함수

u  선언과 정의의 반환형에 void 표기

u  return문 생략 가능, return문이 없어도 함수의 코드를 모두 수행하면 호출된 곳으로 자동으로 돌아감

 

3)    반환 값과 매개변수가 모두 없는 함수

u  함수의 매개변수와 반환형에 모두 void 표기

 

4절  기억 클래스

1.     참조영역에 따른 구분

n  변수 참조는 변수의 참조영역 안에서만 가능

n  참조영역 : 프로그램에서 변수를 참조할 수 있는 영역, 변수의 참조가 유효한 영역

n  지역 변수는 함수 외부에서는 참조할 수 없고, 전역 변수는 모든 함수에서 참조할 수 있음

 

1)    지역 변수

u  함수(블록) 안에서 선언된 변수

u  변수가 선언된 함수(블록) 안에서만 참조할 수 있음

u  지역 변수의 참조영역은 그 변수가 선언된 함수(블록) -> 함수를 벗어난 곳에서는 참조 불가

 

(1)   지역 변수의 선언 위치

o  블록의 어디서든지 변수 선언할 수 있음

o  { }이기만하면 됨. for, while문 등!

 

(2)   이름이 같은 지역 변수

o  다른 지역 안에 동일한 이름이 있어도 컴파일 오류 발생하지 않음

 

(3)   지역 변수의 생존 기간

o  변수가 선언된 블록이 시작할 때 시스템 스택이라 불리는 메모리 공간에 만들어지며 동시에 초기화됨

o  지역 변수에 할당된 메모리 공간은 블록 끝에서 반환됨

o  전역 변수는 프로그램이 시작되기 전에 만들어지고 프로그램 끝날 때 까지 계속 존재함

 

(4)   지역 변수의 초기값

o  지역 변수의 초기값을 정해주지 않았다면 아무런 의미 없는 값이 들어있음-> 쓰레기값

 

(5)   함수의 매개 변수

o  함수의 헤더 부분에 정의되어 있는 매개변수도 일종의 지역 변수임

o  호출 시의 인수 값으로 초기화되어 있음(지역 변수와 다른 점)

o  함수 내부에서는 지역 변수처럼 사용할 수 있음

 

2)    전역 변수

u  함수 외부에서 선언되는 변수

u  참조 영역 : 소스 파일 전체

u  모든 함수에서 접근가능하고 사용이 가능한 변수

 

(1)   전역 변수의 초기값과 생존기간

o  프로그래머가 전역 변수를 초기화하지 않으면 컴파일러에 의해 0으로 초기화됨

o  프로그램 시작과 동시에 생성되어 프로그램이 종료되기 전까지 메모리에 존재

 

(2)   전역 변수의 사용

o  어디서나 접근이 가능하다는 장점 / 단점

o  전역 변수로 데이터 교환을 하는 것보다는 알맞게 잘 정의된 인터페이스를 통해 데이터 교환을 하는 편이 더 수월

o  전역 변수들로 인해 코드가 꼬이는 현상 -> 스파게티 코드

o  프로그램을 작성할 때 모듈화 프로그래밍을 해야 하는데, 전역 변수는 사용하지 않는 편이 좋음

o  함수간의 독립성을 보장하기 위해

-> 거의 모든 함수에서 공통적인 데이터는 전역 변수

-> 일부의 함수들만 사용하는 데이터는 지역 변수

 

(3)   같은 이름의 전역 변수와 지역 변수

o  전역 변수와 이름이 같은 지역 변수를 선언하면 지역 변수가 전역 변수보다 우선시 됨

o  지역 변수가 전역 변수를 가린다.”

 

2.     지속기간에 따른 구분

n  변수의 기억장소는 변수 선언 방법에 따라 존재기간이 달라짐

n  지속기간, 수명 : 변수에 할당된 기억장소가 존재하는 기간

n  변수의 수명이 끝났다 = 변수의 기억장소가 존재하지 않는다 = 해당 변수를 사용할 수 없다

 

1)    자동 변수

u  변수의 지속기간이 함수의 실행 시작부터 끝까지로 한정됨

u  반환형 함수명 (매개변수 선언 목록) {

auto 자료형 자동변수명;

}

(1)   자동 변수의 선언과 지속기간

o  함수가 호출되면 변수에 기억장소가 할당 -> 실행 끝나면 변수 기억장소 해제

o  기억 장소의 동적 할당!

o  auto 생략 가능. 지역 변수는 모두 자동 변수에 해당

o  반환형 함수 (매개변수 선언 목록){

auto 자료형 자동변수명;

…}

 

(2)   변수의 기억장소 할당과 자동 초기화

o  컴파일 하면

o  전역 변수는 프로그램이 실행될 때부터 기억장소를 할당 받고 자동으로 0으로 초기화됨

o  자동(지역) 변수는 기억장소 할당 받아도 자동으로 초기화 되지 않음 -> 쓰레기값

 

2)    정적 변수

u  동적 : 무언가 실제로 필요할 때마다 처리되는 것

u  정적 : 필요한 것을 미리 처리해두고 처음부터 끝까지 고정적으로 유지하는 것

u  정적 변수는 정적 할당과 관련됨

u  함수 안에서 정적 변수로 선언한 변수는 함수 실행과 상관없이 프로그램 실행 시작부터 끝까지 기억장소 차지 -> 마지막 함수 호출에서 저장된 값을 유지 가능

u  정적 변수 : 프로그램이 실행될 때부터 기억장소를 정적으로 할당받아 실행이 끝날 때 까지 유지되는 변수 (정적 전역 변수 / 정적 지역 변수)

u  static 자료형 정적 변수명; (초기화 가능)

 

(1)   정적 지역 변수

o  ‘static’을 변수 앞에 붙여 함수 안에서 선언한 변수

o  초기값을 주지 않아도 자동으로 0으로 초기화 됨

o  함수 안에서만 참조할 수 있지만 프로그램의 실행 시작부터 끝까지 기억 장소를 차지 -> 이전 함수 실행에서 저장된 값이 사라지지 않음

o  값 보존하고 싶은 경우 사용

 

(2)   정적 전역 변수

o  함수 외부에서 선언한 정적 변수

o  선언한 이후로 프로그램 어디서나 참조할 수 있음

o  초기값 주지 않으면 자동으로 0으로 초기화됨

o  변수를 선언한 소스 파일에서만 전역으로 참조할 수 있고, 다른 소스 파일에서는 참조할 수 없음

그냥 전역 변수! 는 다른 소스 파일에서도 동일한 전역 변수로 참조 가능 -> 사용하고 싶은 전역 변수를 외부 변수로 지정해야 함

 

3)    레지스터 변수

u  일반 변수는 주기억장치의 일부분을 할당 받으나 레지스터를 할당 받는 변수가 레지스터 변수

u  레지스터 변수는 지역변수만 가능

u  레지스터 변수는 CPU 자원을 잠깐 빌리는 것 -> 프로그램 실행하는 동안 계속 저장 공간을 확보해야 하는 전역변수는 레지스터에 할당할 수 없음

u  저장 공간이 메모리에 있는 것이 아니므로 주소 연산자를 써서 포인터를 구할 수 없음

u  레지스터 변수의 선언이 레지스터의 사용을 보장하는 것은 아님

u  register 자료형 레지스터 변수명;

 

4)    외부 변수

u  프로젝트 하나를 여러 파일로 나누어 개발하는 경우 모든 파일에 공통으로 동일하게 사용하고 싶은 전역 변수가 있다면 main()함수 이전에 전역 변수 선언하고 다른 프로그램 파일에서는 이 변수를 외부 변수로 선언

u  main()함수 있는 파일에 있는 전역 변수를 다른 파일에서 extern 으로 선언하여 사용

u  전역 변수를 사용하는 소스파일을 #include로 포함시켜야 됨

u  다른 파일에서 정의한 함수의 원형 선언도 명시해야함

 

 


+ Recent posts