본문 바로가기

개발 공부/C++

따라하며 배우는 C++ 7. 함수

 

따라하며 배우는 C++ 

 

7. 함수

 

7.1 매개변수Parameter와 인자Argument의 구분

 

#include <iostream>
#include <vector>
using namespace std;
int foo(int x, int y);
int foo(int x, int y)
{
	return x + y;
}//x and y are destroyed here, 지역 변수.
int main()
{
	int x = 1, y = 2;
	foo(6, 7); //6, 7 : arguments (actual parameters) = 실매개변수
	foo(x, y + 1);
	return 0;
}

 

7.2 값에 의한 전달 Passing Arguments by Value(Call by Value)

 

 

#include <iostream>
#include <vector>
using namespace std;

void doSomething(int y)
{
	cout << "In func " << y << " " << &y << endl;
}
int main()
{
	doSomething(5); //리터럴 값이 매개변수로 전달된다.
	//내부적으로 함수에서 int y가 선언이 되고 리터럴 값으로 초기화됨.
	//값이 전달됨


	int x = 6;

	cout << "In main " << x << " " << &x << endl;
	doSomething(x); //6이라는 값이 argument로서 parameter로 전달됨

	return 0;
}

이런 경우 함수가 바깥에 영향을 줄 수 없다.

 

 

7.3 참조에 의한 인수 전달 Call by Reference

 

#include <iostream>
#include <cmath>//sin(), cos()
using namespace std;

void addOne(int& y)
{
	cout << y << " " << &y << endl;
	y = y + 1;
	cout << y << " " << &y << endl;
}
//call by value였다면 아무런 의미가 없는 연산이겠지만
//reference전달이라 값이 그대로 변화되게 된다.
int main()
{
	int x = 5;
	cout << x << " " << &x << endl;
	addOne(x);
	cout << x << " " << &x << endl;

	int y = 3;
	addOne(y);
	cout << y << " " << &y << endl;
	return 0;
}

 

#include <iostream>
#include <cmath>//sin(), cos()
using namespace std;

void getSinCos(const double degree, double& sinOut, double& cosOut)
{
	//그냥 변수형이면 단순 입력이라는 사실을 알 수 있다.
	//& 표시가 있다면 해당 변수 그 자체가 들어온 것이라고 보면 된다.
	static const double pi = 3.141592;
	//매번 새로 정의가 되는 것이 아니라 메모리에서 정해져 재사용할 수 있음.
	//&들을 return처럼 쓰일 수 있다.
	double radians = degree * pi / 180.0;
	sinOut = sin(radians);
	cosOut = cos(radians);
}

int main()
{
	double sin(0.0);
	double cos(0.0);
	getSinCos(30.0, sin, cos);
	cout << sin << " " << cos << endl;
	return 0;
}

 

#include <iostream>
#include <cmath>//sin(), cos()
using namespace std;

void foo(int& x)
{
	cout << x << endl;
}

int main()
{
	//foo(6); //에러

	return 0;
}

참조는 메모리 주소를 가지고 있어야 하므로 위 코드는 에러가 생긴다.

void foo(int x) 혹은 void foo(const int &x)로 해결할 수 있다. 단, 후자는 수정이 되지 않는 경우만.

 

입력은 거의 const int x 혹은 const int &x.

출력은 int &x

 

#include <iostream>
#include <cmath>//sin(), cos()
using namespace std;

void foo(int *&ptr) {
	cout << ptr << " " << &ptr << endl;
}
int main()
{
	int x = 5;
	int* ptr = &x;
	cout << ptr << " " << &ptr << endl;
	foo(ptr);
	return 0;
}

 

이중포인터를 쓸 일이 있을 때 typedef int* pint라고 선언해서 사용하면 덜 헷갈린다.

#include <iostream>
#include <cmath>//sin(), cos()
using namespace std;

//정적 어레이를 매개변수로 보낼 때는 배열 크기를 꼭 보내야 한다.
void printElement(int (&arr)[4])
{
	cout << arr << " " << &arr << " " << 
		*arr << " " << arr[0] << " " << &arr[0] << endl;
}
int main()
{
	int arr[]{ 1, 2, 3, 4 };
	cout << arr << " " << &arr << " " << 
		*arr << " " << arr[0] << " " << &arr[0] << endl;
	printElement(arr);
	return 0;
}

 

 

