구조체, 레퍼런스, 함수 인자전달

yu-podong·2021년 3월 23일
2

CPP

목록 보기
3/9
post-thumbnail

구조체(Structure)


구조체 정의

어떤 대상을 표현하는 서로 연관된 변수들을 하나의 새로운 data type으로 정의한 것
=> 사용자가 직접 정의하는 data type

#include <iostream>
using namespace std;

struct StudnetInfo {
	char name[20];	//이름
   	int stdNumber; //학번
    float grade[2] //최근 2학기 평점
}

int main() {
	StudentInfo stuInfo = {"yu-podong", 2019001001, {4.43f, 4.28f}};
    cout << stuInfo.name;		//yu-podon
    cout << stuInfo.stdNumber;	//2019001001
    cout << stuInfo.grade[0];	//4.43
	return 0;
}

구조체 배열

구조체 배열은 일반적인 배열 선언 방식과 똑같다.

// 위의 구조체를 그대로 사용한다.
StudentInfo  stuInfo[2] = {
	{"yu-podong", 2019001001, {4.43f, 4.28f}},	//studentInfo[0]
   	{"Capricorn", 2019001002, {1.2f, 3.4f}}		//studentInfo[1]
};

구조체 포인터 & 포인터 배열

구조체 포인터 : 일반 포인터 변수와 유사하게 정의

struct Rectangle {
	int x,y;
    int width, height;
};
Rectangle rec = {100,100,50,50}
Rectangle *pRec = &rec;

(*p).x = 200;	//p->x = 200
p->y = 250;		//(*p).y = 250

구조체 포인터 배열 : 일반 포인터 배열과 유사하게 정의

//위의 Rectangle 구조체 그대로 사용
Rectangle rec[2] = {
	{100,100,50,50},
   	{200,200,100,100}
}
//구조체 포인터 배열
Rectnagle *pRec[2] = {&rec[0], &rec[1]};
//
(*(*(pRec+1))).x = 300;	
//(*(*(&pRec[1]))).x == (*(pRec[1])).x == (*(&rec[1])).x == rec[1].x
(*pRec[1]).y = 250;
//*(&rec[1]).y == rec[1].y
p[1]->width = 200;

Q. 포인터배열 pRec를 사용하여 Rec배열의 2번째 원소값을 찍으려면 어떻게 해야할까?
A. cout << pRec[1] ->x ...

중첩 구조체(Nested Structure)

어떤 구조체가 다른 구조체 형의 멤버를 가지는 것이다.

struct date {
	int year;
    int month;
}
struct student {
	char name[10];
    float GPA;
    date birthday;
}

student s1 = {"yu-podong", 4.41, 2021,1,1};
cout << s1.birthday.year; 	//2021

Q. student *s2를 사용하여 s1의 변수값을 변경시키려면 어떻게 해야할까?
A. s2 = &s1; -> s2->GPA = 3.3; ...

자기 참조 구조체

어떤 구조체의 멤버변수 중 하나가 자기 자신의 구조체 포인터 변수를 갖는 것이다.
ex. Linked list : 다음 node를 가리킬 때 사용

struct Node {
	int number;
    Node* next;
    //어떤 타입의 변수 주소를 가리킬 지만 알려주는 것이므로 errorX
}

struct Node {
	int number;
    Node next;
    //자신의 구조체 선언이 끝나지 않아 Node type이 만들어지지도 않았는데
    //자신의 구조체 변수를 생성한다는 것은 error 발생
}

레퍼런스


레퍼런스 선언 및 사용

레퍼런스 : &를 사용하여 이미 존재하는 변수에 대한 다른 이름을 선언하는 것
              => 해당 변수에 대한 별명 설정

  • 참조 변수에 대한 새로운 공간을 할당하지 않는다. 즉, 레퍼런스 변수에 대한 공간 할당X
  • 초기화로 지정된 기존 변수 공유한다.
int target = 20;
int &ref = target;	//target에 대한 레퍼런스 변수
ref = 20; 		//target = 20

cout << ref << target;		//ref == target == 20
cout << &ref << &target;	//&ref == &target

레퍼런스 변수는 포인터 변수와는 달리 가리키는 대상을 바꿀 수 없다!

