• char 배열이름[크기] ="문자열";
#include <stdio.h>

int main()
{
    char s1[10] = "Hello";  // 크기가 10인 char형 배열을 선언하고 문자열 할당

    printf("%s\n", s1);     // Hello: %s로 문자열 출력

    return 0;
}

  • 배열을 미리 선언해 놓고 문자열 나중에 할당 하는 방법
#include <stdio.h>

int main()
{
    char s1[10];     // 크기가 10인 char형 배열 선언
    
    s1 = "Hello";    // 이미 선언된 배열에 문자열을 할당하면 컴파일 에러 발생

    printf("%s\n", s1);    // Hello: %s로 문자열 출력

    return 0;
}

이미 선언된 배열에는 문자열을 할당 할 수 없음. 정 할당하고 싶으면 

s1[0] = 'h';

s1[1] ='e';

이런식으로 하나 하나 집어 넣어야함.

 

 

  • 배열이 크기 할당 시 
char s1[6] = "Hello";    // 크기가 6인 배열. Hello 5글자에 NULL 하나를 더해 6개의 공간이 필요함

 

char[] 와 char* 의 차이점

char str[] = "abc";

char *str = "abc";

char* 는 읽기 전용 수정 불가

//수정 불가
int main()
{
    char *str = "abc";
    str[0] = 'b';
}

//수정 가능
int main()
{
    char str[] = "abc";

    str[0] = 'b';
}

 

'C++' 카테고리의 다른 글

Visual Studio 2015 - 자주 사용하는 단축키  (0) 2020.08.19
[C++] 포인터(Pointer)  (0) 2020.07.23
[C++] 스택과 힙  (0) 2020.07.23
[C++] 메모리누수 체크  (0) 2020.07.23
[C++] char[] 와 char*의 차이  (0) 2020.07.22

문자 검색/치환

  • Ctrl+F: 문자 검색
  • Ctrl+H:문자의 치환

직사각형 선택

Alt 키를 누른 상태에서 마우스로 원하는 직사각형 모양의 범위를 만든다.

자동 인덴트(indent)

  • Ctrl+K, Ctrl+D: 파일 전체의 인덴트 조정
  • Ctrl+K, Ctrl+F: 선택 범위의 인덴트 조정

코드 개요 확장/축소

  • Ctrl+M, Ctrl+L: 파일 전체의 개요 확장/축소
  • Ctrl+M, Ctrl+M: 선택 범위의 개요 확장/축소

주석

  • Ctrl+K, Ctrl+C: 선택 범위의 주석화
  • Ctrl+K, Ctrl+U: 선택 범위의 주석 해제

클립 보드 링

  • Ctrl+Shift+V: 클립 보드 링을 사용하여 이전에 복사한 데이터를 순환하면서 붙이기 할 수 있다.

함수 정의로 이동

  • F12: 선택한 함수의 정의로 이동

커서 위치 이력 기록

  • Ctrl + -(마이너스): 직전의 커서 위치로 돌아간다
  • Ctrl + Shift + -(마이너스): 다음 커서 위치로 나간다

 

 

https://jacking75.github.io/VS_tips01/

 

'C++' 카테고리의 다른 글

[C++] char 문자열 (기본, char[] 와 char* 의 차이점 등)  (0) 2020.09.24
[C++] 포인터(Pointer)  (0) 2020.07.23
[C++] 스택과 힙  (0) 2020.07.23
[C++] 메모리누수 체크  (0) 2020.07.23
[C++] char[] 와 char*의 차이  (0) 2020.07.22

포인터(Pointer)

  • 프로그램이 변수를 인스턴스화 할때 사용 가능한 메모리 주소가 변수에 자동으로 할당되고, 변수에 할당된 값은 이 메모리 주소에 저장된다.
int x;
  • CPU가 위 문장을 실행하면 RAM의 메모리 조각이 따로 설정됨.
예를 들어 변수 x에 메모리 위치 140이 할당 되었다고 가정하면, 프로그램에서 변수 x를 표현식 또는 명령문으로 접근할 때마다 값을 얻으려면 메모리 위치 140을 찾아야함.
변수의 좋은 점은 우리가 어떤 특정한 메모리 주소가 할당되는지 걱정할 필요가 없다는 것이다.
지정된 변수를 참조하면 컴파일러에서 이 이름이 할당된 메모리 주소로 반환한다.

주소 연산자(&) (The address-of operator(&))

주소 연산자 &를 사용하면 변수에 할당된 메모리 주소를 확인할 수있다.

