열혈강의 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
문자열 str1str2를 비교하여 결괏값을 반환,
결괏값을 -1,0,1중 결정
Str1<str2, str1=str2, str1>str2
이때 문자열 내용을 16진법으로 변환 후 값 비교

위에서 노랑색으로 칠해진 함수들은 보안에 취약한 함수이다. 이것들을 사용해 디버깅을 실행하면 경고 창이 나올 것이다.

 

보안에 취약하지 않은 함수들 ( 그냥 위에 함수에 _s만 붙임 )

함수 설명
Strcpy_s(dest,size,str)
// string capy
문자열 strdest에 복사!
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명령으로 해제를 시켜야 한다. 만약 해제를 안시키면 다른 곳의 변수이름과 겹칠 때 오류가 생긴다.

 

 

+ Recent posts