포인터: 메모리 상에 위치한 특정 데이터의 (시작) 주소값을 보관하는 변수
(포인터에 저장되는 주소값의 데이터형)* (포인터의 이름)
ex)
int *pa;
&(주소값을 저장할 데이터) = 주소값
ex)
&a = pa;
const = 이 데이터의 값은 절대로 바뀌면 안된다
ex)
const int* pa = &a
: const int 형 변수를 가리킨다는 것이 아님. int형 변수를 가리키는데 pa가 가리키는 값을 절대 바꾸지 말라는 뜻. 즉 이 문장에서 pa는 반드시 a의 주솟값만 가리키도록 하고 a에 담기는 값은 변할 수 있음을 의미한다. 그래서 이 문장 이후에 'pa = &b'같은 문장은 에러가 난다.
&와 *은 상쇄된다는 늒김으로다가....
포인터는 자신이 가리키는 데이터의 '형'의 크기를 곱한 만큼 덧셈을 수행한다.
ex) pa라는 포인터가 int a를 가리킨다면, p + 1을 하면 p의 주솟값에 1x4(= 4)가 더해지는 것이고, p + 3을 하면 p의 주솟값에 3x4(= 12)가 더해지는 것이다.
배열에서 배열의 이름은 배열의 첫번째 원소의 주솟값을 가리키는 포인터가 된다.
: 배열의 이름과 배열의 첫번째 주소값은 엄밀히 다른 것이지만, 배열의 이름을 사용했을 때 암묵적으로 첫번째 원소를 가리키는 포인터로 타입 변환이 되기 때문이다!
ex)
arr[10] = {1, 2, 3, ..., 10};
에서 'arr'의 값 = '&arr[0]'의 값
레퍼런스(참조자)
ex)
int& another_a = a;
= another_a는 a의 참조자다. 즉, another_a는 a의 또다른 이름이라고 컴파일러에게 알려주는 것. ("another_a야, 너는 이제부터 a의 또다른 이름이야.") 따라서, another_a에 수행하는 작업은 사실상 a에 수행하는 작업.
포인터와 비교되는 레퍼런스의 특징
1. 레퍼런스는 반드시 처음에 누구의 별명이 될 것인지 지정해야함. (int* pa;는 가능하지만 int& another_a;는 불가능)
2. 레퍼런스가 한 번 누군가의 별명이 되면 다른 이의 별명이 될 수 없다.
3. 포인터와 달리 레퍼런스는 메모리상에 존재하지 않을수도 있다.
4. 불필요한 &와 *가 없어서 코드가 훨씬 간결해짐.
(C++ 문법상 참조자의 참조자를 만드는 것은 금지되어 있음)
+) scanf 쓸때는 &another_a 해줘야하는데 cin 쓸때는 & 없이 그냥 another_a 해도 됨!
{리터럴(literal): 소스 코드 상에서 고정된 값을 가지는 것. 리터럴이 보관되는 곳은 오직 읽기만 가능한 곳.}
{참고적으로 VS 2017 이상에서는 리터럴을 char* 가 가리킬 수 없습니다. 반드시 const char* 가 가리켜야 하며, 덕분에 리터럴을 수정하는 괴랄한 짓을 컴파일 단에서 막을 수 있습니다.}
+) 함수를 만들 때 반드시 고려해야 할 사항
1. 이 함수는 무슨 작업을 하는가? (자세하게)
2. 함수의 리턴형이 무엇이면 좋을까?
3. 함수의 인자으로는 무엇을 받아야 하는가?
ex) 문자열 복사하기
#include <stdio.h>
int copy_str(char *src, char *dest);
int main() {
char str1[] = "hello";
char str2[] = "hi";
printf("복사 이전 : %s \n", str1);
copy_str(str1, str2);
printf("복사 이후 : %s \n ", str1);
return 0;
}
int copy_str(char *dest, char *src) {
while (*src) { //*src = NULL(= 0)이 될 때까지
*dest = *src; //src의 문자를 dest에 대입
src++; //배열의 다음 원소를 가리키게 함
dest++; //배열의 다음 원소를 가리키게 함
}
*dest = '\0';
/*
위의 while문에서 src가 NULL 이 된다면
while문을 종료해 버렸기 때문에 src 에 넣을 틈이 없었는데
마지막에 위와 같이 처리해줌으로써
dest 에 NULL 문자를 끝부분에 삽입할 수 있게 됨
*/
return 1;
}
ex) 문자열 더하기
/*
dest에 src 문자열을 끝에 붙인다.
이 때 dest 문자열의 크기를 검사하지 않으므로
src가 들어갈 수 있는 충분한 크기가
있어야 한다.
*/
int stradd(char *dest, char *src) {
//dest 의 끝 부분을 찾는다.
while (*dest) {
dest++;
}
/*
while문을 지나고 나면 dest는
dest 문자열의 NULL 문자를 가리키고 있게 된다.
이제 src의 문자열들을 dest의 NULL 문자 있는 곳 부터
복사해넣는다.
*/
while (*src) {
*dest = *src;
src++;
dest++;
}
/*
마지막으로 dest 에 NULL 추가 (왜냐하면 src 에서
NULL 이 추가 되지 않았으므로)
*/
*dest = '\0';
return 1;
}
ex) 문자열 비교하기
int compare(char *str1, char *str2) {
while (*str1) {
if (*str1 != *str2) {
return 0;
}
str1++;
str2++;
}
if (*str2 == '\0') return 1;
return 0;
}
(in C++)
[코드]
#include <cstdio>
#include <cstdlib>
//int형 2차원 배열 동적 할당 함수
int** alloc2DInt (int rows, int cols){
if( rows <= 0 || cols <= 0 ){
return NULL;
}
int** mat = new int* [rows];
for (int i = 0 ; i < row ; i++){
mat[i] = new int [cols];
}
return mat;
}
//int형 2차원 배열 동적 해제 함수
void free2DInt (int** mat, int rows, int cols = 0){
if ( mat != NULL){
for (int i = 0; i < row; i++)
delete [] mat[i];
delete [] mat;
}
}
//동적 생선된 2차원 배열을 랜덤으로 초기화하는 함수
void set2DRandom (int** mat, int rows, int cols){
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
mat[i][j] = rand()%100;
}
}
}
//2차원 배열을 화면으로 보기 좋게 출력하는 함수
void print2DInt (int** mat, int rows, int cols){
printf("행의 수 = %d, 열의 수 = %d", rows, cols);
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
printf("%4d", mat[i][j]);
}
}
}
//주 함수: 2차원 배열 동적 할당 테스트
void main(){
int** mat;
int rows, cols;
printf("행과 열의 크기를 입력하시오: ");
scanf("%d%d", &rows, &cols);
mat = alloc2DInt( rows, cols );
set2DRandom( mat, rows, cols );
print2DInt( mat, rows, cols );
free2DInt( mat, rows, cols );
}
[실행 결과]
행과 열의 크기를 입력하시오: 4 6
행의 수 = 4, 열의 수 = 6
41 67 34 0 69 24
78 58 62 64 5 45
81 27 61 91 95 42
27 36 91 4 2 53
계속하려면 아무 키나 누르십시오...
잘보고 갑니다