본문 바로가기

C언어

컴프 7주차

포인터는 c계열에만 있다.자바에는 없음. c언어는 하드웨어용 제어를 할 때 많이 쓴다.(가전제품 등등) 하드웨어를 제어하기 편리함. 반면 하드웨어를 직접 제어하므로 실수하면 문제가 생겨서 자바에서는 사라짐. (11장 교재) 
포인터도 변수이다. 배열도 변수이다. 모두 변수이다. 그런데 변수와는 조금 다르다. 지금까지느 ㄴ변수가 값을 갖고 있었는데, 포인터 변수는 값이 아닌 주소를 가진다. 포인터는 메모리 주소를 가지고 있는 변수이다. 다른 변수는 값을 가진다. 
메모리를 그리고 변수가 있으면 a는 10 0x16진수로 주소값이 정해짐. 포인터는 P라는 변수명(자주) 0x16진수가 들어가 있다. 주소값을 가졌다는의미. 값이 없고 주소가 있따. 값은 그 주소에 가야 있다. 그래서 주소를 쫓아 가보면 값이 있다. 포인터는 값이 없고 주소가 있다. 변수는 메모리에 저장되어 있고 바이트 단위로 실행된다. 포인터는 변수이므로 선언법과 값을 넣는 방법을 알아보자. 
주소연산자: & 
간접 (참조) 연산자: * => 곱셈의 의미가 아님. //역으로 참조해봐라.
포인터 덧셈/뺄셈의 의미: ++, --, +, - 

<선언법>
int *P; => 변수를 선언한 것처럼 하고 앞에 *를 붙인다.
int* P; => 요즘은 이렇게 쓴다.
P는 다른 변수의 주소를 저장한다. => 직접적으로 주소값을 입력하지 않는다. 

P에는 주소가 정수형이라 int라고 쓰는 것일까? P앞의 자료형은 포인터 변수 자체의 자료형은 무조건 정수형이고, P앞의 자료형은 주소값을 넣으려는 변수의 자료형이다.

char ch ='A';
double d = 3.14;
int i = 10;
char *PC; //PC의 자료형은 정수이고, 가리키는 주소에 가면 char 데이터가 있음.
double *PD; //PC의 자료형은 정수이고, 가리키는 주소에 가면double데이터가 있음.
int *PI; //PC의 자료형은 정수이고, 가리키는 주소에 가면 int데이터가 있음.
PC = &ch;
PD = &d;
PI = &i;
즉 포인터 변수를 선언할 때 쓰이는 앞의 데이터형은 포인터 변수가 가리키는 곳의 값의 데이터 형이다.
만약 64비트 컴터라면 8바이트
만약 32비트 컴터라면 4바이트

int i = 10;
int *P;
int P = &i; //i 변수의 주소 대입
//int *P = &i; 로 23을 줄여서 쓸 수 있다.

ppt자료의 포인터 선언 및 값 설정 빈칸 부분
int i = 10; 
int *p; // 정수형 포인터 
p = &i; // 한번에 int *p = &i; 라고 선언 및 초기화해도 된다.
i의 주소가 0x200라고 가정하자.

i와 p는 서로 같은 값을 가지는 것이다.
p의 값은 0x200
*p의 값은 10 //P가 가리키는 자리에 들어있는 값. 간접적으로 10을 가리킴.
p* = 20; 이라면 i도 20으로 바뀐다. //P가 가리키는 자리에 들어있는 값을 바꾸라는 것.
p++; //P는 정수형 포인터 변수였으므로, +4만큼 건너뛰어 진다. 그러므로 0x204이 됨. 만약 double 형이었다면 0x208이 된다. 즉, 자료형의 크기만큼 증가한다. => 배열일 때 자주 쓰인다.

배열명은 주소를 갖는 상수(바꿀 수 없음)이고, 포인터는 주소를 갖는 변수이다.
int i = 10;
int a[3];
int b[3] = { 1, 2, 3 };
int *P;

