| AcceleratedC++/Chapter9 | AcceleratedC++/Chapter11 |
| 포인터(pointer) | 주소를 나타내는 값 |
| 주소 연산자(address operator) | 객체의 주소를 리턴한다. |
| 역참조 연산자(dereference operator) | 포인터 p가 가리키는 객체를 리턴한다. |
~cpp int *p; // *p는 int 타입을 갖는다. int* p; // p는 int*라는 것을 강조하는 표현이다. C컴파일러는 * 주변의 공백을 무시하기 때문에 상기의 2개 표현은 완전히 동일하다.
~cpp int* p, q; // p는 int* 인 포인터 형식, q는 int 형을 가리킨다.
~cpp
//pointer_example.cpp
#include <iostream>
using std::cout;
using std::endl;
int main()
{
int x = 5;
// `p' points to `x'
int* p = &x;
cout << "x = " << x << endl;
// change the value of `x' through `p'
*p = 6;
cout << "x = " << x << endl;
return 0;
}
~cpp
int (*fp)(int);
int next(int n)
{
return n+1;
}
fp = &next;
fp = next; // 상기의 2가지 표현 모두 next함수의 포인터를 fp에 대입하는 것이 가능하다.
int i = 0;
int n =1;
i = (*fp)(i);
i = fp(i); // 마찬가지로 이 2개의 표현모두 유효한 표현이된다.
6.2.2절에 존재하는 write_ayalysis의 선언구문을 살펴보도록 하자.~cpp
void write_analysis(std::ostream& out, const std::string& name,
double analysis(const std::vector<Student_info>&),
const std::vector<Student_info>& did,
const std::vector<Student_info>& didnt);
상기에서 3번째 매개변수를 살펴보도록 하자. ~cpp double analysis(const std::vector<Student_info>&)
~cpp double (*analysis)(const std::vector<Student_info>&)따라서 우리가 일반적으로 사용하는 함수의 표현만으로도 매개변수로 함수를 전달시키는 것이 가능한 것이다.
~cpp //올바른 표현 typedef double (*analysis_fp)(const vector<Student_info>&); analysis_fp get_analysis_ptr(); // 이와 같이 이용하는 것이 가능합니다. //올바르지 않은 표현 double (*get_analysis_ptr()) (const vector<Student_info>&);상기의 코드에서 프로그래머가 원한 기능은 get_analysis_ptr()을 호출하면 그 결과를 역참조하여서 const vector<Student_info>&를 인자로 갖고 double 형을 리턴하는 함수를 얻는 것입니다.
~cpp
template<class In, class Pred>
In find_if(In begin, In end, Pred f) {
while (begin != end && if f(*begin)) //여기서 Pred는 Pred(*begin)이 의미를 갖는 모든 타입이 가용합니다.
++begin;
return begin;
}
bool is_negative(int n) {
return n<0;
}
vector<int>::iterator i = find_if(v.begin(), v.end(), is_negative); // &is_negative 를 사용하지 않는 이유는 자동형변환으로 포인터형으로 변환되기 때문임.
~cpp const size_t NDim = 3; const size_t PTriangle = 3; double coords[NDim]; double coords1[PTriangle];상기와 같은 표현은 const로 지정된 변수로 변수를 초기화하기 때문에 컴파일시에 그 크기를 알 수 있다. 또한 상기와 같은 방식으로 코딩을 하면 coord에 의미를 부여할 수 잇기 때문에 장점이 존재한다.
~cpp *coord = 1.5; //coord 배열의 첫번째 요소를 1.5로 할당한다. 즉, coord[1] = 1.5; 와 동일한 표현이 된다.
| coord+1 | 1번째 요소 |
| coord+2 | 2번째 요소 |
| coord+3 | 3번째 요소. 배열에서는 유효하지 않지만 포인터 그 자체로는 유효한 포인터이다. |
| coord+4 | 유효하지 않은 포인터 |
| coord-1 | -1번째 요소. 배열에서는 유효하지 않지만 포인터 그 자체로는 유효한 포인터이다. |
~cpp vector<double> v; copy(coords, coords + NDim, back_inserter(v));coord+NDim 은 coord의 마지막 요소에서 1개가 더 지난 값을 가리키므로 상기의 표현은 유효한 표현식이다.
~cpp
const int month_length[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
}; // 윤년은 무시
상기의 예제에서 month_length의 배열의 크기를 명시적으로 나타내지 않았다는 사실에 유의. 대신에 컴파일러가 초기화된 갯수에 맞추어서 배열을 할당한다.~cpp
const char hello[] = { 'h', 'e', 'l', 'l', 'o', '\0' }; //이 표현은 const char hello[] = "hello";와 동일한 표현이다.
<cstring> strlen~cpp
size_t strlen(const char* p) { // 쉬우니 기타 설명은 생략
size_t size = 0;
while (*p++ != '\0')
++size;
return size;
}
상기의 내용을 바탕으로 string에서 우리는 다음과 같은 초기화를 행하는 것이 가능하다. ~cpp
string s(hello);
string s("hello");
string s(hello, hello+strlen(hello));
상기의 3가지 표현은 모두 같다.~cpp
//letter_grade.cpp
#include <cstddef>
#include <string>
using std::string;
string letter_grade(double grade)
{
// range posts for numeric grades
static const double numbers[] = {
97, 94, 90, 87, 84, 80, 77, 74, 70, 60, 0
};
// names for the letter grades
static const char* const letters[] = {
"A+", "A", "A-", "B+", "B", "B-", "C+", "C", "C-", "D", "F"
};
// compute the number of grades given the size of the array
// and the size of a single element
static const size_t ngrades = sizeof(numbers)/sizeof(*numbers);
// given a numeric grade, find and return the associated letter grade
for (size_t i = 0; i < ngrades; ++i) {
if (grade >= numbers[i])
return letters[i];
}
return "?\?\?";
}
~cpp
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char** argv)
{
// if there are command-line arguments, write them
if (argc > 1) {
cout << argv[1]; // write the first argument
// write each remaining argument with a space before it
for (int i = 2; i != argc; ++i)
cout << " " << argv[i]; // `argv[i]' is a `char*'
}
cout << endl;
return 0;
}
char**는 (char*)를 요소로 갖는 배열이라고 생각하면 된다. 즉 문자열 리터럴을 요소로 갖는 배열이다.| cerr | 버퍼링을 사용하지 않고, 즉각적인 출력을 한다. 오버헤드가 크다. |
| clog | 버퍼링을 이용하고, 적당한 시기에 출력한다. |
~cpp
//copy_file.cpp
#include <fstream>
#include <string>
using std::endl;
using std::getline;
using std::ifstream;
using std::ofstream;
using std::string;
int main()
{
ifstream infile("in");
ofstream outfile("out");
string s;
while (getline(infile, s))
outfile << s << endl;
return 0;
}
만약 파일의 이름으로 string 형을 이용하고 싶다면 string형의 멤버함수인 c_str() 을 이용해서 사용하는 것이 가능하다.~cpp
string file("out");
ifstream infile(file.c_str());
~cpp
//concat_files.cpp
#include <iostream>
#include <fstream>
#include <string>
using std::cerr;
using std::cout;
using std::endl;
using std::getline;
using std::ifstream;
using std::string;
int main(int argc, char **argv)
{
int fail_count = 0;
// for each file in the input list
for (int i = 1; i < argc; ++i) {
ifstream in(argv[i]);
// if it exists, write its contents, otherwise generate an error message
if (in) {
string s;
while (getline(in, s))
cout << s << endl;
} else {
cerr << "cannot open file " << argv[i] << endl;
++fail_count;
}
}
return fail_count;
}
단순한 프로그램이므로 설명은 생략함. 한번 쳐보자.~cpp
int* invalid_pointer() {
int x;
return &x; //함수의 종료와 함께 x가 해제되므로 리턴되는 값은 무효한 메모리상의 공간을 가리킨다.
}
~cpp
int* pointer_to_static() {
static int x;
return &x; //유효하다. static 으로 함수 안에서 선언하면 함수가 처음 실행될때 메모리 공간이 한번 할당되고 그 함
수가 종료되더라도 해제되지 않고 프로그램이 종료될때 해제된다. 따라서 메모리가 해제되지 않은 static 변수를 리턴하는 것이기에 유효하다.
}
| 자동메모리 관리 | 지역변수, 지역변수를 참조형, 포인터형으로 리턴하면 그 리턴값은 무효한 값이된다. 사용하고 싶다면 static 키워드를 이용해야한다. |
| 정적메모리 할당 | 정적 변수가 존재하는 블록이 처음 실행되는 동안 할당되어 프로그램이 실행되는 동안 계속 유효한 상태로 남는다. |
| 동적메모리 할당 | new, delete 키워드를 이용해서 프로그래머가 원하는 시기에 메모리상에 할당하고 해제를 할 수 있다. |
~cpp new T(args)와 같은 표현을 이용하면 된다.
~cpp new T[n]와 같은 표현을 이용하면 된다.
~cpp
char* duplicate_chars(const char* p) {
size_t length = strlen(p) + 1;
char* result = new char[length];
copy(p, p+length, result);
return result;
간단한 소스이므로 설명생략