#include <iostream>
#include <vector>
using namespace std;

//정적 어레이를 매개변수로 보낼 때는 배열 크기를 꼭 보내야 한다.
void printElement(vector<int> &arr)
{
}
int main()
{
	vector<int> arr{ 1, 2, 3, 4 };
	printElement(arr);
	return 0;
}

 

7.4 주소에 의한 인수 전달 Call by Address

 

#include <iostream>
#include <vector>
using namespace std;

void foo(int* ptr)
{
	cout << *ptr << " " << ptr << " " << &ptr << endl;
}
int main()
{
	int value = 5;
	cout << value << " " << &value << endl;
	int* ptr = &value;
	cout << &ptr << endl;
	foo(ptr);
	foo(&value);
	//foo(5); //불가
	return 0;
}

 

포인터 변수도 변수이므로 원래 main의 pointer 주소와

매개변수로 전달된 포인터의 주소가 다르다.

즉 위 코드는 값에 의한 전달이다.

 

#include <iostream>
#include <vector>
using namespace std;

void foo(const int* ptr)
{
	cout << *ptr << " " << ptr << " " << &ptr << endl;
	//de-refrencing 불가
}
int main()
{
	int value = 5;
	cout << value << " " << &value << endl;
	int* ptr = &value;
	cout << &ptr << endl;
	foo(ptr);
	foo(&value);
	//foo(5); //불가
	return 0;
}

 

#include <iostream>
#include <vector>
using namespace std;

void foo( int* ptr)
{
	cout << *ptr << " " << ptr << " " << &ptr << endl;
	*ptr = 10;
}
int main()
{
	int value = 5;
	cout << value << " " << &value << endl;
	int* ptr = &value;
	cout << &ptr << endl;
	foo(ptr);
	foo(&value);
	//foo(5); //불가
	cout << value << " " << &value << endl;
	return 0;
}

수정은 가능하다.

 

레퍼런스처럼 사용 가능하나 실용적인 건 레퍼런스.

 

위와 같은 스타일이 C스타일 코딩.

배열에서는 []가 바로 de-referencing처럼 작용함.

 

void foo(const int *ptr, int *arr, int length)
{
	for(int i=0; i<length; ++i)
    	cout << arr[i] << endl;
    int x = 1;
    ptr = &x;
 }

 

여기서 ptr은 포인터 변수 자체를 출력하는 것이므로 수정이 가능.

막으려면 const int * const ptr로 막을 수 있지만 굳이 안 쓰는 경우가 많다.

결국 값에 의한 전달이고, foo를 호출한 곳엔 영향을 주지 않기 때문에.

 

 

7.5 다양한 반환 값들(값, 참조, 주소, 구조체, 튜플)

 

#include <iostream>
using namespace std;

int getValue(int x)
{
	int value = x * 2;
	return value;
}
//return by value 형식

int main()
{
	int value = getValue(3);
	return 0;
}

가장 간단하고 안전한 방법.

그러나 함수 안에 선언 및 초기화가 따로 되므로 속도가 느릴 수 있다.

 

#include <iostream>
using namespace std;

int* getValue(int x)
{
	int value = x * 2;
	return &value;
}
//주소로 돌려받는 형식

int main()
{
	int *value = getValue(3);
	//이건 아래보다 더 위험하다. 주소를 직접 받는 방법
	//영역을 넘어서 사라진 메모리 주소를 받는 것이다.
	cout << *value << endl;

	//이것도 가능. int value = *getValue(3); 
	//매개변수를 de-referencing해 받는 방법.
	//그러나 이 방법은 권장하지 않는다.
	//함수가 구동되고 나서 사라질 변수를 디레퍼런싱하는 것이 안전하지 않기 때문
	//위는 값을 받은 것이므로 cout<<value<<endl;
	return 0;
}

 

그러나 특이한 방식으로 주소에 의한 반환을 사용하기도 한다.

#include <iostream>
using namespace std;

int* allocateMemory(int size)
{
	return new int[size];
}

int main()
{
	int* array = allocateMemory(3);
	//어떤 메모리를 생성하고 그 메모리의 포인터를
	//함수의 리턴값으로 받는 디자인 패턴이 존재한다. = factory pattern
	return 0;
}

위 방법도 위험하긴 하다. delete를 어떻게 할지 막막할 수도.

 

#include <iostream>
using namespace std;

