본문 바로가기

C lang

[C language] Geany편집기 - 7. * 포인터 (참조 변수)의 참조, 역참조, 상수처리, 함수 매개변수 활용

#정리

# printf - 주소출력 
// printf로 값을 출력할 때는 타입에 맞게 형식을 쓰며, 주소를 출력할 때는 %p를 이용한다.
 - value : %d, %c, %s, %lld, %f, %lf, %c, %s - address : %p
//배열 변수는 실제 값이 아닌, 값의 시작 주소를 가진다.
 - printf("sus[0] address : %p\n", &sus[0]);//index를 주면 실제 값을 가진다.
 - printf("sus address : %p\n", sus);//배열의 시작 주소는 sus[0]의 시작 주소와 같다.
 - printf("sus[0] value : %d\n", sus[0]);//index를 주면 실제 값을 가진다.
//문자열 배열도 주소값을 가지지만, 문자열 배열은 %s로 바로 출력이 가능하다.
 - printf("cs value : %s\n", cs);


# pointer : 참조 변수
(1. 주소값 반환 및 역참조 값 출력)
//& : 주소를 표현하는 연산자
 - su : 값 / &su : su값의 메모리 주소
//* : 포인터 - 참조형 연산자로 주소값을 담을 수 있는 변수 타입을 만들 수 있다.
 - ** 주소값을 담는 그릇이지, 포인터 변수가 주소값은 아니다. (4.변수로써의 포인터 내용 참조)**
//참조 연산자 포인터(*)를 사용할 때는 변수 본래의 타입과 맞춰줘야한다.
//변수 주소를 포인터 변수에 할당하는 것을 통해 포인터 변수를 초기화 한다.
 - int *pt = &su; 
//포인터 변수에 참조 연산자를 붙이면 해당 주소의 값이 나온다.
 - printf("*pt : %d\n",*pt);//값의 용량이 커지면, 주소로 보내는 쪽이 효율이 좋아진다.
 - 주소는 4Byte로 용량이 일정하기 때문.

(2. 값 변경 및 역참조 변경)
//변수 선언 이후, 초기화(값 지정)가 없으면 경고가 뜨지만, 변수는 인정해준다. 
 - 대신 변수에는 알 수 없는 값이 들어가고, 주소는 임의의 주소가 들어간다.
//변수의 값을 바꿔도 변수 주소는 바뀌진 않는다.
//포인터변수를 역참조한 값을 다른 변수에 넣으면 값은 같아도 다른 변수이므로, 주소가 달라진다.
//특정 변수의 주소 값을 역참조하여 안에 있는 값을 바꾸면, 대상 변수의 값도 같이 바뀐다.
 - 하지만 동일 값을 가진 다른 변수의 값과 주소에는 영향이 없다.


(3. 상수처리 효과)
//포인터 변수에 const 처리를 하면 기본적으로 값을 변경할 수 없지만, 다른 값이 있는 주소값으로 변수 값을 변경하여 우회하여 역참조로 출력되는 값을 변경할 수 있다.
 - *p_total = *p_kor + *p_eng + *p_math; //const read-only error : 주소 내부에 있는 값을 변경할 수 없다.
 - const int* p_total = &total;  >>  p_total = &kor;//국어 값이 들어있는 주소로 바뀜 >>const(상수)일때, 값 자체는 변경이 안되지만 주소를 변경하는 것을 통해 값을 변경할 수 있는 여지가 있다.


(4. 변수로써의 포인터)
//포인터 변수도 주소를 담는 "변수"이기 때문에, 값을 바꿔서 넣을 수 있다.
** null 값으로도 변수를 초기화 할 수 있다. >> (nil) **
 - 선언 후 초기화 하지않으면, 쓰레기(임의의 주소) 값이 들어간다.
 - 다른 변수들의 주소 값으로 변경 가능하다.
