03. 제어구조와 배열2
제어구조와 배열 (2)
< ex19_multi_array.cpp >
#include <iostream>
using namespace std;
#define WIDTH 9
#define HEIGHT 3
int main(int argc, char const *argv[]) {
int table[HEIGHT][WIDTH];
int r, c;
for (r = 0; r < HEIGHT; r++){
for (c = 0; c < WIDTH; c++){
table[r][c] = (r+1) * (c+1);
}
}
for (r = 0; r < HEIGHT; r++){
for (c = 0; c < WIDTH; c++){
cout << table[r][c] << ", ";
}
cout << endl;
}
return 0;
}
-
다차원 배열
- 데이터타입 배열이름[행][열];
- 바깥 루프가 보통 높은 차원의 배열, 안쪽 루프가 보통 낮은 차원의 배열
- c++에서는 배열의 연산 불가능
- sizeof() -> 해당 변수에 할당된 메모리의 크기를 byte단위로 리턴해준다
< ex18_2_advanced_for.cpp >
#include <iostream>
using namespace std;
int main(int argc, char const *argv[]) {
int list[] = {1,2,3,4,5,6,7,8,9,10};
int list2[10];
// int 하나는 4byte
int length = sizeof(list) / sizeof(int); // 40 / 4 -> 10 (엘리먼트 개수)
// list 메모리 크기 : int 크기(4) * 10개 -> 40byte
cout << length << endl;;
// 복사 전 list2 출력, 초기화 안 된 배열
// 출력 -> 14292736 0 16 0 0 0 4200206 0 4199744
// 지역변수는 초기화되지 않으면 임의의 값을 가진다
// 0으로 초기화되지 않는다
for(auto i: list2){
cout << i << " ";
}
// 복사
for (int i = 0; i < length; i++){
list2[i] = list[i]; // 엘리먼트 단위로 복사
}
// 복사 후 lsit2 출력
for(auto i: list2){
cout << i << " ";
}
return 0;
cout << list << endl
// 0x61fda0 출력, 주소값 출력
}
< ex01_func.cpp >
#include <iostream>
using namespace std;
// 함수의 존재 밝혀준다, 함수 원형, 뒤에 나올 것이다
// 매개변수의 이름은 생량 가능하다
int max(int x, int y);
int max(int x, int y){
if (x > y){
return x;
}
else
{
return y;
}
}
int main(int argc, char const *argv[]) {
int n;
n = max(2,3);
// C++는 함수를 정의 전에 호출해도 요즘 컴파일러는 돌아간다, 컴파일러에 따라 상이
// 컴파일러는 매개변수가 매칭이 잘 되고 있는가, 리턴값 맞는가를 체크
// 컴파일러가 해석할 수 있는 정보는 int max(int x, int y); 에 다 있다
cout << "result : " << n << endl;
return 0;
}
-
함수의 구조
-
반환형 함수이름(매개변수){}
-
ex) int max(int x, int y){}
-
반환형 생략시 디폴트로 int 배정
-
void -> 리턴데이터가 없는 때
-
-
함수 인자 전달 방법
-
call by value
- 값 복사
-
call by reference
- &(참조변수), 원본에 대한 참조로 매개변수 넘기는 것
- 참조변수 -> 기존 변수에 새로운 운영 이름 추가하는 것, 저장공간은 하나
- 참조변수는 초기화문과 같이 써야 한다, 분리되어 있으면 안 된다 (이름을 붙여야 하는데 이름을 붙일 곳이 없는 상황)
- 참조변수는 주로 매개변수 처리할 때 사용한다
- 원본을 다른 함수에서 참조매개변수를 통해서 수정할 수 있다
-
call by address (pointer)
-
사용자가 선택해서 쓰면 된다
-
파이썬은 call by value, call by reference가 일어나는 데이터타입이 정해져 있다
-
< ex04_overload.cpp >
#include <iostream>
using namespace std;
int square(int i){
cout << "square(int) : " << endl;
return i*i;
}
double square(double i){
cout << "square(double) : " << endl;
return i*i;
}
int main(int argc, char const *argv[]) {
cout << square(10) << endl;
cout << square(2.0) << endl;
return 0;
}
< ex05_default_param.cpp >
#include <iostream>
using namespace std;
void display(char c = '*'){
for (int i = 0; i < 20; i++){
cout << c;
}
cout << endl;
}
void display(char c = '*', int n = 10){
for (int i = 0; i < n; i++){
cout << c;
}
cout << endl;
}
int main(int argc, char const *argv[]) {
display(); // 허용 X, 둘 다 호출가능한 형태
display('#'); // 허용 X, 둘 다 호출가능한 형태
display('#', 5); //후자의 display
return 0;
}
-
중복 함수 (overload)
-
함수의 이름은 동일하지만 함수의 인자가 다르면 다른 함수로 인식
-
동일한 이름의 함수를 여러개 만들 수 있다
-
함수 중복 체크할 때 리턴타입을 보지 않는다 (함수의 이름과 매개변수만 체크한다)
-
< ex05_2_array_func.cpp >
#include <iostream>
using namespace std;
void initArray(int array[], int size, int value = 0){
// int value = 0는 call by value, & 없기 때문, 대입연산을 통해서 값이 대입될 수 있어야 한다
// int array[] -> 비워두면 초기화식의 엘리먼트의 개수에 따라 결정된다, 범용함수
// 호출될 때 결정된다, 배열의 크기 한정짓지 않았다
// int size = sizeof(array) / sizeof(int);
int array[] -> call by address (원본으로 작업)
for (int i = 0; i < size; i++){
array[i] = value;
}
}
void printArray(int array[], int size){
// int size = sizeof(array) / sizeof(int);
for(int i = 0; i < size; i++){
cout << array[i] << " ";
}
cout << endl;
}
int main(int argc, char const *argv[]) {
const int ARRAY_SIZE = 40;
int intList[ARRAY_SIZE];
initArray(intList,ARRAY_SIZE, 100); // 두 번째 인자 값으로 초기화
printArray(intList, ARRAY_SIZE);
initArray(intList, ARRAY_SIZE); //인자 하나, 0으로 초기화
printArray(intList, ARRAY_SIZE);
return 0;
}
- 배열의 개수는 상수로 운영하는 걸 추천
- 배열은 call by value 불가능! call by address 방식으로 전달한다 (배열1 = 배열2; 불가능)
- 배열1 = 배열2; 허용되면 call by value 가능, 안 되면 call by value 불가능
< ex06_string.cpp >
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[]) {
string s1 = "Slow", s2 = "steady";
// s1은 string 객체의 인스턴스
string s3 = "the race.";
string s4;
s4 = s1 + " and " + s2 + " wins " +s3;
cout << s4 << endl;
return 0;
}
-
string 클래스
- 문자열 데이터 저장 및 처리 함수(메서드) 제공
- #include <string>을 먼저 지정 후 사용</string>
-
파이썬의 문자열은 조작 불가능 (불변)
-
c++ 문자열은 조작 가능
- s.empty(), s.insert(), s.remove(), s.find(), s.reverse()
< ex07_string.cpp >
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[]) {
string s1, addr;
cout << "name : ";
cin >> s1;
// enter를 치면 "홍길동\r\n" 입력된다
// \r 입력되면 문자열이 끝났다고 생각함, 홍길동이 s1에 들어간다
// getline은 줄바꿈 문자열이 있을 때까지, \n이 남아있으니 새로운 문자열 받지 않고 자동으로\n을 받는다
// ignore()을 사용하게 되면 \n을 제거하고 쓰라는 뜻
cin.ignore(); // 엔터키 제거
// 주소는 공백이 들어가니
cout << "address : ";
getline(cin, addr);
cout << addr << "'s " << s1 << " sir hello" << endl;
return 0;
}
< ex08_string.cpp >
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[]) {
string s = "when in rome, do as the romans";
int size = s.size();
int index = s.find("rome");
cout << size << endl;
cout << index << endl;
s. insert(0, "hello"); // 맨 앞에 문자열 추가
cout << s << endl;
s += "end of world" // 맨 뒤에 문자열 추가
cout << s << endl;
s.append("\n-------------\n"); // 맨 뒤에 문자열 추가
cout << s;
return 0;
}
-
sizeof(s) -> 항상 32 리턴, 스트링 객체의 크기는 항상 32 바이트
- string 객체의 인스턴스에 데이터가 있다는 것이 아니라 다른 곳에 데이터가 있다는 뜻
- 스택에는 자신의 데이터의 주소를 가지고 있다
- 힙에 실제 데이터 저장, 관리
-
s.size -> 문자열의 사이즈 리턴
- size는 힙에 있는 실제 데이터의 길이를 리턴해주는 것
-
파이썬은 해당 인스턴스가 힙에 만들어진다
-
c++은 실제 데이터의 저장공간이 힙에 만들지 스택에 만들지 선택할 수 있다
-
스트링 객체 내부 관리 데이터의 크기가 32바이트라는 뜻
< ex09_string.cpp >
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char const *argv[]) {
string s = "when in rome, do as the romans";
// 읽기
for(auto& ch : s){ // char &ch = s[i], 참조, 속도 더 빠름
cout << ch << ' ';
}
cout << endl;
for (auto ch : s){ // char ch = s[i], 새로운 변수 만들고 값 복사
cout << ch << ' ';
}
cout << endl;
// 읽을 때는 참조변수로 하나 값 복사하나 결과 똑같다
// 쓰기 (참조와 값복사가 다름)
for(auto& ch : s){ // char &ch = s[i], 이름만 추가, T를 위한 공간 할당 X, 원본으로 작업
ch = 'T';
}
cout << s << endl;
for (auto ch : s){ // char ch = s[i], ch를 위한 별도의 메모리 공간을 만들고 운영(1byte), 값 복사
ch = 'W'; // 메모리 공간에 W 입력
}
cout << s << endl; // 원본에는 변화 X
// 쓰기 작업은 속도의 문제가 아니라 원본을 수정할 것인지 아닌지의 문제
// 속도 자체는 참조변수가 더 빠르다
return 0;
}
< ex10_string.cpp >
#include <iostream>
using namespace std;
int main(int argc, char const *argv[]) {
string list[] = {"홍길동", "고길동", "둘리"};
// string list[] -> 지역변수, 스택에 지정
// 배열명 list는 상수이다, 배열명도 스택에 독자적인 메모리 공간을 가진다, 배열명은 배열의 첫 번째 엘리먼트의 주소값을 가진다 (스택), 이 값을 수정할 수 없다 (상수이기 때문에)
// 배열1 = 배열2의 표현은 배열명을 바꾸겠다는 표현이기 때문에 불가능하다
// 실제 배열의 데이터는 힙에 있다
for(auto& name : list){
cout << name << endl;
}
return 0;
}
- 내가 지금 작업중인 데이터가 어디에 있냐? 내가 복사본으로 작업하고 있는지 아니면 원본으로 작업하고 있는지 (스택 or 힙) -> 항상 신경쓰기