//return by reference
int& getValue(int x)
{
	int value = x * 2;
	return value;
}

int main()
{
	int value = getValue(5);
	//레퍼런스를 반환해서 그 레퍼런스가 가리키는 값이 복사되어 들어온다.
	cout << value << endl;
	//비교적 안전.
	//다만 int &value = getValue(5);
	//이런 식으로 레퍼런스를 레퍼런스로 받으면 원래 메모리가 불명확하므로 위험.
	return 0;
}

레퍼런스를 레퍼런스로 받으면 value를 두 번째 이용할 시 문제가 발생한다.

OS로 메모리가 반환되어 버리는 것.

 

#include <iostream>
#include <array>
using namespace std;

//return by reference
int& get(array<int, 100>& my_array, int ix)
{
	return my_array[ix];
}
int main()
{
	array<int, 100> my_array;
	get(my_array, 30) = 1024;
	cout << my_array[30] << endl;
	return 0;
}

메모리가 이미 잡혀 있는 상태에서, 요소를 변수처럼 편리하게 사용할 때 많이 쓰인다.

 

#include <iostream>
#include <array>
using namespace std;

//return by structure
//함수 하나를 만들 때마다 구조체를 만들어주면
//구현 오버헤드가 꽤 커진다. 예전에 애용되던 방식.
struct S
{
	int a, b, c, d;
};

S getStruct()
{
	S my_s{ 1, 2, 3, 4 };
}
int main()
{
	S my_s = getStruct();

	return 0;
}

특히 C 스타일 코딩에서 많이 쓰임.

#include <iostream>
#include <array>
#include <tuple>
using namespace std;

//return by tuple
tuple<int, double> getTuple()
{
	int a = 10;
	double d = 3.14;
	return make_tuple(a, d);
}
//사용자 정의 자료형처럼 쓰임.

int main()
{
	tuple<int, double> my_tp = getTuple();
	get<0>(my_tp); //a
	get<1>(my_tp); //d
	return 0;
}

 

#include <iostream>
#include <array>
#include <tuple>
using namespace std;

//return by tuple
tuple<int, double> getTuple()
{
	int a = 10;
	double d = 3.14;
	return make_tuple(a, d);
}
//사용자 정의 자료형처럼 쓰임.

int main()
{
	auto[a, d] = getTuple();
	
	return 0;
}

최신 버전에선 위와 같은 것도 가능.

 

 

 

7.6 인라인 함수 Inline Functions

 

#include <iostream>
using namespace std;

inline int min(int x, int y)
{
	return x > y ? y : x;
}
//inline으로 바꾸면 함수가 아닌 것처럼 컴파일된다.
//inline 키워드는 할 수 있으면 하는 것이다. 권장사항이라 변환이 안될 수도 있다.
int main()
{
	cout << min(5, 6) << endl;
	cout << min(3, 2) << endl;
	//cout<<(5>6?6:5)<<endl; 이런 것처럼 작동함.
	return 0;
}

함수 자체가 호출되어 있는 곳에 선언되어 있는 것처럼 변경된다.

작은 함수가 대체되면 속도가 빨라지는 것이다.

단점으론 컴파일된 프로그램이 커질 수도 있다. (최적화에 불리)

 

 

7.7 함수 오버로딩

 

#include <iostream>
using namespace std;

int add(int x, int y)
{
	return x + y;
}
double add(double x, double y)
{
	return x + y;
}
//함수 이름이 같아도 작동함.
int main()
{
	add(1, 2);
	add(3.0, 4.0);
	return 0;
}

함수 이름으로만 함수가 특정되는 것이 아니라, (return type이 다른 건 인식 못함)

매개변수의 개수와 타입에 따라 특정될 수 있다.

다만 컴파일 타임에 argument의 형이 결정되어 있어야 한다.

 

#include <iostream>
using namespace std;
typedef int my_int;
void print(int x) {}
void print(my_int x) {}
int main()
{
	
	return 0;
}

사용자 정의형이라도 같은 것으로 인식되어 버린다.

 

 

#include <iostream>
using namespace std;
void print(char* value) {}
void print(int value) {}
int main()
{
	print(0);
	print('a'); //이 경우 전자가 아니라 후자로 인식된다.
	//매치를 못 찾는 경우.
	return 0;
}

위의 경우,

void print(const char* value) {}

와 메인에서

print("a"); 로 바꾸면 해결 가능.