//동적 메모리 할당이 매번 해제되고, 다시 할당되면서 동일한 메모리 주소값을 부여받은 사례
 - test01( ), test02( ), test03( )에서 받아온 배열 값의 메모리 주소가 모두 같은 것을 볼 수 있다.

 

 

 

 

# printf - 주소출력 

// printf로 값을 출력할 때는 타입에 맞게 형식을 쓰며, 주소를 출력할 때는 %p를 이용한다.

 - value : %d, %c, %s, %lld, %f, %lf, %c, %s
 - address : %p

//배열 변수는 실제 값이 아닌, 값의 시작 주소를 가진다.

 - printf("sus[0] address : %p\n", &sus[0]);//index를 주면 실제 값을 가진다.

 - printf("sus address : %p\n", sus);//배열의 시작 주소는 sus[0]의 시작 주소와 같다.

 - printf("sus[0] value : %d\n", sus[0]);//index를 주면 실제 값을 가진다.

//문자열 배열도 주소값을 가지지만, 문자열 배열은 %s로 바로 출력이 가능하다.

 - printf("cs value : %s\n", cs);

 

--예문 코드 보기--

더보기
#include <stdio.h>

int main(int argc, char **argv)
{
	printf("pointer...\n");
	//printf로 출력할 때 사용되는 타입 
	//>> value : %d, %c, %s, %lld, %f, %lf, %c, %s
	//>> address : %p
	printf("----------- int -----------------\n");
	int su = 100;
	printf("su value : %d\n", su);
	printf("su address : %p\n", &su);
	
	printf("------------- long ---------------\n");
	long lsu = 3000;
	printf("lsu value : %ld\n", lsu);
	printf("lsu address : %p\n", &lsu);
	
	printf("------------ double ----------------\n");
	double d = 3.14;
	printf("d value : %lf\n", d);
	printf("d address : %p\n", &d);
	
	printf("-------------- number array --------------\n");
	int sus[4] = {11,22,33,44}; //배열 변수는 실제로 갑을 가지고 있지 않고, 값의 주소를 가진다.
	printf("sus[0] value : %d\n", sus[0]);//index를 주면 실제 값을 가진다.
	printf("sus[0] address : %p\n", &sus[0]);//index를 주면 실제 값을 가진다.
	printf("sus address : %p\n", sus);//배열의 시작 주소는 sus[0]의 시작 주소와 같다.
	
	printf("-------------- character --------------\n");
	char c = 'A';
	printf("c value : %c, %d\n",c,c);
	printf("c address : %p\n", &c);
	
	printf("-------------- char array --------------\n");
	char cs[4] = {'a','b','c','\0'}; 
	printf("c[0] value : %c, %d\n", cs[0], cs[0]);
	printf("c[0] address : %p\n", &cs[0]);
	printf("cs address : %p\n", cs);
	printf("cs value : %s\n", cs);//문자열 배열도 주소값을 가지지만, 문자 배열은 %s로 바로 출력이 가능하다.	
	
	return 0;
}

 


 

 

# pointer : 참조 변수 - 1. 주소값 반환 및 역참조 값 출력 

//& : 주소를 표현하는 연산자

 - su : 값 / &su : su값의 메모리 주소

//* : 포인터 - 참조형 연산자로 주소값을 담을 수 있는 변수 타입을 만들 수 있다.

 - ** 주소값을 담는 그릇이지, 포인터 변수가 주소값은 아니다.**

//참조 연산자 포인터(*)를 사용할 때는 변수 본래의 타입과 맞춰줘야한다.

//변수 주소를 포인터 변수에 할당하는 것을 통해 포인터 변수를 초기화 한다.

 - int *pt = &su; 

//포인터 변수에 참조 연산자를 붙이면 해당 주소의 값이 나온다.

 - printf("*pt : %d\n",*pt);
//값의 용량이 커지면, 주소로 보내는 쪽이 효율이 좋아진다.

 - 주소는 4Byte로 용량이 일정하기 때문.

 