#include <iostream>

int main()
{
	int x=5;
	cout<<x<<endl;
	cout<<&x<<endl;
    
    return 0;
}

역참조 연산자(*) (The dereference operator(*))

  • 변수의 주소를 얻는 것 자체로는 그다지 유용하지 않다.
  • 역참조 연산자(*)를 사용하면 특정 주소에서 값에 접근할 수있다.
 int main() 
{
	int x = 5; 
	std::cout << x << '\n'; // print the value of variable x 
	std::cout << &x << '\n'; // print the memory address of variable x 
	std::cout << *&x << '\n'; /// print the value at the memory address of variable x 
	return 0; 
} 

// prints: 
// 5 
// 0027FEA0 
// 5

역참조 연산자(*)는 곱셈 연사자처럼 보이지만, 역참조 연산자는 단항이고 곱셈 연산자는 이항 연산자이다.

 

포인터(Pointer)

  • 포인터는 어떠한 값을 저장하는게 아닌 메모리 주소를 저장하는 변수이다.
  • C++에서 가장 혼란스러운 부분이라고 생각X -> 매우간단하다. 

포인터 선언

 포인터 변수는 일반 변수처럼 선언되며, 자료형과 변수 이름사이에 별포(*)가 붙는다.

  • 자료형* 포인터 이름;
int* iPtr; // int형 포인터 
double* dPtr; // double형 포인터 
int* iPtr2, *iPtr3; // int형 두 개의 포인터 선언
  • 여러 포인터 변수를 선언하는 경우 별표가 각 변수에 포함되어야한다. 초기화 하지않으면 쓰레기 값

포인터에 값 할당(Assingning a value to a pointer)

  • 포인터는 메모리 주소만 저장하므로, 포인터에 값을 할당할 때 그 값은 주소여야한다.
  • 포인터로 하는 가장 흔한 작업은 다른 변수의 주소를 저장하는 것이다.
int value = 5; 
int *ptr = &value; // 변수값의 주소로 ptr 초기화
 

double *dPtr = 0x0012FF7C; // not okay (정수 리터럴을 할당하는 것으로 취급된다.)

the address-of operator returns a pointer

  • 주소 연산자 &는 피연산자의 주소를 리터럴로 반환하지 않는다.
  • 대신 피연사자의 주소가 들어있는 포인터를 반환하다.

 

Dereferencing pointers 

  • 어떤 것을 가리키는 포인터변수가 있다면, 역참조 변환자(*) 를 통해 포인터가 가리키는 주소의 값을 알 수 있다.
int value = 5; 
std::cout << &value; // value의 주소를 출력한다. 
std::cout << value; // value의 값을 출력한다. 

int *ptr = &value; // ptr은 value를 가리킨다. 
std::cout << ptr; // ptr이 가리키는 주소를 출력한다. (=&value) 
std::cout << *ptr; // ptr을 역참조한다. (ptr이 가리키는 주소의 값을 출력한다. =value) 

// 0012FF7C 
// 5 
// 0012FF7C 
// 5
  • 이러한 이유(주소의 값을 알아내는 것) 때문에 반드시 자료형을 가져야한다. 자료형이 없으면 역참조 시 가리키는 내용을 해석하는 방법을 알지 못함.
  • *ptr은 변수이므로 다른 변수를 할당 가능하다.
int value =5;
int *ptr= &value;

*ptr= 7; //가능

 

요약(Summary)

  • 포인터는 메모리 주소를 저장하는 변수이다.
  • *를 사용하여 저장한 메모리의 주소의 값을 알 수있다.
  • 가비지 포인터를 역참조하면 응용 프로그램이 종료될 수있다.

세그먼트(Segment)

  • 코드 세그먼트 : 컴파일된 프로그램이 저장되는 영역, 일반적으로 read-only 속성이다.
  • 데이터 세그먼트 : 전역 변수 및 정적 변수가 저장되는 영역
  • 힙 세그먼트 : 동적으로 할당된 변수가 할당되는 영역
  • 스택 세그먼트 : 함수 매개 변수, 지역 변수 및 기타 함수 관련 정보가 저장되는 영역.

힙 세그먼트(Heap segment)

힙 세그먼트는 동적 메모리 할당에 사용되는 메모리를 적재한다. C++에서 new 연산자를 사용해서 메모리를 할당하면 이 메모리는 응용 프로그램의 힙 세그먼트에 할당된다.

