Programming

[C언어] 포인터

아나엘 2022. 11. 9. 17:33
Pointer

주소를 가지고 있는 변수

     

메모리의 구조
  • 변수는 메모리에 저장된다. 
  • 메모리는 바이트 단위로 액세스됨.( 첫번째 바이트의 주소는 0, 두번째 바이트는 1,..)
  • 변수의 크기에 따라 차지하는 메모리 공간이 달라짐
  • char 형 변수: 1바이트, int형 변수: 4바이트, float형 변수 : 4바이트
  • 변수의 주소를 계산하는 연산자: & (&i -> 4, &c -> 8, ..; 시작점)
포인터의 선언 및 변수와의 연결
int i = 10;
int *p;
p = &i;
다양한 포인터의 선언
char c = 'A';
float f = 36.5;
double d = 3.141592;

char *pc = &c;   //문자를 가리키는 포인터 pc
float *pf = *f;  //실수를 가리키는 포인터 pc
double *pd = &d; //실수를 가리키는 포인터 pc
간접 참조 연산자 *

포인터가 가리키는 값을 가져오는 연산자(&가 주소를 반환한다면,...)

int i =10;
int *p;
p = &i;
printf("%d", *p);

예제#1
#include <stdio.h>

int main(void){
	int i = 3000;
    int *p = &i;
    
    printf("&i = %u\n", &i); //변수의 주소 출력
    printf("i = %d\n", i);   //변수의 값 출력 
    
    printf("*p = %d\n", *p); //포인터를 통한 간접 참조 값 출력
    printf("p = %u\n", p);   //포인터의 값 출력
    
    return 0;
}

# result
# &i = 1245024
# i = 3000
# *p = 3000  //포인터가 가리키는 값. 간접참조.. 이걸 통해 변수의 값도 변경이 가능함
# p = 1245024

초기화가 안 된 포인터를 사용하면 안 됨. 즉 바로 *p=100 이렇게 쓰면 안 되고, int *p   p = &i 이 이후에 사용 가능. 만약 아무것도 가리키고있지 않다면 NULL로 초기화. 

또한 포인터의 타입과 변수의 타입도 일치해야 함.

 

포인터 연산
  • 가능한 연산: 증가, 감소, 덧셈, 뺄셈
  • 증가연산: 증가되는 값은 포인터가 가리키는 객체의 크기임. 
  • p++-> char, int, ... 에 따라 증가되는 값이 다름.

간접 참조 연산자와 증감 연산자
  • *p++;
    • p가 가리키는 위치에서 값을 가져온 후, p를 증가시킨다. 즉 p가 가리키는 값을 v에 대입한 후 p를 증가시킴
  • (*p)++;
    • (p가 가리키는 위치의 값)을 증가시킨다.
  • *++p;
    • p를 증가시킨 후 p가 가리키는 값을 v에 대입.
  • ++*p;
    • p가 가리키는 값을 가져온 후 그 값을 증가하여 v에 대입. 
포인터의 형변환

꼭 필요한 경우 명시적으로 포인터의 타입을 변경할 수 있다.

double *pd = &f;
int *pi;
pi = (int *)pd;
포인터와 배열
  • 배열과 포인터는 아주 밀접한 관계임.
  • 배열 이름이 바로 포인터임
  • 포인터는 배열처럼 사용 가능.
  • (이해 안 되기 시작)
  • 인덱스 표기법을 포인터에 사용 가능.
#include <stdio.h>

int main(void){
	int a[] = { 10, 20, 30, 40, 50};
    
    printf("&a[0] = %u\n", &a[0]);
    printf("&a[1] = %u\n", &a[1]);
    printf("&a[2] = %u\n", &a[2]);
    
    printf("a = %u\n", a);
    
    return 0;
}

#include <stdio.h>
int main(void) {
	int a[] = {10,20,30,40,50};
    
    printf("a = %u\n",a);
    printf("a + 1 = %u\n", a+1);
    printf("*a = %d\n",*a);
    printf("(a+1) = %d\n",*(a+1));
    
    return 0;
}

#a = 1245008
#a+1 = 1245012
#*a = 10
#*(a+1) = 20