--예문 코드 보기--

더보기
#include <stdio.h>

void test01(int *pt);
void test02(double *pt2);
void test03(char *pt3);

int main(int argc, char **argv)
{
	printf("pointer...\n");
	
	printf("---- int - test01 -----\n");
	int su = 100;
	printf("su : %d\n",su);
	printf("&su : %p\n",&su);//address operator
	
	printf("---- int - test01 -----\n");
	//참조 연산자 포인터(*)를 사용할 때는 변수 본래의 타입과 맞춰줘야한다. 
	int *pt = &su; //su변수 주소를 포인터 변수에 할당해줘.
	printf("pt : %p\n",pt);//할당된 su의 메모리 주소값이 출력된다. 
	printf("*pt : %d\n",*pt);//포인터 변수에 참조 연산자를 붙이면 해당 주소의 값이 나온다.
	
	test01(&su);
	
	
	//double test02 mission
	printf("---- double - test02 -----\n");
	double su2 = 3.14;
	printf("su2 : %lf\n",su2);
	printf("&su2 : %p\n",&su2);
	
	printf("---- double - test02 -----\n");
	double *pt2 = &su2;
	printf("pt : %p\n",pt2);
	printf("*pt : %lf\n",*pt2);

	test02(&su2);
	
	
	//char test03 mission
	printf("---- char - test03 -----\n");
	char abc = 'A';
	printf("abc : %c\n",abc);
	printf("&abc : %p\n",&abc);
	
	printf("---- char - test03 -----\n");
	char *pt3 = &abc;
	printf("pt : %p\n",pt3);
	printf("*pt : %c\n",*pt3);

	test03(&abc);
	
	return 0;
}//end main()

void test01(int *pt){
	printf("---- int - test01 -----\n");
	//값의 용량이 커지면, 주소로 보내는 쪽이 효율이 좋아진다.
	printf("test01...pt : %p\n",pt);
	printf("test01...*pt : %d\n",*pt);
}

void test02(double *pt2){
	printf("---- double - test02 -----\n");
	printf("test02...pt2 : %p\n",pt2);
	printf("test02...*pt2 : %lf\n",*pt2);
}

void test03(char *pt3){
	printf("---- char - test03 -----\n");
	printf("test03...pt3 : %p\n",pt3);
	printf("test03...*pt3 : %c\n",*pt3);
}

 


 

 

# pointer : 참조 변수 - 2. 값 변경 및 역참조 변경 

//변수 선언 이후, 초기화(값 지정)가 없으면 경고가 뜨지만, 변수는 인정해준다. 
 - 대신 변수에는 알 수 없는 값이 들어가고, 주소는 임의의 주소가 들어간다.
//변수의 값을 바꿔도 변수 주소는 바뀌진 않는다.
//포인터변수를 역참조한 값을 다른 변수에 넣으면 값은 같아도 다른 변수이므로, 주소가 달라진다.
//특정 변수의 주소 값을 역참조하여 안에 있는 값을 바꾸면, 대상 변수의 값도 같이 바뀐다.
 - 하지만 동일 값을 가진 다른 변수의 값과 주소에는 영향이 없다.

 

--예문 코드 보기--

더보기
#include <stdio.h>