#include <iostream>
using namespace std;
void print(unsigned int value) {}
void print(float value) {}
int main()
{
	print('a'); //int와 float 둘 다 불명확하기 때문에 에러 발생.
	print(0); //그냥 int가 아닌 unsigned라 타입이 모호해진다.
	print(3.141592); //double이 아니라 인식이 안됨.

	//print(0u); print(3.14159f); 혹은 casting으로 해결 가능.
	//정확하게 형을 사용해야 한다.
	return 0;
}

 

 

7.8 매개변수의 기본값 Default Parameters

 

 

#include <iostream>
using namespace std;

void print(int x = 0) //default parameter
{
	cout << x << endl;
}
int main()
{
	print(10);
	print();

	return 0;
}

 

 

 

매개변수가 여러 개일 때도 가능.

void print(int x = 1, int y = 2, int z = 3) //가능

void print(int x, int y = 2, int z = 3) //가능

void print(int x, int y =2, int z) //불가능

 

#include <iostream>
using namespace std;

void print(int x = 10, int y = 20, int z = 30)
{
	cout << x << " " << y << " " << z << endl;
}
int main()
{
	print();
	print(100); //x
	print(100, 200); //x y
	print(100, 200, 300); //x y z
	return 0;
}

 

만약 함수의 정의가 헤더 파일에 되어 있을 경우, 기본값 적용은 둘 중에 하나만 해줘야 함.

(정의에 디폴트가 있으면, 몸체에는 디폴트를 빼줘야 함)

 

#include <iostream>
#include <string>
using namespace std;

void print(string str) {}
void print(char ch = ' ') {}
int main()
{
	print(); //ch 파라미터 함수가 사용됨
	return 0;
}

void print(int x) {}

void print(int x, int y = 10) {}

일 경우, 매개변수의 개수로도 함수 구분이 모호해진다.

 

 

7.9 함수 포인터

 

 

#include <iostream>
#include <string>
using namespace std;

int func()
{
	return 5;
}
int main()
{
	cout << func << endl; //함수도 일종의 포인터이다.
	return 0;
}

 

#include <iostream>
#include <string>
using namespace std;

int func()
{
	return 5;
}

int goo()
{
	return 10;
}
int main()
{
	int (*fcnptr)() = func; //함수 포인터
	//func()는 함수를 실행시켜 그 결과를 가져온다는 뜻.
	cout << fcnptr() << endl; //func가 실행됨
	fcnptr = goo;
	cout << fcnptr() << endl; //goo가 실행됨
	return 0;
}

 

#include <iostream>
#include <string>
using namespace std;

int func(int x)
{
	return 5;
}

int main()
{
	int (*fcnptr)(int) = func;
	return 0;
}

 

위와 같이 return 형과 매개변수 형도 정확히 맞춰줘야 한다.

 

#include <iostream>
#include <array>
using namespace std;

void printNumbers(const array<int, 10>& my_array, bool print_even)
{
	for (auto element : my_array)
	{
		if (print_even && element % 2 == 0) cout << element;
		if (!print_even && element % 2 == 1) cout << element;
	}
	cout << endl;
}

