Ch2. C++
Ch2. C++ 언어의 언어의 기초 기초 ( ( 배열 배열 , , 구조체 구조체 , , 포인터 포인터 ) )
Korea Polytechnic University 최성진
choisj@kpu.ac.kr
http://mobile.skku.ac.kr/~sjchoi/OOP.html
HP: 011-9091-6671
배열 배열 (array) (array)
배열(array)
데이터 형이 같은 여러 개의 값을 연속적으로 저장할 수 있는 데이터 구조
예) 5년 동안의 월별 게임 판매량: 60개의 int형 값을 하나의 배열에 저 장, 1년 동안의 하루하루 식비: 365개의 float형 값 등
배열 선언 명령문
일반적인 형식
typeName arrayName[arraySize];
typeName: 각 원소에 저장될 값의 데이터 형
arrayName: 배열의 이름
arraySize: 배열 원소의 개수
9 값 또는 const 기호 상수와 같은 보통의 상수, 또는 컴파일 할 때 값이 결정되 는 8*sizeof(int)와 같은 상수 수식
예) short months[12]; //12개의 short형 값을 넣을 수 있는 배열을 생성
배열 배열 (array) (array)
배열 원소
원소에 개별적으로 접근 할 수 있고, 하나의 선언으로 많은 변수들을 생성할 수 있도록 해준다.
개별적인 접근을 위해 첨자(subscript) 또는 색인(index)을 사용하여 배 열 원소에 차례로 번호가 매겨진다.
C++의 배열 첨자는 항상 0부터 시작한다.(절대적)
예) month[0] 은 month 배열의 첫 번째 원소, month[11]은 month 배열의 마지막 원소를 나타낸다.
배열의 마지막 원소를 나타내는 첨자는 배열의 크기보다 항상 1만큼
작다.
배열 배열 (array) (array)
#include <iostream>
using namespace std;
int main() {
int yams[3];
yams[0]=7;
yams[1]=8;
yams[2]=6;
int yamcosts[3]={200, 300, 50}; //배열 초기화 cout<<"고구마는 총 ";
cout<<yams[0]+yams[1]+yams[2]<<" 개입니다.\n";
cout<<yams[1]<<" 개가 들어있는 포장은";
cout<<"개당 "<<yamcosts[1]<<"원씩입니다.\n";
int total=yams[0]*yamcosts[0]+yams[1]*yamcosts[1]+yams[2]*yamcosts[2];
cout<<"세 포장의 총 가격은 "<<total<<"원입니다.\n";
cout<<"\nyams 배열의 크기는 "<<sizeof(yams)<<"바이트입니다.\n";
cout<<"원소 하나의 크기는 "<<sizeof(yams[0])<<"바이트입니다.\n";
배열 배열 (array) (array)
배열 초기화 규칙
int cards[4]={3, 6, 8, 10}; // 맞다
int hand[4]; // 맞다
hand[4]={5, 6, 7, 9}; // 틀리다
hand=cards; // 틀리다
첨자를 사용하여 배열 원소에 개별적으로 값을 대입하는 것은 언제든 지 가능
float hotelTips[5]={5.0, 2.5};
배열을 부분적으로 초기화하면, 컴파일러가 나머지 원소들을 모두 0으로 설정한다.
long totals[500]={0};//첫 번째 원소만 0으로 명확히 초기화
short things[]={1, 5, 3, 8};
배열을 초기화 할 때 대괄호 속을 비워두면, 컴파일러가 초기화 값의 개수를 헤아려 배열 원소의 개수를 결정한다.
문자열 문자열 (String) (String)
문자열 (string)
메모리에 바이트 단위로 연속적으로 저장되는 문자들을 말한다.
C++의 문자열 처리 방법
string 클래스 라이브러리에 기반을 두는 처리
C 로부터 유래한 C 스타일 문자열 처리
문자들이 메모리에 바이트 단위로 연속적으로 저장되기 때문에, 문자열 을 char형의 배열에 저장할 수 있다.
문자열을 구성하는 각 문자들은 배열의 원소에 하나씩 저장
모든 문자열의 마지막 문자가 반드시 널 문자(null character)여야 한다. 널 문자는 \0로 쓰며, ASCII 코드가 0인 문자이다.
9 char dog[5]={‘b’, ‘e’, ‘a’, ‘u’, ‘x’}; //문자열이 아니다
9 char cat[5]={‘f’, ‘a’, ‘t’, ‘s’, ‘\0’}; //문자열이다
char 형의 배열을 문자열로 초기화
9 char bird[10]=“Mr. Cheeps”; // \0을 저장한다
배열에 배열에 문자열 문자열 사용 사용
배열에 문자열을 넣는 방법
배열을 문자열 상수로 초기화하는 방법
키보드 입력이나 파일 입력을 배열에 저장하는 방법
#include <iostream>
#include <cstring>
using namespace std;
int main() {
const int Size=15;
char name1[Size];
char name2[Size]="C++owboy"; //문자열 상수로 초기화 cout<<"안녕하세요! 저는 "<<name2;
cout<<"입니다! 실례지만 성함이? \n";
cin>>name1;
cout<<"아, "<<name1<<" 씨! 당신의 이름은 ";
cout<<strlen(name1)<<" 자입니다만 \n";
cout<<sizeof name1<<"바이트 크기의 배열에 저장되었습니다.\n";
cout<<"이름이 "<<name1[0]<<"자로 시작하는군요.\n";
name2[3]='\0';
cout<<"제이름의 처음 세 문자는 ";
cout<<name2<<"입니다.\n";
문자열 문자열 입력 입력
사용자의 이름과 좋아하는 디저트를 키보드로 입력 받아 그 정보를 화면에 다시 출력하는 예제
#include <iostream>
using namespace std;
int main() {
const int ArSize=20;
char name[ArSize];
char dessert[ArSize];
cout<<"이름을 입력하세요:\n";
cin>>name;
cout<<"좋아하는 디저트를 입력하시오:\n";
cin>>dessert;
cout<<"맛있는 "<<dessert;
cout<<" 디저트를 준비하겠습니다. "<<name<<" 님!\n";
문자열 문자열 입력 입력
cin이 문자열의 끝을 인식하는 방법
cin은 빈칸, 탭, 캐리지 리턴과 같은 여백이 있으면 그 위치에서 문자열 이 끝난 것으로 간주
키보드로는 끝내기 널 문자를 입력할 수 없기 때문에, 다른 수단이 필 요하다.
행 단위의 입력: getline() 과 get()
단어 단위의 입력이 아닌 행 단위의 입력
getline()
Enter 키에 의해 전달되는 개행 문자를 입력의 끝으로 간주하여 한 행 전 체를 읽는다.
사용방법: cin.getline()
두 개의 전달 인자를 사용. 첫 번째 전달인자는 입력한 행을 저장할 배열 의 이름. 두 번째 전달 인자는 입력 받을 문자들의 한계.
예) cin.getline(name, 20)
문자열 문자열 입력 입력
cin.getline() 함수를 사용하여 수정
#include <iostream>
using namespace std;
int main() {
const int ArSize=20;
char name[ArSize];
char dessert[ArSize];
cout<<"이름을 입력하세요:\n";
cin.getline(name, ArSize);
cout<<"좋아하는 디저트를 입력하시오:\n";
cin.getline(dessert, ArSize);
cout<<"맛있는 "<<dessert;
cout<<" 디저트를 준비하겠습니다. "<<name<<" 님!\n";
return 0;
문자열 문자열 입력 입력
get()
getline() 함수처럼 동작
그러나 이 함수는 개행 문자를 읽어서 버리지 않고 입력 큐에 그대로 남겨 둔다. 따라서 get()을 연달아 두 번 호출하면 문제가 발생.
9 cin.get(name, ArSize);
9 cin.get(desesert, ArSize); //문제 발생
첫 번째 호출이 입력 큐에 개행 문자를 그대로 남겨 두기 때문에, 두 번째 호출은 그 개행 문자를 첫 문자로 만나게 된다. 따라서, get()은 읽을 것도 없이 곧 바로 행의 끝에 도달했다고 결론을 내린다.
9 cin.get(name, ArSize); //첫 번째 행을 읽는다
9 cin.get(); // 개행 문자를 읽는다
9 cin.get(desesert, ArSize); //두 번째 행을 읽는다
멤머 함수를 결합하여 사용
9 cin.get(name, ArSize).get();
9 cin.getline(name1, ArSize).getline(name2, ArSize); // 두 행의 입력을 연속해서 읽어 name1과 name2 배열에 각각 저장. 이것은 cin.getline()을 두 번 호출하는 것과 같다.
문자열 문자열 입력 입력
멤버 함수의 결합을 사용하여 수정한 예
#include <iostream>
using namespace std;
int main() {
const int ArSize=20;
char name[ArSize];
char dessert[ArSize];
cout<<"이름을 입력하세요:\n";
cin.get(name, ArSize).get();
cout<<"좋아하는 디저트를 입력하시오:\n";
cin.get(dessert, ArSize).get();
cout<<"맛있는 "<<dessert;
cout<<" 디저트를 준비하겠습니다. "<<name<<" 님!\n";
return 0;
문자열과 문자열과 수치의 수치의 혼합 혼합 입력 입력
행 단위의 문자열 입력과 수치 입력을 혼합하여 사용하는 예
#include <iostream>
using namespace std;
int main() {
cout<<"지금 사시는 아파트에 언제 입주하셨습니까?\n";
int year;
cin>>year;
//(cin>>year).get(); //cin.get(); or cin.get(ch);
cout<<"주소를 말씀해 주시겠습니까?\n";
char address[80];
cin.getline(address, 80);
cout<<"아파트의 입주 연도: "<<year<<endl;
cout<<"주소: "<<address<<endl;
cout<<"등록이 완료되었습니다.\n";
return 0;
}
구조체 구조체 (structure) (structure)
구조체 (structure)
서로 다른 몇 개의 자료 형을 단일 명칭 하에서 한데 묶은 구조
서로 관련된 정보를 하나의 단위로 묶어서 저장할 수 있다.
하나의 구조체 안에 여러 종류의 데이터를 저장 할 수 있기 때문에 배 열보다 융통성이 있다.
구조체는 사용자가 정의할 수 있는 데이터 형이다.
구조체 생성 단계
구조체 서술 정의
구조체에 저장할 여러 종류의 데이터를 서술하고 이름을 정한다.
구조체 서술에 따라 구조체 변수를 생성
구조체 데이터 객체를 생성하는 단계
구조체 구조체 (structure) (structure)
예) 어떤 장난감 회사에서 생산하고 있는 모형 풍선 제품들에 대한 정보
키워드 struct는 이 코드가 구조체 서술을 정의하고 있다는 것을 나타냄
태그(tag)라고도 부르는 식별자 inflatable은 새로 만들어지는 데이터 형의 이름으로 사용
{ }안에는 이 구조체를 구성하는 데이터 형들의 리스트를 삽입할 수 있다.
이 리스트의 각 항목을 멤머(member)라고 부른다.
struct inflatable // 구조체 서술 {
char name[20]; // 배열 멤버
float volume; // float 형 멤버 double price; // double형 멤버 };
구조체 구조체 (structure) (structure)
구조체 서술 템플릿
구조체 변수 생성
inflatable hat; //inflatable 형의 구조체 변수
struct inflatable {
char name[20];
float volume;
double price;
};
여는 중괄호와 닫는 중괄호
구조체 멤버들
세미콜론은 템플릿 선언을 끝낸다
struct 키워드 태그는 새로운 데이터형의 이름이 된다
구조체 구조체 (structure) (structure)
구조체 멤버 접근
멤버 연산자(.)를 사용하여 구조체의 개별적인 멤버에 접근할 수 있다.
hat.volumn은 hat 변수의 volumn 멤버를 나타내고, hat.price는 hat 변수의 price 멤버를 나타낸다.
hat.price는 double형으로 선언되었기 때문에 double 형 변수와 모든 면에 서 동일하다.
hat은 구조체이고 hat.price는 double 형 변수이다.
배열 첨자를 이용하여 배열 원소에 접근 할 수 있듯이, 멤버 이름을 사용 하여 구조체의 멤버에 접근할 수 있다.
구조체 구조체 (structure) (structure)
구조체의 예
#include <iostream>
using namespace std;
struct inflatable {
char name[20];
float volume;
double price;
};
int main() {
inflatable guest=
{
"Glorious Gloria", 1.88,
29.99 };
inflatable pal=
{
"Audacious Arthur", 3.12,
32.99 };
cout<<"지금 판매하고 있는 모형 풍선은 “
<<guest.name;
cout<<" 와 "<<pal.name<<"입니다.\n";
cout<<"두 제품을 $";
cout<<guest.price+pal.price
<<"에 드리겠습니다.\n";
return 0;
}
구조체 구조체 (structure) (structure)
구조체 변수 초기화
한 쌍의 중괄호 { } 안에 초기화 값들이 콤마로 구분되는 초기화 리스 트를 넣는다.
모든 값을 한 행에 나타낼 수도 있다.
inflatable guest=
{
"Glorious Gloria", 1.88,
29.99 };
inflatable guest= {"Glorious Gloria", 1.88, 29.99};
구조체 구조체 (structure) (structure)
구조체의 배열
구조체의 배열을 만드는 방법은 기본 데이터 형의 배열을 만드는 것과 같다.
예를 들어, inflatable형 구조체 100개를 원소로 가지는 배열을 생성하 려면
inflatable gifts[100]; //inflatable형 구조체 100개의 배열
gifts를 inflatable 형의 배열로 만들었기 때문에, gifts[0] 또는 gift[99]와 같 은 배열 원소는 inflatable형 객체이다.
cin>>gifts[0].volumn; //첫 번째 구조체의 volumn 멤버에 입력
cout<<gifts[99].price<<endl; // 마지막 구조체의 price 멤버를 출력
초기화
구조체 초기화 규칙과 배열 초기화 규칙을 하나로 결합
9 inflatable guests[2]= // 구조체의 배열을 초기화 {
{“Bambi”, 0.5, 21.99}, // 첫 번째 배열 원소인 구조체
공용체 공용체 ( union) ( union)
공용체 (union)
서로 다른 데이터 형을 한 번에 한 가지만 보관할 수 있는 데이터 형식
여러 가지 데이터 형 중에서 한 번에 어느 하나만 보관할 수 있다.
union one4all {
int int_val;
long long_val;
double double_val;
};
one4all pail;
pail.int_val=15;//int형을 저장 cout<<pail.int_val;
pail.double_val=1.38;
//double형을 저장, int형 값은 소실 cout<<pail.double_val;
열거체 열거체 (enumeration) (enumeration)
열거체 (enumeration)
0부터 시작하는 정수 값들만 차례로 대입되는 특수 구조체
열거체 선언
enum spectrum{red, orange, yellow, green, blue, violet, indigo, ultraviolet};
9 spectrum을 새로운 데이터 형의 이름으로 만든다. struct형 변수를 구조체라 부 르듯이, enum 형 변수를 열거체(enumerationm)이라 부른다.
9 red, orange, yellow,… 등을 0에서 7까지의 정수 값을 각각 나타내는 기호 상수 로 만든다. 이 상수들을 열거자(enumerator)라 부른다.
열거체 변수 선언
spectrum band; //이 변수 band는 단지 8개의 값만 보유
9 band = blue; band = green;
9 band = orange; band = 3; No (int→spectrum)
9 band = 2000; No (2000은 열거자 아님) int color = blue; ok (spectrum→
9 ++band; No (일부 C++에서는 허용) int 확장)
tag에 해당 (새로운 데이터 형)
0 1 2 3 4 5 6 7 열거자 (enumeration)
포인터 포인터 (pointer) (pointer)
포인터 (pointer)
포인터는 값 자체가 아니라 Data 값이 있는 곳의 주소를 저장하는 변 수 (Data 값 자체를 저장하는 변수 아님)
즉, 그 변수의 값은 주소(char변수의 값 : char, int 변수의 값 : int, 포인 터의 값 : 주소)
주소 연산자 (&)
변수 앞에 &를 사용 -> 그 변수의 주소(일반적으로 16진수)를 알 수 있 음
#include <iostream>
using namespace std;
int main() {
int donuts=6;
double cups=4.5;
cout<<"donuts의 값 = "<<donuts;
cout<<", donuts의 주소 = "<<&donuts<<endl;
cout<<"cups의 값 = "<<cups;
cout<<", cups의 주소 = "<<&cups<<endl;
포인터 포인터 (pointer) (pointer)
내용 참조 연산자 (*)
포인터 앞에 *을 사용 -> 그 위치에 저장된 값을 획득
예) maily가 포인터라면 주소 표시, *maily는 그 주소에 저장된 값을 표시
#include <iostream>
using namespace std;
int main() {
int updates=6;
int *p_updates; //포인터 선언
p_updates=&updates;
cout<<"값: updates = "<<updates;
cout<<", *p_updates = "<<*p_updates<<endl;
cout<<"주소: &updates = "<<&updates;
cout<<", p_updates = "<<p_updates<<endl;
*p_updates=*p_updates+1;
cout<<"변경된 updates = "<<updates<<endl;
*p_updata=update;
p_update=&update;
동전의 양면성
포인터 포인터 (pointer) (pointer)
포인터의 선언
반드시 어떤 데이터 형을 가리키는지 명시!
형식
typeName * pointer_name;
9 예) int* p_updates; // p_updates는 포인터(주소)이고, *p_updates는 포인터가 아 니라 int형 변수
9 int* P1, P2; // P1은 포인터 변수, P2는 int 변수.
9 double* tax_ptr; // tax_ptr은 double 형을 가리키는 포인터 변수
9 char* str; // str은 char형을 가리키는 포인터 변수
포인터의 초기화
선언 명령문을 사용하여 포인터를 초기화
int higgens=5;
int* pt=&higgens;
9 포인터에 의해 지시되는 값인 *pt가 초기화되는 것이 아니라, 포인터 pt가
&higgens 값으로 초기화 된다
포인터 포인터 (pointer) (pointer)
포인터 초기화 예
#include <iostream>
using namespace std;
int main() {
int higgens=5;
int *pt=&higgens;
cout<<"higgens의 값 = "<<higgens<<
", higgens의 주소 = "<<&higgens<<endl;
cout<<"*pt의 값 = "<<*pt<<", pt의 주소 = “
<<pt<<endl;
return 0;
new new 를 를 사용한 사용한 메모리 메모리 할당 할당
new의 사용 (포인터 선언과 동시에 사용)
메모리의 동적 할당 -> OOP의 진수!
어떤 데이터 형의 메모리를 원하는지 new 연산자에게 알려주면 new 연산자는 몇 바이트가 필요한지 결정하고 그 크기의 메모리 블록을 찾 아 할당하고 그 블록의 주소를 리턴 그 리턴 되는 주소를 포인터에 대 입⇒ Every thing is done
예) int* pn = new int;
9 new int 부분은 int형 데이터를 저장할 새로운 메모리가 필요하다고 프로그램 에게 알린다.
9 new 연산자는 뒤따르는 데이터 형을 보고, 몇 바이트가 필요한지를 파악한다.
9 적당한 메모리를 찾아 필요한 만큼 할당하고, 그 주소를 리턴한다.
9 리턴 되는 주소는 int 형을 지시하는 포인터로 선언되어 있는 pn에 대입된다.
형식
typeName pointer_name = new typename;
delete를 사용한 메모리 해제
int* ps = new int; // new로 메모리 할당
…….. // 메모리 사용
delete ps; // delete로 메모리 해제
new new 를 를 사용한 사용한 메모리 메모리 할당 할당
new와 delete를 사용할 때 규칙
new로 할당하지 않은 메모리는 delete로 해제하지 않는다.
같은 메모리 블록을 연달아 두 번 delete로 해제하지 않는다.
new [ ]로 메모리를 할당한 경우에는 delete [ ]로 해제한다.
new를 대괄호 없이 사용했으면 delete도 대괄호 없이 사용한다.
널 포인터에는 delete를 사용하는 것이 안전하다.
int* ps = new int; // 맞다
delete ps; // 맞다
delete ps; // 틀리다
int jugs=5; // 맞다
int* pi = &jugs; // 맞다
delete pi; // new로 할당한 메모리가 아니므로 틀리다.
new new 를 를 사용한 사용한 메모리 메모리 할당 할당
두 가지 다른 데이터 형을 다루는 예
#include <iostream>
using namespace std;
int main() {
int *pt=new int;
*pt=1001;
cout<<"int 형";
cout<<"값 = "<<*pt<<": 메모리 위치 = "<<pt<<endl;
double *pd=new double;
*pd=10000001.0;
cout<<"double 형";
cout<<"값 = "<<*pd<<": 메모리 위치 = "<<pd<<endl;
cout<<"pt의 크기 = "<<sizeof pt;
cout<<"*pt의 크기 ="<<sizeof *pt<<endl;
cout<<"pd의 크기 = "<<sizeof pd;
cout<<"*pd의 크기 = "<<sizeof *pd<<endl;
return 0;
new new 를 를 사용한 사용한 동적 동적 배열의 배열의 생성 생성
동적 배열 (dynamic array) 생성
정적 바인딩 (static binding)
프로그램이 컴파일 될 때 배열을 위한 메모리가 할당
동적 바인딩 (dynamic binding)
프로그램이 실행하는 동안에 배열을 위한 메모리가 할당. 배열이 실행 시 간에 생성된다는 것을 뜻 함.
사용법
int* psome = new int[10]; // 10개의 int 형 값을 저장할 블록을 할당
9 배열 원소의 데이터 형과 원소 개수를 new에 알려준다.
9 ⇒ new 연산자는 그 Block의 첫 번째 주소를 return
9 ⇒ then psome은 그 Block의 첫 번째 원소인 int형 하나를 가리키는 포인터다!!
typeName* pointer_name = new typeName[num_elements];
9 tpeName형의 원소를 num_elements만큼 저장할 수 있는 메모리 블록을 할당하 고, 그 블록의 첫 번째 원소의 주소를 pointer_name에 대입한다.
해제
9 delete [ ] psome; //대괄호 [ ]를 사용했기 때문에 배열 전체가 해제
원소 접근 방법
new new 를 를 사용한 사용한 동적 동적 배열의 배열의 생성 생성
동적 배열의 예
#include <iostream>
using namespace std;
int main() {
double *p3=new double [3];
p3[0]=0.2;
p3[1]=0.5;
p3[2]=0.8;
cout<<"p3[1]은 "<<p3[1]<<" 입니다.\n";
p3=p3+1;
cout<<"이제는 p3[0]이 "<<p3[0]<<" 이고,";
cout<<"p3[1]이 "<<p3[1]<<" 입니다.\n";
p3=p3-1;
delete [] p3;
return 0;
new new 를 를 사용한 사용한 동적 동적 구조체 구조체
사용법
inflatable* ps = new inflatable;
inflatable 형의 구조체를 저장할 수 있는 크기의 새로운 메모리 블록을 확 보하고, 그것의 주소를 포인터 ps에 대입
멤버에 접근
멤버 연산자(.)를 사용하지 못한다.(동적 구조체의 이름이 없기 때문)
동적 구조체의 주소는 알고 있기 때문에 화살표 멤버 연산자 (->) 사용
예) ps가 inflatable 형 구조체를 지시하는 포인터라면, ps->price는 ps가 지 시하는 구조체의 멤버이다.
ps가 구조체를 지시하는 포인터이면, *ps는 그 포인터가 지시하는 값, 즉 구조체가 된다. 따라서, (*ps).price는 그 구조체의 멤버이다.
new new 를 를 사용한 사용한 동적 동적 구조체 구조체
동적 구조체 생성과 구조체 멤버에 접근하는 예
#include <iostream>
using namespace std;
struct inflatable {
char name[20];
float volume;
double price;
};
int main() {
inflatable *ps=new inflatable;
cout<<"모형풍선의 이름을 입력하십시오: ";
cin.get(ps->name, 20);
cout<<"부피를 세제곱 피트 단위로 입력하십시오: ";
cin>>(*ps).volume;
cout<<"가격을 달러 단위로 입력하십시오: $";
cin>>ps->price;
cout<<"이름: "<<(*ps).name<<endl;
cout<<"부피: "<<ps->volume<<endl;
cout<<"가격: "<<ps->price<<endl;
delete ps;
return 0;