포인터를 배열처럼 사용.. 배열은 결국 포인터로 구현된다. 또 포인터를 통해 배열 원소를 변경 가능.

 

포인터를 사용한 방법의 장점

포인터가 인덱스 표기법보다 빠릅.

왜냐? 인덱스를 주소로 변환할 필요가 없기 때문. 

sum += a[i]; 대신 sum += *p++;

 

영상처리에 활용해보쟈

디지털 이미지는 배열을 사용해 저장되는데,,, 속도를 빠르게하기위해 포인터를 사용한다! 그래서 빠르구나

이미지 내의 모든 픽셀의 값을 10씩 증가시키는 예제

 

#include <stdio.h>
#define SIZE 5
void print_image(int image[][SIZE]) {
	int r,c;
    for(r=0;r<SIZE;r++){
    	for(c=0;c<SIZE;c++){
        	printf("%03d", image[r][c]);
        }
        printf("\n");
    }
    printf("\n";
}

void brighten_image(int image[][SIZE]) {
	int r, c;
    int *p;
    p = &image[0][0];
    for(r=0;r<SIZE;r++){
    	for(c=0;c<SIZE;c++){
        	*p += 10;
            p++; //포인터닷
        }
    }
}

int main(void){
	int image[5][5] = {
    	{10,20,30,40,50},
        {10,20,30,40,50},
        {10,20,30,40,50},
        {10,20,30,40,50},
        {10,20,30,40,50},
        {10,20,30,40,50}};
    print_image(image);
    brighten_image(image);
    print_image(image);
    return 0;
}
인수 전달 방법

함수 호출 시에 인수 전달 방법

  • 값에 의한 호출( call by value): 함수 호출 시 변수의 값을 전달해주는 것. 값만을 복사
  • 참조에 의한 호출(call by reference): 포인터를 이용하여 흉내낼 수 있다. 변수의 주소를 함수의 매개 변수로 전달.
  • swap() 함수(call by value): 변수 두 개의 값을 바꾸는 작업을 함수로 작성
#call by value 방식: 값만 복사

#include <stdio.h>
void swap(int x, int y);
int main(void){
	int a = 100;, b = 200;
    
    swap(a,b);
    return 0;
}

void swap(int x, int y){
	int tmp;
    
    tmp = x;
    x = y;
    y = tmp;
}
#포인터를 이용

#include <stdio.h>
void swap(int x, int y);
int main(void){
	int a = 100, b = 200;
    swap(&a, &b);
    
    return 0;
}

void swap(int *px, int *py){
	int tmp;
    
    tmp = *px;
    *px = *py;
    *py = tmp;
    
}

제일 이해 안됨

scanf()함수

변수에 값을 저장하기 위해 변수의 주소를 받음

? 주소를 받는다......값을 저장..아!알았다

#include <stdio.h>
//기울기와 y절편 계산
int get_line_param(int x1, int y1, int x2, int y2, float *slope, float *yintercept){
	if(x1==x2)
    	return -1;
    else{
    	*slope = (float)(y2-y1)/(float)(x2-x1);
        *yintercept = y1 -(*slope)*x1; //이걸 반대로 밖으로 전달해주는구만!!!!!!
        return 0;
    }
}
int main(void){
	float s, y; //일단 변수를 주고
    if(get_line_parameter(3,3,6,6,&s,&y)==-1)
    	print("에러\n");
    else
    	printf("기울기는 %f, y절편은 %f\n", s,y);
    return 0;
}
배열 매개 변수
  • 일반 매개 변수: 매개변수 x에 기억 장소가 할당됨.
  • 배열 매개 변수: b에 기억 장소가 할당되지 않음. 왜냐하면 배열을 함수로 복사하려면 시간 오래걸림.

 

화물이 너무 크면 화물 전체를 x, 주소만 전달하는 수 밖에..

포인터 반환 시 주의점
  • 함수가 종료되더라도 남아있는 변수의 주소를 반환해야 함.
  • 지역 변수의 주소를 반환하면, 함수가 종료되면 사라지기 때문에 오류가 난다.

오? 그러면.. 함수 종료되면서 result는 사라지니까 그럼 우째

반응형