열혈강의 C++ 언어본색 책을 참고하여 작성한 글입니다.
CHAPTER 4. 고급변수 사용 포인터, 메모리
4.1 포인터 변수
- 포인터는 기억 장소의 주소를 의미한다.
- 이번 장에서는 일반 변수와 포인터 변수의 쓰임새를 정확히 구별할 수 있어야 한다.
- 일반 변수는 자료 자체를 저장하기 위해 사용하고, 포인터 변수는 일반 변수가 실제 메모리에 할당된 주소를 참조하기 위해 사용한다.
변수 및 디버깅 단축키
- 변수는 사용 전 미리 선언 해야한다.
- 변수 선언에서 프로그래머로서의 예의 있는 코딩은 변수 초기화이다.
- 변수 초기화를 잊어버리고 디버깅을 실행하면 아무리 살피고 살펴도 틀린 구석을 찾아내기 쉽지 않다.
- 이때 프로그램 한줄 한줄 디버깅 모드로 실행 상태를 확인하면 초기화를 하지 않은 부분이 보일 것이다.
디버깅 모드에서 기본적으로 사용하는 단축키
단축키 | 설명 |
F5 | 디버깅을 시작 |
Shitf + F5 | 디버깅을 중지 |
F9 | 현재 커서 위치에 중단점을 설정하거나 해제한다. |
F10 | 프로시저 단위로 디버깅을 실행 |
F11 | 한 단계씩 코드로 디버깅을 실행 |
Def . 포인터 변수
- 포인터는 말 그대로 주소이다. 변수가 선언되면 기억장치 어딘가에 임의 공간이 할당된다. 그 할당된 공간은 주소로 식별된다. 바로 그 주소를 포인터라 한다.
주소지정 연산자 (&)의 활용 방법 // 변수의 주소를 확인하는 방법
Cout << “a의 주소 = “ << &a << Endl; |
&를 사용하면 cout시 해당 변수에 할당된 주소를 가져온다
간접지정 연산자 (*)의 활용 방법 // 포인터 변수 선언 방법
자료형 *포인터 변수 이름; |
- 간접지정 연산자를 표시한 것 외에 일반 변수와 외형은 같다. 그리고 포인터 변수도 자료형을 정해야 한다.
- 자료형은 주소에 저장된 값의 자료형에 따라 결정된다. 따라서 주소에 저장된 값의 자료형과 동일하게 포인터 변수의 자료형을 결정해야 한다.
- 간접지정 연산자 (*)는 현재의 값을 메모리 주소로 하여 해당 기억 장소에 한 번 더 접근하게 한다.
- 이는 직접 한 번에 접근한 것이 아닌 *로 지정된 포인터 변수를 거쳐 접근하기 때문에 간접 접근이라 한다.
출력 시 나오는 값들 | 예시 |
일반변수 -> 값 | Cout << a; 결과 : 값 |
&일반변수 -> 주소 | Cout << &a; 결과 : 주소 |
포인터 변수 -> 주소 | Cout << pa;’ 결과 : 주소 |
*포인터 변수 -> 주소 | Cout << *pa; 결과 : pa 주소를 참조하여 저장되어 있는 값을 불러옴 |
4.2 배열
Def . 배열
- 배열은 연속적인 기억 공간을 나타낸다. 변수는 하나의 기억공간을 사용하는 반면 배열은 여러 기억 공간을 사용해 편리하다.
- 배열을 선언할 때는 하나의 이름에 몇 개의 기억 공간이 필요한지 그 개수를 정확히 적어야 한다. ( 변수를 사용해서 갯수를 적을수 없다. 정확한 숫자가 필요함 )
형태
자료형 배열이름[공간개수]; |
- 배열은 선언이 되면 선언된 이름으로 자료형 기억장소 n개를 가지게 되는것이다.
- 이때 각 기억 장소는 대괄호([])안에 숫자로 나타내고 이를 첨자라 한다.
- 배열의 첨자는 0부터 시작한다. 즉 각각의 기억장소 이름은 배열이름[0], 배열이름[1], 배열이름[2] …… 이렇게 선언이 된다.
배열의 주소
- 기본적으로 Window Xp가 32비트 운영체제이므로 작업 기본단위가 4바이트이다. 따라서 배열 변수의 주소 또한 4바이트 단위로 증가한다.
- 배열 변수가 갖는 특징은 하나의 이름으로 여러 개의 기억 장소를 지칭할 수 있어 편리하다는 점이다. 그리고 또한 배열 이름이 주소를 나타내는 점이다. 예를 들어 score[30]이라고 배열을 선언하면 score은 배열의 시작 주소를 나타내는 포인터가 된다.
- 또한 만약 배열 자료형의 기본 크기가 4바이트이면 배열 이름에 +1을 하게 되면 4바이트가 증가하게 되어 배열의 그 다음 요소의 주소를 나타내게 된다.
Cout << 배열이름 << Endl; | 배열의 시작 주소 출력 |
Cout << &배열이름[0] << Endl; | 배열의 시작 주소 출력 |
Cout << *(배열이름+n-1) << Endl; | 배열의 n번째 요소에 저장된 값 출력 |
Cout << 배열이름[n-1] << Endl; | 배열의 n번째 요소에 저장된 값 출력 |
정수형 배열
정수형 배열의 선언 및 초기화 방법
Int score[3] = {80,90,100}; | 첫번째부터 순서대로 80,90,100의 값을 가진다. |
Int score[30] = {100,} | 첫번째는 100이고 나머지 배열의 요소는 0의 값 |
4.3 문자열
Def . 문자열
- 문자열은 문자의 모음이다. 문자열을 사용하는 경우에는 문자들이 연이어 있는 자료에서 각각의 문자들에 대한 작업이 필요할 때 사용하면 편리하다.
- 문자 변수의 자료형은 char이고, 문자 상수는 작은따옴표(‘’)로 표기하며 기억장소 1바이트를 차지한다. 문자열은 문자 상수의 모음으로 표기할 때 큰따옴표 (“”)로 표기한다.
- 문자열의 특징 중 하나는 문자열의 마지막을 나타내는 문자 ‘\0’ (null)문자가 꼭 배열의 마지막에 들어간다. 예를 들어 computer이라는 문자열을 선언하면 배열의 9번째 요소는 null문자이다.
문자열의 선언 및 초기화 방법
Char string[30] = {‘c’, ‘o’, ‘m’, ‘p’, ‘u’, ‘t’, ‘e’, ‘r’ ‘\0’ } | 1~8번째 요소에 문자 9번째 null |
Char string[30] = “computer” | 위와 같다 |
Char string[3] = “computer” | 범위 초과로 인한 오류 발생 |
문자 배열의 활용과 주의점
- 숫자 데이터와 마찬가지로 문자열도 숫자에서의 연산과 같이 요구되는 기능이 있다. 주로 많이 사용되는 것은 문자열 전체 복사나 일부분 복사, 문자열 내에서 특정 문자 찾기 등이 있다.
- 이런 기능들은 표준 라이브러리 iostream에 이미 정의 되어있다.
문자열 관련 함수들
- 여기서 const char* _str[ 아래에서 str이라고 표시 ] 은 y=f(x)값에서 x라고 생각하면 됨
- Char* _Dest [ 아래에서 dest라고 표시할게 ] 는 y=f(x)에서 y값이라고 생각하면 됨
함수 | 설명 |
Countof(str) | 문자열 str의 배열 크기 구하기 Ex) score[30]을 이 함수에 넣으면 30이 출력 |
Strlen(str) // string length |
문자열 str의 길이 구하기 |
Strcpy(dest,str) // string capy |
문자열 str을 dest에 복사! Dest에 있는 내용 지우고 str에 있는 내용 복사 |
Strncpy(dest,str,count) // string n capy |
문자열 str의 내용 count만큼 dest에 복사! Dest에 있는 내용 지우고 str에 있는 내용 n개 복사 |
Strcat(dest,str) // string concatenate |
문자열 str의 내용 dest에 붙이기 Dest에 있는 내용 살리고 그 뒤에 str 내용 붙이기 |
Strncat(dest,str,count) // string n concatenate |
문자열 str의 내용 count만큼 dest에 붙이기 Dest에 있는 내용 살리고 그 뒤에 str 내용 n개 붙이기 |
Int strcmp(str1,str2) // string compare |
문자열 str1과 str2를 비교하여 결괏값을 반환, 결괏값을 -1,0,1중 결정 Str1<str2, str1=str2, str1>str2 이때 문자열 내용을 16진법으로 변환 후 값 비교 |
위에서 노랑색으로 칠해진 함수들은 보안에 취약한 함수이다. 이것들을 사용해 디버깅을 실행하면 경고 창이 나올 것이다.
보안에 취약하지 않은 함수들 ( 그냥 위에 함수에 _s만 붙임 )
함수 | 설명 |
Strcpy_s(dest,size,str) // string capy |
문자열 str을 dest에 복사! Dest에 있는 내용 지우고 str에 있는 내용 복사 이때 복사되는 문자배열의 최대 크기는 size |
Strncpy_s(dest,size.str,count) // string n capy |
문자열 str의 내용 count만큼 dest에 복사! Dest에 있는 내용 지우고 str에 있는 내용 n개 복사 이때 복사되는 문자배열의 최대 크기는 size |
Strcat_s(dest,size,str) // string concatenate |
문자열 str의 내용 dest에 붙이기 Dest에 있는 내용 살리고 그 뒤에 str 내용 붙이기 이때 붙여지는 문자배열의 최대 크기는 size |
Strncat_s(dest,size,str,count) // string n concatenate |
문자열 str의 내용 count만큼 dest에 붙이기 Dest에 있는 내용 살리고 그 뒤에 str 내용 n개 붙이기 이때 붙이지는 문자배열의 최대 크기는 size |
4.4 포인터 : 메모리 주소
포인터 변수는 기억장소의 주소를 기억하기 때문에 주어진 크기는 운영체제에 의해 결정이 된다. 즉 윈도우 테는 32비트를 기본으로 하기 때문에 기억 장소를 나타내는 주소는 모두 4바이트가 할당된다.
포인터 변수는 저장하는 주소의 자료형과 서로 일치해야 한다.
정수형, 문자형, 실수형, 배정도형 포인터의 크기는 4byte이다. 즉 이 자료형들의 포인터를 1증가하면 그 다음 방의 주소가 출력이 된다.
4.5 레퍼런스 변수
Def . 레퍼런스 변수
- 레퍼런스 변수는 이미 선언된 변수를 다른 이름으로 부르는 변수이다.
- 따라서 레퍼런스 변수는 변수 선언에서 반드시 어떤 변수를 다른 이름으로 부르는가를 명시해야 한다.
- 즉 반드시 초기화가 함께 이루어져야 한다.
- 이때 선언 시 주소지정 연산자(&)를 사용한다.
레퍼런스 변수의 선언 및 초기화 방법
자료형 &변수이름 = 변수; |
레퍼런스 변수를 사용하면 포인터 변수와 같이 같은 기억 장소를 다른 이름으로 참조할 수 있는데, 포인터 변수는 간접접근이지만 레퍼런스 변수는 직접 접근을 통해 참조한다.
4.6 동적할당
Def . 정적 & 동적 할당
- 기억 장소를 할당 하는 방법에는 정적할당과 동적할당이 있다.
- 프로그램 실행 전에 필요한 기억 장소를 미리 할당 하는 방법을 정적, 실행 중 필요한 만큼 기억장소를 요청하는 것이 동적할당이다.
동적할당을 이용한 변수 선언 방법
자료형 *포인터변수 = new 자료형[개수] |
Ex ) int *pi = new int[30] |
만약 필요한 변수의 개수가 하나이면 [ ]내용은 생략한다.
동적할당을 이용한 변수 선언 해제 방법
Delete 포인터변수; // 하나의 기억장소 해제 시 |
Delter [] 포인터변수; // 여러 개의 기억장소 해제 시 |
여러 개 해제시 [ ] <- 여기안에 숫자 쓸 필요 X
정적할당과 동적할당의 차이
할당 방법 | 할당 장소 | 기억장소 확보 시기 | 기억장소 해제 시기 | |
정적 할당 | 필요한 자료형 변수 선언 | 스택(stack) 함수 선언후 {} 여기 안에서만 할당 |
변수가 선언된 함수가 호출될 떄 | 변수가 선언된 함수가 실행이 종료될 때 |
동적할당 | New 연산자 사용 | 힙(heap) 함수 상관없이 모든 곳에서 할당 |
동적 할당 코드가 실행될 때 | Delete 명령이 실행될 때 만약 명령이 없으면 프로그램이 종료될 때 |
- 위에 표를 확인하면 동적할당은 delete명령이 없으면 프로그램 내 모든 곳에서 기억장소를 확보하고 있다.
- 그러므로 꼭 사용이 끝나면 delete명령으로 해제를 시켜야 한다. 만약 해제를 안시키면 다른 곳의 변수이름과 겹칠 때 오류가 생긴다.
'언어공부 > C++' 카테고리의 다른 글
[ C++ ] 기초정리 6. 함수 (0) | 2022.07.19 |
---|---|
[ C++ ] 기초정리 5. 논리적 자료 표현 - 구조체 (0) | 2022.07.19 |
[ C++ ] 기초 정리 3. 조건문, 반복문, 네임스페이스 (0) | 2022.07.18 |
[ C++ ] 기초 정리 2. 자료형과 연산자 (0) | 2022.07.18 |
[ C++ ] C++ for문, for-each문 (0) | 2022.06.21 |