int main()
{
	array<int, 10> my_array{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	printNumbers(my_array, true);
	printNumbers(my_array, false);
	return 0;
}

 

 

#include <iostream>
#include <array>
using namespace std;

bool isEven(const int& number)
{
	if (number % 2 == 0) return true; 
}

bool isOdd(const int& number)
{
	if (number % 2!= 0) return true;
}

void printNumbers(const array<int, 10>& my_array, bool (check_fcn)(const int&))
{
	for (auto element : my_array)
	{
		if (check_fcn(element) == true) cout << element;
	}
	cout << endl;
}

int main()
{
	array<int, 10> my_array{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	printNumbers(my_array, isEven);
	printNumbers(my_array, isOdd);
	return 0;
}

 

동일하게 작동한다.

 

void printNumbers(const array<int, 10>& my_array, bool (check_fcn)(const int&))

 

여기서 함수에도 = isEven처럼 디폴트 값을 줄 수 있다.

 

typedef bool(*check_fcn_t)(const int &);

를 하면 check_fcn_t가 마치 함수 포인터인 것처럼 작용한다.

 

void printNumbers(const array<int, 10>& my_array, check_fcn_t check_fcn = isEven)

 

using check_fcn_t = bool(*)(const int&);도 typedef와 같은 효과.

 

#include <iostream>
#include <string>
#include <functional>

using namespace std;

int main()
{
	function<bool(const int&)> fcnptr = isEven;
	printNumbers(my_array, fcnptr);
	fcnptr = isOdd;
	printNumbers(my_array, fcnptr);
	return 0;
}

(코드 일부 생략)

위처럼도 사용할 수 있다.

 

 

7.10 스택과 힙 the stack and the heap

 

메모리는 segment라고 불리는 영역으로 나뉜다.

Code : 우리가 작성한 코드부분. 실행시키는 영역.

Data - Initialized data segment : 초기화가 된 전역 변수, 정적 변수

Data - uninitialized data segment : 0으로 초기화된 전역 변수, 정적 변수

 

전역 변수가 먼저 메모리에 자리잡음.

메인 함수가 실행되면 Stack frame에 메인 함수가 들어옴.

 

매개변수와 안에서 선언되는 변수가 저장됨.

 

함수가 끝나면 위에서부터 하나씩 사라진다.

모든 프로그램이 끝나면 메모리를 OS가 거둬감. 속도가 힙보다 좀 더 빠르다.

 

단, 크기가 작다.

= Stack Overflow!!

 

지역 변수는 Stack에 쌓인다.

 

Heap은 사이즈가 큰 대신 메모리가 어디 들어갈지 알 수 없다.

delete로 지우면, 힙의 메모리를 거둬간다.

 

7.11 std::vector를 스택처럼 사용하기

 

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	//int *v = new int [3] {1, 2, 3}; 과 비슷함
	vector<int> v{ 1, 2, 3 };

	//vector에는 size와 capacity가 있다.
	//capacity는 실제 vector가 가지는 메모리, size는 실제 사용되는 용량

	for (auto& e : v)
		cout << e << " ";
	cout << endl;
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	return 0;
}

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	//int *v = new int [3] {1, 2, 3}; 과 비슷함
	vector<int> v{ 1, 2, 3 };

	//vector에는 size와 capacity가 있다.
	//capacity는 실제 vector가 가지는 메모리, size는 실제 사용되는 용량

	for (auto& e : v)
		cout << e << " ";
	cout << endl;
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.resize(2);
	for (auto& e : v)
		cout << e << " ";
	cout << endl;
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	return 0;
}

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	//int *v = new int [3] {1, 2, 3}; 과 비슷함
	vector<int> v{ 1, 2, 3 };

	//vector에는 size와 capacity가 있다.
	//capacity는 실제 vector가 가지는 메모리, size는 실제 사용되는 용량

	v.resize(10);
	for (auto& e : v)	cout << e << " ";
	cout << v.size() << " " << v.capacity() << endl;
	v.resize(2);
	for (auto& e : v)	cout << e << " ";
	cout << v.size() << " " << v.capacity() << endl;
	
	//cout << v.at(2) << endl; //불가
	int* ptr = v.data();
	cout << ptr[2] << endl;

	return 0;
}

즉 resize를 하면 실제로는 갖고 있어도, 없는 척 하는 것.

작은 쪽으로 resize할 때 메모리를 반납하는 것이 아니라 속도를 높이기 위해 접근을 막아 버린다.

 

옛날에는

for(unsigned int i=0; i<v.size() ; ++i) cout<<v[i] << " ";

로 프린트 했었다.

 

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	//int *v = new int [3] {1, 2, 3}; 과 비슷함
	vector<int> v{ 1, 2, 3 };
	for (auto& e : v)	cout << e << " ";
	cout << v.size() << " " << v.capacity() << endl;


	v.reserve(100);

	for (auto& e : v)	cout << e << " ";
	cout << v.size() << " " << v.capacity() << endl;
	
	//cout << v.at(2) << endl; //불가
	int* ptr = v.data();
	cout << ptr[2] << endl;

	return 0;
}

 

이렇게 해두면 메모리를 새로 교체하는 작업을 하지 않는다(reserve)

= 속도가 빨라진다.

 

#include <iostream>
#include <vector>

using namespace std;
void printStack(const vector<int>& v)
{
	for (auto& e : v)
		cout << e << " ";
	cout << endl;
}
int main()
{
	vector<int> stack;
	stack.reserve(1024); //속도가 빨라짐

	stack.push_back(3);
	printStack(stack);
	stack.push_back(5);
	printStack(stack);
	stack.push_back(7);
	printStack(stack);
	stack.pop_back();
	printStack(stack);
	stack.pop_back();
	printStack(stack);
	stack.pop_back();
	printStack(stack);
	return 0;
}