int main()
{ 
	int* ptr = new int;//ptr은 힙에서 4바이트로 할당됨.
	int* array = new int[10];//array는 힙에서 40바이트로 할당됨.

	//차례로 선언했지만 순차적 메모리 주소를 갖는 것은 아님
	int* ptr1 = new int;
	int* ptr2 = new int;
}

힙의 장단점

  • 힙에 메모리를 할당하는 것은 비교적 느리다.
  • 할당된 메모리는 명시적으로 할당 해제하거나 (delete) 응용 프로그램이 종료될 때까지 유지된다.(메모리 릭 주의
  • 동적으로 할당된 메모리는 포인터를 통해 접근한다: 포인터를 역참조하는 것은 변수에 직접 접근하는 것보다 느리다.
  • 힙은 큰 메모리 풀이므로 큰 배열, 구조체 또는 클래스를 할당할 수 있다.

스택 세그먼트

  • 스택 세그먼트(=콜스택)는 메인() 함수부터 현재 실행 지점까지의 모든 활성 함수를 추적하고 모든 함수 매개 변수와 지역 변수의 할당을 처리한다.
  • 스택은 후입선출(LIFO) 자료구조이다. 즉, 함수 호출이 끝나고, 이전 함수로 돌아갈 때 이 함수의 바로 이전함수로 돌아가야한다. 그래서 컴퓨터는 내부적으로 스택 세그먼트를 스택 자료구조로 구현한다.(재귀)
    • 콜 스택(call stack) 이란 컴퓨터 프로그램에서 현재 실행 중인 서브루틴(함수)에 관한 정보를 저장하는 스택 자료구조이다.
    • 응용 프로그램이 시작되면 메민() 함수가 운영체제에 의해 호출 스택에 푸시됨.
    • 프로그램 실행
    • 함수호출이 발생하면 함수가 콜 스택에 푸시됨.
    • 현재 함수가 끝나면 해당함수는 콜 스택에서 해제 됨.
    • 따라서 콜 스택에 푸시된 함수를 살펴보면 현재 실행 지점에서 이동하기 위해 호출된 모든 함수를 볼 수 있다.
#include <iostream>
using namespace std;
void func()
{
	cout << "func" << endl;
	 
 }
void func2()
{ 
	cout << "func" << endl;
}
void func3()
{
	cout << "func" << endl;
}

int main()
{ 
	int* ptr = new int;//ptr은 힙에서 4바이트로 할당됨.
	int* array = new int[10];//array는 힙에서 40바이트로 할당됨.

	//차례로 선언했지만 순차적 메모리 주소를 갖는 것은 아님
	int* ptr1 = new int;
	int* ptr2 = new int;

	//콜 스택 ex
	func();
	func2();
	func3();

}

 

  • 콜 스택 자체는 고정된 크기의 메모리 영역이다.
  • 스택 프레임(stack frame) : 콜 스택에 넣고 빼는 데이터, 하나의 함수 호출과 관련된 모든 데이터를 추적
  • 스택 포인터(stack pointer) : cpu의 작은 조각인 레지스터는 현재 호출 스택의 최상위 위치를 가리킨다.

콜 스택 발생 순서

  1. 프로그램에 함수 호출이 발생
  2. 스택 프레임이 생성되고 콜 스택에 푸시된다. 스택 프레임은 다음과 같이 구성된다.
    1. 함수가 종료되면 복귀할 주소
    2. 함수의 모든 매개변수
    3. 지역 변수
    4. 함수가 반환할 때 복원해야 하는 수정된 레지스터의 복사본
  3.  CPU가 함수의 시작점을 점프한다.
  4. 함수 내부의 명령어를 실행한다.

함수가 종료 되면 다음단계가 수행된다.

  1. 레지스터가 콜 스택에서 복원된다.
  2. 스택 프레임이 콜 스텍에서 튀어나온다. 이렇게 하면 모든 지역 변수와 매개 변수에 대한 메모리가 해제된다.
  3. 반환 값이 처리된다.
  4. CPU는 반환 주소에서 실행을 재개한다.

일반적으로 콜 스택이 어떻게 동작하는지에 대한 모든 세부사항은 중요하지 않다. 그러나 함수가 호출될 때와 종료될 때 함수가 콜 스택에서 효과적으로 작동하다는 것을 이해하면 재귀를 이해할 때와 디버깅할 때 유용하다.

 

스택 오버플로 (stack overflow)

  • 스택 세그먼트는 크기가 제한되어 있으므로 제한된 양의 데이터만 저장할 수 있다. 
  • window 운영체제에서 기본 스택 세그먼트의 크기는 1MB다. 
  • 응용 프로그램이 스택 세그먼트에 너무 많은 정보를 담으려고 하면 스택 오버플로(stack overflow)가 발생한다.
  • 스택 오버플로는 보통 스택 세그먼트에 1)너무 많은 변수 2)중첩된 함수 호출 이다.

