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;간단한 소스이므로 설명생략