본문 바로가기
2CHAECHAE 학교생활/객체지향프로그래밍(C++)

[ 객체지향프로그래밍(C++) 4주차 ② ]

by 2CHAE._.EUN 2022. 3. 28.

[ 4주차 - 2 ]

 

함수

 

전역변수와 지역변수의 이름이 같을 때는 지역변수에 우선순위가 있음

 

 

포인터와 함께 함수 호출

 

1. 포인터와 함께 함수 호출

→ 함수의 매개변수를 포인터 형으로 선언

→ 포인터를 사용하는 함수 내의 연산을 수행할 때, 그 포인터가 가리키는 변수에서 작동

 

 2. 배열과 함께 함수 호출

→ 함수의 매개변수를 배열 또는 포인터로 선언한다.

→ 함수 호출시에 배열에 대한 오직 하나의 포인터만이 전달된다.

→ c++는 배열의 경계를 확인하지 않으므로 배열의 실제 크기는 중요하지 않다.

 

3. 문자열 전달

→ 문자열이 함수에 전달될 때, 그 문자열의 시작에 대한 포인터가 실제 전달된다.

 

#include <iostream>
using namespace std;

void f(int *j);

int main() {

	int i;
	int *p;
	p = &i; // p는 i를 가리키는 포인터 변수

	f(p); // f(&i)와 같은 기능이다. -> i의 주소가 전달됨

	cout << i;

	return 0;

}

void f(int *j) { // 포인터 변수를 받는 매개변수도 포인터 변수로 선언을 해줘야함
	*j = 100;
}


// ▶ 100

 

함수를 호출할 때 포인터 변수를 파라미터로 넘겨준다면 대응하는 함수의 매개변수는 반드시 포인터 변수로 선언을

해주고, 호출할 때 파라미터로 들어온 포인터 변수의 주소를 받아서 * 연산자를 사용해 그 주소에 해당하는 값에 

넣어줄 수 있다.

 

 

배열과 함께 함수 호출하기
#include <iostream>
using namespace std;

void display(int num[10]);

int main() {

	int t[10];

	for (int i = 0; i < 10; ++i) {
		t[i] = i;
	}

	display(t);

	return 0;

}

void display(int num[10]) { // int num[10] == int num[] == int *num
	
	for (int i = 0; i < 10; i++) {
		cout << num[i] << " ";
	}
    
}

// ▶ 0 1 2 3 4 5 6 7 8 9

 

display 함수의 파라미터인 num 배열은 인수로 넣은 배열 t를 공유한다. 즉 t의 주소를 그대로 받게 된다.

→ t의 시작주소가 num에 들어가게 된다.

 

* 배열을 파라미터로 받을 때는 빈 대괄호( [] )로 줌으로써 배열을 명시하는게 좋다. 포인터 변수를 넣을 경우

배열이 들어오는지 무슨 변수가 들어오는지 알 수 가 없다.

 

 

문자열 전달하기
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;

void stringupper(char *str);

int main() {

	char str[80];
	strcpy_s(str, "this is a text");

	stringupper(str); // str 배열의 주소가 전달이 된다.

	cout << str;

	return 0;
}

void stringupper(char *str) { // char *str == char str[]

	while (*str) {
		*str = toupper(*str);
		str++; // 다음 문자로 이동
	}
}

// ▶ THIS IS A TEXT

 

문자열도 char 형 배열이기 때문에 함수의 파라미터로 포인터 변수나 배열을 전달하는 것은 똑같다.

 

 

main() 함수의 매개변수 : argc, argv

 

명령어 라인 인수 ( command line argument ) : 프로그램이 실행할 때의 정보 전달

→ 명령어 라인에서 프로그램의 이름 뒤에 오는 정보를 메인 함수의 매개변수가 받는다.

* 명령어 라인 인수는 빈칸 또는 탭에 의해 구분

 

1. argc : 명령어 라인에 있는 인수들의 수를 저장 ( 프로그램의 이름도 하나의 인수로 취급 )

 

2. argv : 문자형 포인터 배열에 대한 포인터

argv[0]은 프로그램의 이름

argv[1]은 첫번째 인수

argv[2]는 두번째 인수

* argv는 여러개 문자열을 나타내는 배열이 되어야 하므로 포인터이다.

또한 2차원 배열로 한 행에는 인수로 들어오는 하나의 문자열을 나타내고, 차례차례 인수로 들어오는 문자열을