vector를 stack처럼 사용할 수 있다.

 

 

7.12 재귀적 함수 호출 recursive function call

 

 

#include <iostream>
using namespace std;

void countDown(int count)
{
	cout << count << endl;
	if (count == 0) return;
	countDown(count - 1);
}
int main()
{
	countDown(10);
	return 0;
}

recursion을 사용할 때는 종료 조건이 있어야 한다.

너무 많이 recursion을 하면 스택 오버플로우가 날 수 있다.

 

#include <iostream>
using namespace std;

int sumTo(int sumto)
{
	if (sumto <= 0) return 0;
	else if (sumto <= 1)
		return 1;
	else return sumTo(sumto - 1) + sumto;
}
int main()
{
	cout << sumTo(10) << endl;
	return 0;
}

 

7.13 방어적 프로그램Defensive Programming의 개념

 

syntax error = 문법 오류

semantic error = 의미 오류.

 

violated assumption = 잘못된 접근을 막는 것.

 

 

7.14 단언하기 assert

 

#include <iostream>
#include <cassert>
using namespace std;

int main()
{
	assert(false);
	return 0;
}

 

assert는 release 모드에선 작동하지 않는다.

속성 > C/C++ > Preprocessor > Preprocessor Definitions > "NDEBUG" 가 있다면 작동하지 않음.

#include <iostream>
#include <cassert>
using namespace std;

int main()
{
	int number = 5;
	//...
	assert(number == 5);
	//단순히 주석만 달아놓는다면, 넘어가기 쉽다.
	return 0;
}

 

#include <iostream>
#include <cassert>
#include <array>
using namespace std;

void printValue(const array<int, 5>& my_array, const int& ix)
{
	assert(ix >= 0);
	assert(ix <= my_array.size() - 1);
	cout << my_array[ix] << endl;
}
int main()
{
	array<int, 5> my_array{ 1, 2, 3, 4, 5 };
	printValue(my_array, 100);
	return 0;
}

 

어디서 오류가 났는지를 수월하게 알 수 있다.

사용자가 지정된 범위 외의 행동을 하려고 하면 런타임에 오류를 알려줌.

 

 

#include <iostream>
#include <cassert>
#include <array>
using namespace std;

int main()
{
	const int x = 5;
	static_assert(x == 5, " x should be 5 " ); 
	return 0;
}

static_assert는 컴파일 타임에서의 오류를 체크한다.

런타임에서 바뀔 수 있는 부분에 대해선 체크할 수 없다.

또한 사용자 지정 로그를 남길 수 있다.

 

 

7.15 명령줄 인수 command line arguments

 

 

#include <iostream>
using namespace std;

int main(int argc, char *argv[]) //매개변수 개수, 실매개변수들
{
	for(int count = 0; count < argc; ++count)
	{
		cout << argv[count] << endl;
	}
	return 0;
}

 

 

 

#include <iostream>
#include <string>
using namespace std;

int main(int argc, char *argv[]) //매개변수 개수, 실매개변수들
{
	for(int count = 0; count < argc; ++count)
	{
		string argv_single = argv[count];
		if (count == 1)
		{
			int input_number = stoi(argv_single);
			cout << input_number + 1 << endl;
		}
		else
			cout << argv_single << endl;
	}
	return 0;
}

 

7.16 생략 부호 Ellipsis 

 

#include <iostream>
#include <cstdarg> //for ellipsis
using namespace std;

double findAverage(int count, ...) //count는 들어갈 매개변수 개수
{
	double sum = 0;
	va_list list;
	va_start(list, count);
	for (int arg = 0; arg < count; ++arg)
		sum += va_arg(list, int); //요소를 int로 변환
	va_end(list);
	return sum / count;
}

int main(int argc, char *argv[]) //매개변수 개수, 실매개변수들
{
	cout << findAverage(1, 1, 2, 3, "Hello", 'c') << endl;
	//count = 1 개를 초과하면 무시됨
	cout << findAverage(3, 1, 2, 3) << endl;
	cout << findAverage(10, 1, 2, 3, 4, 5) << endl;//오류
	return 0;
}