오늘의 TIL 목차 (22.08. 08)
- 문자열
- 함수 포인터
문자열
[ 문자열 ]
: 문자열을 배열 / 포인터 형태로 저장
[문자 배열]
자료형 변수명[크기] = {};
char szName[6] = { 'j', 'u', 's', 'i', 'n'}; // 문자열은 끝에 널 공간도 줘야함 (남겨둬!)
[문자열 상수]
자료형 변수명[크기] = " ";
char szName[6] = "jusin";
[문자열 상수 배열]
자료형* 변수명[문자열 갯수] = {};
char* pArray[3] = {"jusin", "Game", "Academy"};
[포인터]
자료형* 포인터명 = " ";
char* pName = "jusin";
※ 포인터를 이용한 문자열 대입은 포인터가 임시 저장 장치에 "jusin"을 저장한 뒤, 주소를 가리키는 구조이므로 불안정함
→ 불안정한 형태를 보완하기 위해 strcpy_s를 통해 변수에 값을 넣어주는 형태로 많이 사용됨
※문자 배열로 선언 시 크기만큼 원소를 초기화해줘도([6]이면 원소 6개 초기화) 오류는 안 뜸, 그래도 널 값 남겨둬야 함
■ 기능 / 주의
- 배열(문자열 배열 포함), 포인터(함수 포인터 포함)는 이름 자체가 주소이다.
- 문자열은 이름 자체가 주소지만 출력 시 문자열 특성 상 널 전까지의 문자열 전체를 출력한다. (주소 출력 원하면 &)
- 선언된 문자열은 변경 불가하지만 포인터로 선언한 경우 변경이 가능하다. ( 문자열 함수를 이용하여 변경 가능 )
- 문자열만 큰 따옴표 (" ") 로 문자열을 선언할 수 있다. (큰 따옴표 사용 시 문자열 상수)
- 바로 이름을 받아서 포인터로 사용할 수 있지만 문자 결합을 위해서 배열을 거의 사용한다.
- 문자열의 마지막은 꼭 '\0'이 들어가므로 배열 개수를 +1하여 '널' 자리를 포함해줘야 한다.
- 문자열 상수 배열의 경우 []안에 문자열의 길이가 아닌 문자열의 개수가 들어간다.
char szName[6] = "dainn"; // 길이 6의 문자열 (널 포함)
char* szArray[3] = {"dainn", "siwoo", "mom"};
char* pName = "siwoo";
// szName = "mom"; 실행 오류, szName은 상수로 변경 불가능
szName[1] = 'D' // 일반 문자열의 경우 [n]번째 원소 '단문자'로 변경 가능 "문자열"은 불가능
szArray[1] = "family"; // 배열 1번째의 문자열 family로 변경 가능
pName = "daddy"; // 포인터로 문자열 입력 시, daddy로 변경 가능
cout << szName << "\t" << szArray[1] << "\t" << pName << endl;
출력 결과 :
Dainn family daddy
※ 주의 사항
- 선언된 문자열은 "문자열"로 변경 불가능, [n] 원소 지정해서 '단문자'로 변경 가능
- 포인터로 선언한 경우 변경 포인터명 = "문자열" 자체로 문자열 변경 가능
- cin으로 입력 시 일반 문자열, 포인터 상관없이 값 변경 가능
■ 문자 배열 & 문자열 상수의 차이점
- 문자 배열 : 문자 하나 하나를 배열의 원소로 담고 있는 방식
- 문자열 상수 : 데이터 영역(프로그램 종료 시 소멸)에 등록된 문자열의 시작 주소를 담고 있는 방식
- 공통점 : 문자 배열도 문자열 상수도 문자열의 시작 주소를 갖고 있다.
char szName[3] = {'H' ,'i' ); 문자 배열은 char* const p 의 경우와 동일
char szName[16]=""; 문자열 상수는 const char* p의 경우와 동일
char* szName = "jusin"; // 포인터는 " " 로 대입
☞ 원리
■ 예시
char szName1[6] = { 'D', 'a', 'i', 'n', 'n' }; // 문자 배열
char szName2[6] = "Dainn"; // 문자열 상수
char* pName = "jusin"; // 포인터
문자 배열
cout << szName1 << endl; // 문자열 전체 출력 ; 문자열은 주소 출력 시 널 전까지의 문자열 출력
cout << *szName1 << endl; // szName1의 시작 주소에 있는 값 출력 = 0번째 값인 D 출력
cout << szName1[1] << endl; // 배열의 1번째 a 출력
cout << szName1[1] + 1 << endl; // 1번째 배열 a(97)에 1을 더한 값 98 출력
cout << &szName1 << endl; // 배열의 시작 주소 출력 (메모리 공간 5byte ?)
cout << szName1 + 2 << endl; // 2글자 뒤인 inn 출력
cout << &szName1 + 2 << endl; // 2글자 뒤인 i 메모리 주소 출력
cout << " --------" << endl;
char szString[6] = "okay";
cout << *szString << endl; // szString의 시작 주소에 있는 값 출력 = 0번째 값인 o 출력
cin >> szString; // notokay 입력 시 notokay로 값 변경됨
cout << szString << endl;; // notokay 출력
cin >> szString[3]; // yes 입력 시 3번째 원소 한 칸에 y 한 칸 들어감
cout << szString[3] << endl; // y 출력
cout << szString << endl; // notykay 출력
문자열 상수, 포인터도 문자 배열과 같음
cout << szName2[2] << endl; // 2번째 칸 i 출력
cout << &szName2 + 1<< endl; // a 주소
cout << &pName + 3 << endl; // i 주소
문자열 상수 배열
char* pArray[3] = { "dainn", "siwoo", "mom" }; // 문자열 배열
pArray[1] = "daddy";
cout << pArray << endl; // pArray의 주소 출력
cout << pArray[1] << endl; // 변경된 1번째 값 daddy 출력
cout << pArray[2] << endl; // 2번째 값 mom 출력
cout << *pArray + 1 << endl; // 0번째 배열의 값인 문자열 dainn + 1은 ainn 출력
cout << *(pArray+1) << endl; // pArray 주소 1칸 이동의 값은 siwoo 출력
→ 문자열 특징
변수명[n]은 해당 [n]번째의 단문자 출력
변수명[n] + x는 해당 n번째의 단문자 + x만큼 한 값 (아스키코드)
변수명은 해당 변수명의 문자열 전체 출력
변수명 + n은 n글자 뒤의 남은 문자열 출력
※ 문자배열의 배열명 + n은 n칸 이동한 주소 출력, 문자열 + n은 n칸 뒤의 문자열 출력
함수 포인터
[ 함수 포인터 ]
: 함수의 주소를 저장하는 용도의 포인터
타입(*변수명)(매개 변수의 형태)
void(*ptr)(void) = Render; // 선언과 동시에 초기화
void(*p)(); // 매개변수가 없는 경우
int(*Func)(int*, int) = Add; // 매개변수가 여러 개인 경우
int(*Print[2])(int, int) = { Sum, Min }; // 함수 포인터 배열
사용
ptr(); // Render(); 처럼 함수처럼 사용
Print[1](iA, iB); // 1번째 배열의 Min함수를 실행
■ 기능 / 주의
- 함수 포인터는 포인터와 마찬가지로 "32비트 기반 프로그래밍 기준" 4byte이다.
- 함수 포인터는 변수의 특성을 지니기 때문에 대입에 따라서 함수는 바뀔 수 있다.
- 함수 포인터 배열은 이름[배열 위치] 만 적으면 배열의 해당 위치에 있는 함수의 주소를 출력한다.
- 함수 포인터 배열은 이름[배열 위치](매개변수)도 같이 적어야 해당 함수를 실행한다.
■ 예시
int Sum(int* _pA, int* _pB);
int Mul(int* _pA, int* _pB);
void Swap(int* _pA, int* _pB);
void Print(void);
void main(void)
{
int iA = 5, iB = 3;
int(*Cal)(int*, int*) = Sum; // 함수 포인터 선언 방식
int(*Calcu[2])(int*, int*) = { Sum, Mul };
void(*p)() = Print;
cout << Cal(&iA, &iB) << endl; // Sum 함수 실행
Cal = Mul; // 함수 포인터는 변수적 특성, Cal안의 Sum 주소 대신 Mul 주소로 변경 가능
cout << Cal(&iA, &iB) << endl; // Mul 함수 실행
// Calcu[0]은 0번째 배열의 주소(Sum의 주소) 출력, Calcu[0](&iA, &iB)은 해당 함수 실행
cout << Calcu[0] << "\t" << Sum << "\t" << Calcu[0](&iA, &iB) << endl;
cout << iA << << "\t" << iB << endl; // Swap(&iA, *iB) 자체는 반환 값이 void이기 때문에 출력 불가능
p(); // Print(); 와 동일
}
int Sum(int* _pA, int* _pB) { return *_pA + *_pB; }
int Mul(int* _pA, int* _pB){
int Mul = (*_pA) * (*_pB);
return Mul;
}
void Swap(int* _pA, int* _pB) {
int iTemp = 0;
iTemp = *_pA;
*_pA = *_pB;
*_pB = iTemp;
}
void Print(void) { cout << "안녕" << endl; }
출력 결과 :
8
18
14325A 1432A 8
3 5
안녕
'C++' 카테고리의 다른 글
| [TIL 13강] 열거체, C언어 동적할당(feat. Heap) (0) | 2022.08.12 |
|---|---|
| [TIL 12장] 문자열 함수, 구조체(feat. 포인터 사용), 공용체 (0) | 2022.08.10 |
| [TIL 10장] 2차원 배열 (0) | 2022.08.05 |
| [TIL 9장] 이중 포인터 개념, 배열, 디버깅 (0) | 2022.08.04 |
| [TIL 8장] 포인터, 상수 포인터 (0) | 2022.08.03 |