C++

03. 제어구조와 배열2

til_t 2021. 1. 22. 13:46

제어구조와 배열 (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 힙) -> 항상 신경쓰기