저장하고 나타낸다.

 

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

int main(int argc, char *argv[]) {
	
	double a, b;

	if (argc != 3) { //비정상적인 경우
		cout << "Usage : add num num\n";
		return 1;
	}

	a = atof(argv[1]);
	b = atof(argv[2]);

	cout << a + b;
	return 0;
}

 

num에게 값을 전달해주는 것은 운영체제이다. argc에는 명령어 라인에 있는 인수들의 수를 전달하므로

argc는 3이 전달이 된다. argv[0]에는 add 라는 문자열이 들어가고, argv[1]에는 100.2, argv[2]에는 231라는

문자열이 전달된다. 명령어 라인에 입력될 때는 모두 문자열 취급한다.

 

* atof()는 문자열을 실수형( float )으로 변환해주는 시스템 함수이다. 

  atoi()는 문자열을 정수형( int )으로 변환해주는 시스템 함수이다.

 

 

* visual studio에서 명령어 인수 넣기

[ 프로젝트 메뉴 ] → [ 프로젝트이름의 속성 ] → [ 구성 속성 - 디버깅 ]

명령인수로 aaa bbb ccc 총 3개가 있지만 4개가 있다고 인식이 되어 argc에는 4가 전달이 된다. 

→ 실행 파일 프로그램의 파일 이름은 명령 인수에 주지 않는다.  

 

 

return 문

 

return문의 기능으로는 함수의 호출 부분으로 즉각 되돌아가게 한다.

하나의 값을 반환하기 위해 사용될 수 있지만 함수가 void로 선언됐을 경우는 값을 반환할 수 없다.

 

* void 함수는 값을 반환하지 않음 → 함수를 식에 사용하는 것을 방지한다.

 

#include <iostream>
using namespace std;

int find_substr(char *sub, char *str);
// sub가 str의 어디 위치에 포함되어 있는지 index를 나타내줌

int main() {

	int index;
	index = find_substr("three", "one two three four");
	cout << "index of three is " << index;
	return 0;
}

int find_substr(char *sub, char *str) {

	char *p, *p2;

	for (int t = 0; str[t]; t++) { //긴 문자열이 끝날 때까지 반복
		p = &str[t]; // 포인터를 다시 설정
		p2 = sub;

		/*p2와 p가 같은 글자를 가리키고 있는 동안 반복*/
		while (*p2 && *p2 == *p) { //부분 문자열을 확인
			p++;
			p2++;
		}

		/* p2의 끝에 도달했다면 일치하는 것을 찾은 것*/
		if (!*p2) return t;  //일치하는 곳의 첨자를 반환

	}

	return -1; //일치하는 것이 없을 때
}

// ▶ index of three is 8

 

 

* const char * 형식의 인수가 char * 형식의 매개 변수와 호환되지 않습니다 오류 구문

→ 대입 하려는 문자열이 문자열 상수이기 때문에 대입하고자 하는 값에 const를 붙여줘야한다.

// 변경 전
char *name = "2chaechae"

// 변경 후
const char *name = "2chaechae"

에러가 생기는 이유는 기존 visual studio 표준을 무시하고 컴파일을 시도했기 때문

→ visual studio 17 기준으로 준수모드가 표준적으로 '예'로 설정되어 있어서 '아니오'로 변경해줘야함

 

실습 문제

 

find_substr 함수를 사용해서 문자열에서 일치하는 부분 문자열의 수를 출력하기

 

입력 문자열 = "aabababacabaabca"

패턴 = "aba"

 

#include <iostream>
using namespace std;

int find_substr(char *string,  char *pattern);

int main() {

	int index;
	index = find_substr("aabababacabaabca", "aba");
	cout << "문자열 수 출력하기 : " << index;
	
	return 0;

}

int find_substr(char *string, char *pattern) {

	int count = 0;
	char* p, * p2;

	for (int i = 0; string[i]; i++) { //문자열이 끝날 때 까지 반복
		p = &string[i]; //포인터를 다시 설정
		p2 = pattern; 

		//p2와 p가 같은 글자를 가리키고 있는 동안 반복
		while (*p2 && *p2 == *p) { //부분 문자열을 확인
			p++;
			p2++;
		}
		if (!*p2) { //p2의 끝에 도달했다면 일치하는 것을 찾은 것
			count++;
		}

	}
	return count;
}