int main(int argc, char **argv)
{
	printf("pointer...\n");
	
	printf("----- int pointer -----\n");
	//변수 선언
	int su;
	int *pt;
	
	//초기화가 없으면 경고가 뜨지만, 변수는 인정해준다. 
	//>> 알 수 없는 값과 임의의 주소가 들어간다.
	printf("su: %d\n",su);
	printf("pt: %p\n",pt);
	
	printf("----- var init -----\n");
	//변수 초기화
	su = 100;
	pt = &su;
	
	printf("su: %d\n",su);
	printf("pt: %p\n",pt);
	
	printf("----- var value change -----\n");
	//변수에 대한 주소이므로, 변수의 값을 바꿔도 주소가 바뀌진 않는다.
	su = 1000;
	printf("su: %d\n",su);
	printf("pt: %p\n",pt);
	
	printf("----- different var init -----\n");
	//포인터변수를 역참조한 값을 변수x에 넣으면 값은 같지만 다른 변수이므로, 주소가 달라진다.
	int x = *pt;
	printf("x: %d\n",x);
	printf("&X: %p\n",&x);
	
	printf("----- dereference var change -----\n");
	//해당 주소의 값을 역참조로 바꾸면, 해당 변수(su)의 값도 같이 바뀐다.
	//하지만 변수(x)의 값과 주소에는 영향이 없다.
	*pt = 10000;
	printf("su: %d\n",su);
	printf("pt: %p\n",pt);
	printf("*pt: %d\n",*pt);
	printf("x: %d\n",x);
	printf("&X: %p\n",&x);
	
	
	//double pointer mission
	printf("====== double pointer =======\n");
	double d;
	double* pt_d;
	
	d = 3.1415;
	pt_d = &d;
	printf("su: %lf\n",d);
	printf("pt_d: %p\n",pt_d);
	

	d = 6.789;
	printf("su: %lf\n",d);
	printf("pt_d: %p\n",pt_d);
	
	double e = *pt_d;
	printf("e: %lf\n",e);
	printf("&e: %p\n",&e);
	
	*pt_d = 12.345;
	printf("d: %lf\n",d);
	printf("pt_d: %p\n",pt_d);
	printf("*pt_d: %lf\n",*pt_d);
	printf("e: %lf\n",e);
	printf("&e: %p\n",&e);
	
	
	//char pointer mission
	printf("====== char pointer =======\n");
	char c;
	char* pt_c;
	
	c = 'A';
	pt_c = &c;
	printf("c: %c\n",c);
	printf("pt_c: %p\n",pt_c);
	

	c = 'B';
	printf("c: %c\n",c);
	printf("pt_c: %p\n",pt_c);
	
	char abc = *pt_c;
	printf("abc: %c\n",abc);
	printf("&abc: %p\n",&abc);
	
	*pt_c = 'C';
	printf("c: %c\n",c);
	printf("pt_c: %p\n",pt_c);
	printf("*pt_c: %c\n",*pt_c);
	printf("abc: %c\n",abc);
	printf("&abc: %p\n",&abc);
	
	return 0;
}

 

 


 

 

# pointer : 참조 변수 - 3. 상수처리 효과 

//포인터 변수에 const 처리를 하면 기본적으로 값을 변경할 수 없지만, 다른 값이 있는 주소값으로 변수 값을 변경하여 우회하여 역참조로 출력되는 값을 변경할 수 있다.

 - *p_total = *p_kor + *p_eng + *p_math; //const read-only error : 주소 내부에 있는 값을 변경할 수 없다.
 - const int* p_total = &total;  >>  p_total = &kor; //국어 값이 들어있는 주소로 바뀜 >>const(상수)일때, 값 자체는 변경이 안되지만 주소를 변경하는 것을 통해 값을 변경할 수 있는 여지가 있다.

 

--예문 코드 보기--

더보기
#include <stdio.h>