P = &i; //가능함
a = b;; //불가능함.
//배열에 들어있는 값을 바꿀 수는있지만, 배열 자체를 대입연산으로 가질 수는 없다.
//배열의 이름은 배열 첫번째 원소의 주소값을 나타내는 포인터 상수 

int array[3] = {10, 20, 30}; 
int *p = array; //포인터 P는 array의 주소를 값을 가질 수 있다.
array는 0x100이라 하면 P는 배열의 첫 번째 주소만 갖는다. P가 3칸을 갖는 것이 아님.
array 10 20 30 / p 0x100

// 예제 A) 
printf("%d\n", *P); //10이 출력 P는0x100
p++; 
printf("%d\n", *P); //20이 출력 P는0x104
p++; 
printf("%d\n", *P); //30이 출력 P는0x108
p++; //P는 0x112
printf("%d\n", *P); //쓰레기값이 출력

예제 B)
for(int i = 0; i < 3; i++) {
printf("%d\n", *p);
p++;
}

예제 C) 
for(int i = 0; i < 3; i++)
printf("%d", *(P + i));
//P[0]은 10 P[1]은 20 P[3]은 30 => P의 값은 0X100으로 고정되어 있다

예제D) 포인터 이름을 배열명으로 표현가능 =>포인터는 배열 같은 개념으로 사용 가능
for(int i = 0; i < 3; i++)
printf("%d", p[i]);
//P[0]은 10 P[1]은 20 P[3]은 30 => P의 값은 0X100으로 고정되어 있다


포인터 변수인 p는 마치 배열의 이름처럼 쓰일 수있다.
[값]
*(p + i) 는 P[i]와 array[i]와 *(array + i)로 쓸 수 있다 //배열은 비교 대입 등등만 안되는 거지 포인터 주소값처럼 쓰일 수는 있따.

[주소]
p + i 는 &p[i]와 &array[i]와 array = i //array 자체가 주소이므로


 more 포인터 연산: *p++ vs. (*p)++ 
array의 주소가 0x100이라면
*p++ 은 p의 주소 값이 +4 돼서 배열의 두 번째 값을 가리키게 된다.
//p의 주소값이 0x104. p가 가리키는 것은 data[1]의 20
(*p)++ 은 p가 가리키는 배열의 값이 +1 돼서 10이 11로 변경된다.
//p의 주소값이 0x100 p가 가리키는 것은 data[0]의 11


 int data[5] = {10, 20, 30, 40, 50}; 
 int *p = data; 
 
 printf("%d %u %p\n\n", p, p, p); //A) //%u는 unsigned 이고, %p 주소 값
 
 printf("%d %d\n", p, *p);  //p는 주소값, *p는 10
 printf("%d\n", *p++);  //*p++는 *p의 값을 먼저 출력후 (data[0]) *p의 주소를 ++ 하는 것.(후위연산이기 때문)
 printf("%d %d\n\n", p, *p); //p처음의 주소값에서 +4된 값과 data[1]인 20이 출력
 
 p = data; // 다시 첫 번째 요소를 가리키게 한 후 p=&data가 아닌 이유는 data 자체가 첫 번째 자리의 주소를 가리키는 것이기 때문.
 printf("%d %d\n", p, *p); //p는 주소값, *p는 10
 printf("%d\n", (*p)++);  //*p를 먼저 출력 후 (data[0]=10), data[0]의 값인 10을 +1 함.
 printf("%d %d\n", p, *p); //p는 처음과 똑같고 data[0]인 11이 출력됨.
}

※연산자 우선순위 
단항연산자는 결합순서가 오른쪽에서 왼쪽으로 간다
a = b = 3 은 3인 b에 b가 a에 대입됨.
논리연산자도 &&가 먼저이고 ||가 다음이다.





































'C언어' 카테고리의 다른 글

컴프 9주차 요약  (0) 2023.11.04
컴프 10주차  (0) 2023.11.04
6주차 복습  (0) 2023.10.10
컴프 6주차 1차시  (0) 2023.10.07
변수  (0) 2023.09.23