ex)1) 너무 큰 배열 2)무한 루프

void foo()
{
	foo(); //2) 무한 루프 
} 
int main()
{
	int stack[100000000]; //1) 너무 많은 크기의 배열
    foo(); 
}
  • 스택에 메모리를 할당하는 것은 비교적 빠르다.
  • 스택에 할당된 메모리는 스택 범위에 있을 때만 접근 할 수 있다.
  • 스택에 할당된 모든 메모리는 컴파일 타임에 알려진다. 메모리는 변수를 통해 직접 접근 가능.
  • 스택은 비교적 크기가 작으므로 스택 공간을 많이 차지하는 지역 변수를 만드는 것은 좋지 않다.

    출처: https://boycoding.tistory.com/235 [소년코딩]

 

동적할당 시 메모리 delete를 안해주면 메모리가 누수된다.

누수된 부분을 찾는 방법

  • int형 400byte 동적할당한다. 
int main()
{
	int* buff = new int[100];

}
  • 전처리 및 함수를 입력한다.
//메모리 누수관련 전처리
#include <iostream>
#define _CRTDBF_MAP_ALLOC 
#include <cstdlib>
#include <crtdbg.h>

int main()
{
	int* buff = new int[100];
	_CrtDumpMemoryLeaks();  //메모리 누수 함수 체크 

}

(출력이미지)

출력은 되었지만, 어느 부분에서 메모리 누수 되었는지 알수없다.

  • 해결방법
#include <iostream>
//메모리누수 체크 코드
//#include "pch.h"
//#include <Window.h>
#define _CRTDBF_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>

//어느 부분인지 체크하는 전처리 및 정의
#ifdef _DEBUG
#define new new (_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

int main()
{
	int* buff = new int[100];
	_CrtDumpMemoryLeaks();

}

ifdef 부분을 추가하면 다음과 같이 어느부분에서 메모리누수가 발생했는지 알수있다.

또한, 더블클릭하면 그 지점으로 이동한다.

https://luckygg.tistory.com/226

'C++' 카테고리의 다른 글

[C++] 포인터(Pointer)  (0) 2020.07.23
[C++] 스택과 힙  (0) 2020.07.23
[C++] char[] 와 char*의 차이  (0) 2020.07.22
[C++] 포인터(Pointer)와 레퍼런스(Reference : 참조자)의 차이  (0) 2020.07.22
[C++] char*, const char*, char* const  (0) 2020.07.21
  • char[]의 경우는 local data를 가지는 포인터이다. 따라서 수정가능.
  • char* 경우는 global static data 할당한 후 그의 포인터를 가지는 것이기 때문에 수정 불가능.!
char str[] = "hello world";  //local data 수정 O
str[3] = '3'; 
cout << str << endl; 

char *str2 = "hello world"; //global static data 수정 X
str2[3] = '3'; //error 

 

'C++' 카테고리의 다른 글

[C++] 스택과 힙  (0) 2020.07.23
[C++] 메모리누수 체크  (0) 2020.07.23
[C++] 포인터(Pointer)와 레퍼런스(Reference : 참조자)의 차이  (0) 2020.07.22
[C++] char*, const char*, char* const  (0) 2020.07.21
C++ assign (vector, map)  (0) 2020.07.16

일반 변수

  • 직접 값을 보유.

포인터

  • 다른 값의 주소(또는  NULL)를 보유.

레퍼런스

  • 참조자(Reference)는 변수에 "별명"을 붙인다고 한다.
  • 별명을 통해서 변수의 메모리 공간에 접근이 가능하다.
  • 참조자(Reference)는 이름 앞에 "&"붙여서 선언한다.
  • 참조자(Reference)는 변수에 대해서만 선언이 가능, 선언과 동시에 누군가를 참조 해야만 한다.
  • 참조자(Reference)는 참조의 대상을 바꾸는 것이 불가능.
  • 참조자(Reference)는 NULL로 초기화 하는 것이 불가능.

세 가지 종류의 참조형 지원

  1. non-const 값 참조형
  2. const 값 참조형
  3. r-value 참조형 