int main(int argc, char **argv)
{
	printf("pointer...\n");
	
	int kor=99, eng=88, math=77;
	const int total = kor + eng + math;
	//total = 300;//const read-only error (상수 변경 시도 에러)
	double avg = 0.00;
	printf("%d %d %d %d %.2lf\n",kor,eng,math,total,avg);
	
	int* p_kor = &kor;
	int* p_eng = &eng;
	int* p_math = &math;
	const int* p_total = &total; 
	//p_total = &kor; //국어 값이 들어있는 주소로 바뀜 >>const(상수)일때, 값 자체는 변경이 안되지만 주소를 변경하는 것을 통해 값을 변경할 수 있는 여지가 있다.
	double* p_avg = &avg;
	//*p_total = *p_kor + *p_eng + *p_math; //const read-only error
	*p_avg = total/3.0;
	printf("%d %d %d %d %.2lf\n",*p_kor,*p_eng,*p_math,*p_total,*p_avg);


	printf("----mission---\n");
	int a = 10;
	int b = 20;
	int c = 30;
	int sum = 0;
	double avg2 = 0.00;
	
	printf("%d %d %d %d %.2lf\n",a,b,c,sum,avg2);
	
	int *p_a = &a;
	int *p_b = &b;
	int *p_c = &c;
	int *p_sum = &sum;
	double *p_avg2 = &avg2;
	*p_sum = *p_a+*p_b+*p_c+*p_sum;
	*p_avg2 = *p_sum/3;
	
	printf("%d %d %d %d %.2lf\n",*p_a,*p_b,*p_c,*p_sum,*p_avg2);
	
    
	return 0;
}

 

 


 

 

 

# pointer : 참조 변수 - 4. 변수로써의 포인터 

//포인터 변수도 주소를 담는 "변수"이기 때문에, 값을 바꿔서 넣을 수 있다.

** null 값으로도 변수를 초기화 할 수 있다. >> (nil) **

 - 선언 후 초기화 하지않으면, 쓰레기(임의의 주소) 값이 들어간다.

 - 다른 변수들의 주소 값으로 변경 가능하다.

 

//동적 메모리 할당이 매번 해제되고, 다시 할당되면서 동일한 메모리 주소값을 부여받은 사례

 - test01( ), test02( ), test03( )에서 받아온 배열 값의 메모리 주소가 모두 같은 것을 볼 수 있다.

 

--예문 코드 보기--

더보기
#include <stdio.h>
#include <stdlib.h>

int *test01();
double *test02();
char *test03();

int main(int argc, char **argv)
{
	printf("pointer...\n");
	
	//int *pt;
	//printf("pt: %p\n",pt);//경고: 쓰레기 주소 값이 들어감.
	
	int *pt = NULL;
	printf("pt(null): %p\n",pt); //>>(nil) - 주소값을 null로 초기화 할 수 있다. 
	
	//포인터 변수는 주소를 담는 변수이기 때문에, 값을 바꿔서 넣을 수 있다.
	int su = 100;
	pt = &su;
	printf("pt(su): %p\n",pt);//input su's address
	printf("*pt(su): %d\n",*pt);//su's value
	
	int kor = 99;
	pt = &kor;
	printf("pt(kor): %p\n",pt);//input kor's address
	printf("*pt(su): %d\n",*pt);//kor's value
	
	printf("-----------\n");
	pt = test01();
	printf("pt(test01): %p\n",pt);
	printf("*pt(test01): %d\n",*pt);
	free(pt);
	
	printf("-----------\n");
	double *pt_d = test02();
	printf("pt(test02): %p\n",pt_d);
	printf("*pt(test02): %.2lf\n",*pt_d);
	free(pt_d);
	
	printf("-----------\n");
	char *pt_c = test03();
	printf("pt(test03): %p\n",pt_c);
	printf("*pt(test03): %c\n",*pt_c);
	free(pt_c);
	
	return 0;
}

int *test01(){
	int su01 = 11;
	int* p_su01 = malloc(sizeof(int));//동적 메모리 할당을 하면, 메모리가 사라지지 않는다.
	*p_su01 =su01;
	return p_su01;
	//return &su01;//메모리가 사라지면서 받아올 때 쓰레기 값이 나온다.
}
double *test02(){
	double* p_d02 = malloc(sizeof(double));
	*p_d02 =3.14;
	return p_d02;
}
char *test03(){
	char* p_c03 = malloc(sizeof(double));
	*p_c03 ='A';
	return p_c03;
}