레퍼런스 변수가 가장 많이 활용되는 사례

Call by reference

함수의 매개 변수(reference parameter)를 레퍼런스 type으로 선언하고, 해당 매개 변수를 '참조 매개 변수'라고 한다.
변수에 해당하는 공간은 생기지 않고 해당 매개 변수는 실인자 변수 공간을 공유한다.
그리고 해당 매개 변수의 조작은 실인자 변수 조작 효과와 동일하다.

int add_3(int &result) {
	result += 3;
}

int main() {
	int x= 10;
    add_3(x);
}

함수의 인자전달


함수의 인자 전달 방법

1. Call by value
   실인자의 값만 넘겨주는 방법이다.
    -> 함수 안에서 매개 변수의 값을 변경해도 실인자에는 영향이 없다.
        즉, 인자를 함수 안에서 사용만 하고 변경하지 않을 경우에 사용한다.

2. Call by reference
   실인자의 주소를 넘겨주는 방법이다.
    -> 함수 안에서 매개 변수의 값을 변경하면 실인자에 영향을 미친다.
        즉, 인자를 함수 안에서 변경해야 할 때 사용한다.

포인터에 의한 함수 인자 전달

void swap(int *a, int *b) {	//포인터에 의한 전달
	int temp = *a;
	*a = *b;
    *b = *a;
}

int num1 =  23, num2 = 30;
swap(&num1, &num2);	//변수의 주소 전달 -> Call by reference

레퍼런스에 의한 함수의 인자 전달

void swap(int &a, int &b) {	//레퍼런스에 의한 전달(메모리 공유)
	int temp = a;
	a = b;
    b = a;
}

int num1 =  23, num2 = 30;
swap(num1, num2);	//변수 전달 -> Call by reference

const 레퍼런스

레퍼런스 변수 선언 시 const 속성을 부여한다면, 레퍼런스가 참조하는 변수의 값을 변경할 수 없다. 즉, 자신이 참조하는 변수에 read-only access만 가능하도록 설정하는 것이다.

int test = 100;
const int &refer = test;

refer = 200; 	//현재 const 레퍼런스이므로 컴파일 error 발생
test = 200;	//해당 변수를 직접 변경하는 것은 가능하다.

📢위의 경우에는 접근 방법에 따라 변경 유무가 결정되는 것이다. 레퍼런스를 통해 변수에 접근하는 경우만 red-only로 설정하는 것이므로, 직접 해당 변수를 이용하여 값을 수정하는 것은 전혀 문제가 없다.

함수의 인자로 사용할 때의 const 레퍼런스

레퍼런스에 의한 함수의 인자 전달 방식과 동일하다. 다만, 매개 변수를 통해 실인자의 값을 변경하지 못한다. 그러므로 실인자의 값을 수정하면 안되는 경우에 사용하면 된다.
주로 '구조체'나 '클래스'를 넘길 때 유용하게 사용된다.

배열, 구조체를 인자로 전달하는 방법

1차원 배열

배열의 시작 주소를 매개변수로 전달한다(= call by reference)

int main() {
	int arr1[3] = {1,2,3};
    usingArr(arr1);
}

void usingArr(int arr[]) {
	arr[1] = 10;
    	//...
}

2차원 배열

1차원 배열과 동일하게 배열의 시작 주소를 전달하지만, 매개 변수에 부분배열의 원소 개수를 작성해야 한다.

int main() {
	int arr2[2][2] = {{1,2},{3,4}};
    usingArr(arr2);
}
void usingArr(int arr[][2]) {
	cout<< arr[0][1];
    	//..
}

구조체

메모리 사용의 효율성을 위해 레퍼런스 변수를 사용하여 인자로 넘겨준다.
만약에 구조체의 데이터를 변경하고 싶지 않다면 const 레퍼런스를 사용하면 된다.

struct Subject {
	char subName[20];
    float score;
}

int main () {
	Subject sub1={"c++", 100.0f}, sub2 = {"java", 90.0f};
    float aveScore = calc(sub1, sub2);
}
float calc(const Subject &sub1, Subject &sub2) {
	return sub1.score + sub2.score;
}

0개의 댓글