C언어

c++ 공부 요점 정리 3

뮹실이 2013. 11. 13. 21:25






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// =====================================================
// 8 레퍼런스의 이해
// =====================================================
// 레퍼런스와 변수는 
// 생성되는 방법에 있어서만 차이를 보일 뿐
// 만들어지고 나면 완전히 같은 것

// 레퍼런스의 제약
// 1 이름이 존재하지 않는 대상을 레퍼런스 할 수 없다
int &ref2 = 10; // 상수가 올수 없으므로 에러
// 2 선언과 동시에 반드시 초기화 되어야 한다.
int &ref1; // 초기화 되지 않았으므로 에러


// =====================================================
// 9 레퍼런스 함수
// =====================================================
// 포인터를 이용한 call-by-reference
// : 함수 외부에 선언된 변수의 접근이 가능
// 포인터 연산에 의해서 가능한 것임
// 포인터 연산의 위험성 존재
// ex
void swap(int *a, int *b)
{
	int temp = *a;
	a++; // 실수로 입력하게 되면 치명적 오류 발생가능
		// 4바이트가 증가되어 원래 a가 가리키던 메모리
		//에서 4바이트를 건너뛰게 되어 어딘지 모르는
		// 곳의 메모리 값을 참조하게 되어 위험
	*a = *b;
	*b = temp;
}

// 레퍼런스를 이용한 call-by-reference
// : 함수 외부에 선언된 변수의 접근이 가능
// 포인터 연산을 할 필요가 없으므로 보다 안정적임
// 함수의 호출형태를 구분하기 어렵다.
// ex
int main(void)
{
	int val1 = 10;
	int val2 = 20;
	
	swap(val1, val2); // 이것만 봐서는 call-by-value인지
					// call-by-reference인지 알수없다
					// swap함수의 매개변수를 확인해봐야
					// 알수 있다.
	return 0;
}

void swap(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
// 위 예제는 포인터를 사용하지 않는다.
// 포인터를 사용할 때는 오류를 발생시킬 위험성이 높음
// 따라서 레퍼런스를 이용해 구현하면 보다 안정적임

// call-by-value
// : 함수 호출 시 인자 전달 과정에서 발생
// 데이터를 복사하는 과정에서 발생
// ex
void main(void)
{
	showdata(man);
}
void showdata(person p)
{
// ...
}

// 대신할 수 있는 call-by-reference
// : 전달되는 인자를 레퍼런스로 받으면, 데이터의
// 복사 연산이 필요없다.
// 원본 데이터가 변경될수 있으므로, 
// const로 선언하면 원본 변경 방지 가
// ex
void showdata(const person &p)
{
// ...
}


// =====================================================
// 10 레퍼런스를 리턴하는 함수
// =====================================================
//
// ex
//
#include <iostream>
using std::cout;
using std::endl;

// 레퍼런스 타입으로 리턴
int& increment(int &val)
{
	val++; // 지역변수 val
	return val;
}// 이 함수 호출이 끝나면 val변수는 사라짐

int main(void)
{
	int n=10;
	int &ref=increment(n);
	// increment가 인수로 리턴하면 상수로 리턴하므로
	// 에러 발생
	// 레퍼런스는 상수에 이름을 붙일 수 없으므로.

	cout<<"n  : "<<n<<endl;
	cout<<"ref: "<<ref<<endl;

	return 0;
}

//
// ex 2
//
#include <iostream>
using std::cout;
using std::endl;

int& function()
{
	int val=10;
	return val;
}

int main(void)
{
	int &ref=function();
	cout<<ref<<endl; // 에러 발생가능
					// 권장하지 않음
					// 지역변수로 선언된 변수를 
					// 리턴하므로..........??

	return 0;
}

// new와 delete 연산자의 기능
//
// c에서는
//
// int 형 변수를 힙에다가 할당해주고
// 그 포인터를 리턴받는 형태
// malloc은 인자로 전달되는 인자의 크기만을
// 할당하고 
// 어떤식으로 사용될지 모르니 void 포인터 타입으로 
// 반환된다.
// 따라서 크기를 직접 계산해서 인자로 주고
// 리턴되는 포인터도 용도에 맞게 형변환해서
// 사용해야함
// 할당한 메모리 공간을 해제할때는 free함수 사용
int *val = (int *)malloc(sizeof(int));
free(val);
// 배열 동적할당
// 
int *arr = (int *)malloc(sizeof(int)* size);
free(arr);
//
// c++에서는
//
// new와 delete가 자동으로 할당해줌
// 인자에 크기계산과 포인터 형변환을 해줄 필요없음
// 힙에다가 int형 데이터 저장하기 위한 메모리공간 할당하라
// 4바이트 메모리 공간을 힙에다가 할당하고 
// 알아서 인트형 포인터로 반환해줌
// 할당한 메모리 공간을 해제할때는 
// 할당한 메모리 공간이 int인 경우에는 
// delete 사용하고
// 할당한 메모리 공간이 배열인 경우에는
// delete에 인덱스연산자를 붙여 arr이 가리키는 공간이
// 배열임을 명시적으로 선언해줘야함
int *val = new int;
delete val;
// 배열 동적할당
// 길이가 size인 인트형 배열을 힙에다가 할당하라
// 리턴될때 자동으로 인트형 포인터로 리턴됨
int *arr = new int[size];
delete []arr;

// 메모리 공간 할당에 실패할 경우
// NULL 포인터를 리턴한다.
// ex
int *arr = new int[size];
if (arr == NULL)
{
	cout<<"에러"<<endl;
	return -1;
}
// 이런식의 메모리 할당 실패 검사는 비효율적이므로
// 다음과 같은 방식으로 사용 추천
#include <iostream>

//#define DEBUG 1;
#define DEBUG  0;

using std::cin;
using std::cout;
using std::endl;

int main(void)
{
	int size;
	cout<<"할당하고자 하는 배열의 크기: ";
	cin>>size;

	int* arr=new int[size];  // 배열의 동적 할당.

#if DEBUG==1 
	cout<<"디버그 모드 입니다"<<endl;
	if(arr==NULL)
	{
		cout<<"메모리 할당 실패"<<endl;
		return -1; //프로그램 종료.
	}
#endif

	for(int i=0; i<size; i++)
		arr[i]=i+10;

	for(int j=0; j<size; j++)
		cout<<"arr["<<j<<"]= "<<arr[j]<<endl;

    delete []arr;  // 할당된 메모리 소멸.

	return 0;
}