1)사용법

  • 참조자(Reference)가 가지고 있는 값을 변경하면 원래 있던 변수의 값이 변경됨.
  • 코드 중에 '&'는 주소(address)를 의미하지 않고 참조(reference)를 의미함.
  • 따라서 num1과 num2는 동의어라고 취급된다. (num1 -= 10 해주면 num2도 -10 됨)
int num1 = 10;
int &num2 = num1; 
num2 += 10; //num1,2 모두 20으로 변환

 

2)참조자와 함수

  • 레퍼런스를 함수의 매개변수로 사용 가능(Call by Reference)
  • C에서는 Call-by-pointer, C++에서는 Call-by-Reference

두 가지 차이점 

 

1.NULL 사용 여부

  • 포인터는 NULL 사용을 허용O
  • 레퍼런스는 NULL 사용 허용X
struct Point 
{
	int x;
	int y;
};

struct Point *aaa = NULL;
	aaa->x = 120;
	aaa->y = 240;

 

  • 하지만, 레퍼런스는 문제 발생하지 않음 why ? 페러런스 자체는 NULL을 할당할 수 없도록 아예 처음부터 제한함.
  • 포인터와 목적은 같지만 잘못된 참조로 인해 발생하는 오류를 방지하기 위해 고안.

2.참조 대상 할당 및 접근

  • 포인터는 참조대상에 대해 &연산을 통해 주소값을 할당함.
  • 하지만, 레퍼런스는 참조 대상을 그대로 할당함.
  • 레퍼런스는 선언과 동시에 초기화 하지 않으면 컴파일 오류가 발생함. (NULL을 할당 불가)
int a = 10;  
int *ppp = &a;  //포인터변수에는 주소값이 할당됨.  
int &r = a;   //레퍼런스에는 참조대상을 그대로 할당함.

 

결론

레퍼런스는 포인터를 잘못 사용해서 생기는 수많은 재앙과도 같은 문제들을 최소화하기위해 등장

Use references when you can, and pointers when you can have to
사용할 수 있다면 참조자를, 어쩔 수 없다면 포인터를 써라

'C++' 카테고리의 다른 글

[C++] 메모리누수 체크  (0) 2020.07.23
[C++] char[] 와 char*의 차이  (0) 2020.07.22
[C++] char*, const char*, char* const  (0) 2020.07.21
C++ assign (vector, map)  (0) 2020.07.16
C++ 동적할당  (0) 2020.07.14

1) char* v;

v는 문자, 문자열이 저장된 메모리의 첫 주소를 저장할 수 있는 포인터변수

v 주소 메모리의 내용 변경 가능

v 문자열 변경 가능

ex)

char* v ="문자열 상수1"; //초기화 했어도 코드중에 언제나 변경 가능
v= "문자열 상수2"; 		//변경 가능
v= "문자열 상수3"; 		//변경 가능 

2)const char* v;

v는 문자열이 저장된 메모리의 첫 주소를 저장할 수 있는 포인터변수, 즉, v는 "상수문자열"의 포인터변수라는 의미

v 주소 메모리의 내용 변경 불가

v 문자열 변경 가능

한편, const의 대상이 v자체가 아니므로  v가 가리키는 주소는 변경가능함.

ex)

const char* v = "난 문자열 상수1이다"

위 처럼 초기화 했어도, 코드상에서 아래 처럼 다른 문자열의 메모리 주소를 대입가능하다는 말

v="난 문자열 상수2임" //가능함 v에 다른 문자열 주소는 대입가능
*v="난 문자열 상수2임"; //허용 안됨. v는 주소 메모리의 값을 변경 의도한 것인데, const char* v; 의 정의가 이런거 못하게 하는 것

 

3)char* const v;

v는 문자열이 저장된 메모리의 첫 주소를 저장할수 있는 포인터변수

초기화 할 때 한번 지정된 문자열& 메모리 주소는 변경 못함

ex)

char* const v = "난 문자열 상수1이다." ; 로 초기화 했는데 
v="난 문자열 상수2임"; 으로 변경 허용 안됨.

'C++' 카테고리의 다른 글

[C++] char[] 와 char*의 차이  (0) 2020.07.22
[C++] 포인터(Pointer)와 레퍼런스(Reference : 참조자)의 차이  (0) 2020.07.22
C++ assign (vector, map)  (0) 2020.07.16
C++ 동적할당  (0) 2020.07.14
C++ iterator, auto  (0) 2020.06.29

+ Recent posts