* 포인터

ChoRong0824·2022년 9월 22일
1

필자는 군대 다녀온 후 c언어를 포맷해버렸기 때문에, 시스템 프로그램을 학습하기 위해서는 c의 기본이자 핵심인 포인터를 따로 학습하며 기억하려고 이렇게 포스팅 하게 되었습니다.

(참고)필자가 누차 적는 데엔 그만큼 중요해서 아는 것은 더욱 확실하게 외워두고, 모르는 것은 적으면서 외우려고 하는 것입니다.
百聞而不如一作 == 백문이 불여일타

포인터

메모리에 존재하는 데이터의 주소값을 가짐

  • 주소를 가지고 주소로 접근
    (명사적의미 : 점, 동사 : 가리키다)
  • 가리키는 녀석. 데이터, 즉 메모리 주소를 갖는다.


변수와 메모리

자료형에 따라 할당된 메모리 공간의 크기가 다름

  • char형 : 1byte,             - int 형 : 4byte
  • float형 : 4byte,             - double형 : 8byte
int main(void)
{
	int i = 10;
    char c = 69;
    float f = 12.3;
}



변수의 주소

주소 연산자(&)

  • 변수의 메모리 주소를 가져옴
  • 예) &i=4, &c=8, &f =12
    => &뒤에 i는 얘의 메모리 주소를 가져온다고 생각.(시작 주소를 출력해준다고 보면 됌)


포인터 선언

포인터 변수의 선언

(참고로 포인트 변수는 4바이트 정수)


간접 참조 연산자

간접 참조 연산자 (*)

  • 포인터 변수가 가리키는 주소에 저장된 데이터를 가져옴
int i= 10;
int*p;

p= &i;
printf("*p= %d\n", *p);

(역시 C는 어렵다. 역시 포인터다. 그치만 해야만한다....)

& 연산자와 * 연산자

& 연산자

지정된 변수의 메모리 주소를 구함 : p = &i

* 연산자

포인터 변수가 가리키는 위치의 데이터를 읽어옴 (간접 참조) :*P



예) & 연산자와 * 연산자의 활용 (paddress.c)

#include <stdio.g>

int main(void)
{
	int i = 10;
    int *p;
    
    p= &i;
    printf("i= %d\n", i);
    *p =20; //주소로 접근
    printf("i= %d\n", i);
    
    return 0;
}



포인터와 배열

배열과 포인터는 밀접한 관계를 가짐

배열이름 : 배열의 시작 주소 (= 포인터 상수)

포인터를 배열처럼 사용할 수 있음

변수와 상수의 차이는 ? (나의생각)
변수란 네모난 박스 안에 집어 넣는, 공간을 만들어서 넣는, 즉 가변성 있다.
상수는 정해진 일정한 값. Int i= 10; 이렇게

예 1) 포인터와 배열의 관계 (parray1.c)

#include <stdio.h>

int main(void)
{
	int a[]= {10,20,30,40,50};
    
    printf("a=%p\n",a); // %p는 주소출력임
    printf("a + 1 = %p\n", a+1);//+1을 하면 자료형의 크기만큼 옮겨짐(자료형은 4바이트)
   	printf("*a= %d\n", *a);
    printf("*(a+1) = %d\n", *(a+1));
    
    return 0;
}

  • 참고로 포인트(변수)는 바뀌어도 주소는 변하지 x

예 2) 포인터를 배열 이름처럼 사용 (parray2.c)

#include <stdio.h>

int main(void)
{
	int a[3]={10,20,30};
    int *p; //정수 값 가리키는 포인트
    
    p = a;
    printf("a[0] =%d, a[1] = %d, a[2] = %d\n", a[0], a[1], a[2]);
    printf("p[0] =%d, p[1] = %d, p[2] = %d\n", p[0], p[1], p[2]);
    return 0;
}

main 함수의 인수

프로그램 시작 시 외부 입력이 없는 main 함수의 형태

int main(void)
{
	...
};

프로그램 시작 시 외부 입력을 받는 main 함수의 형태

int main (int argc, char *argv[])
{
...
};

이 두개는 동일하며, 배열 = 포인터로 교체 가능.
char * argv[];
char ** argv;

또한, 외부에서 입력받는 int argc, char argv[])의 char argv[] 는
1. ls 만으로는 안돼서
2. ls -l 이나
3. ls -l/usr

  • argc : 명렁어 행에 존재하는 인수(인자)들의 개수
  • argv : 인수들의 시작 주소를 갖는 포인터 배열

mycopy src dst => 인자의 갯수 3개, 1번 mycopy 2번 src 3번 dst

예) 명령어 행의 인수(Command line arguments) 활용

#include <stdio.h>

int main(int argc, char *argv[])
{
	int i;
    
    for(i = 0; i < argc; i++)
    	printf("argv[%d] = %s\n", i, argv[i]);
        
	return 0;
}


이중 포인터 (Double pointer)

포인터

  • 다른 변수의 메모리 주소값을 가지고 있음

이중(이차) 포인터

  • 포인터를 가리키는 포인터 : 다른 포인터의 주소값을 가짐
int i = 10;  // i : 정수형 변수
int *p = &i;  // p : 변수 i를 가리키는 포인터
int **q = &p; // q : 포인터 p를 가리키는 포인터



이중 포인터의 의미

예) 이중 포인터의 활용 (dpointer.c)

#include <stdio.h>

int main(void)
{
	int i = 100;
    int *p = &i;
    int **q = &p;
    
    *p = 200;
    printf("i=%d *p = %d **q = %d\n", i, *p, **q);
    **q = 300;
    printf("i= %d *p =%d **q =%d\n", i. *p, **q);
    return 0;
}


(결과 값)
i = 200, p = 200, **q = 200
i = 300,
p = 300, **q = 300


포인터 배열

포인터 배열(An array of pointers)

배열의 원소가 포인터


2차원 배열 : 과일 이름을 저장

char fruits[4][10] = {
	"apple","bluberry","orange","melon"};



대안 : 포인터 배열의 활용 (공간 낭비 해결)

char *fruits[] = {		// 문자형 포인터 배열 
	"apple","bluberry","orange","melon"};



예) 문자형 포인터 배열의 활용 (fruits.c)

#include <stdio.h>

int main(void)
{
	int i;
    char *fruits[4] ={"apple","bluberry","orange","melon"};
    
    for(i=0; i<4; i++)
    	printf("fruits[%d] = %s\n", i, fruits[i]);
	return 0;
}
  • %s 는 문자열로 인식

다차원 배열과 포인터

2차원 정수형 배열 : int m[3][3]

  • 데이터의 메모리 저장 순서 : 행 우선(row-major) 방법 적용

2차원 배열 이름 (= &m[0][0])

  • m[0] : 1 행의 시작 주소
  • m[1] : 2 행의 시작 주소
  • m[2] : 3 행의 시작 주소


예) 2차원 배열과 포인터 (2dpointer.c)

#include <stdio.h>

int main(void)
{
	int m[3][3] = {10,20,30,40,50,60,70,80,90};
    
    printf("&m[0][0] = %p\n", &m[0][0]);
    printf("&m[1][0] = %p\n", &m[1][0]);
    printf("&m[2][0] = %p\n", &m[2][0]);
    printf("m[0] = %p\n", m[0]);
    printf("m[1] = %p\n", m[1]);
    printf("m[2] = %p\n", m[2]);
    printf("m = %p\n" , m);
    
    return 0;
}




포인터란,

+1, -1 코드를 작성할 때, 단순히 연산하는 +,-가 아니라 인덱스 배열의 크기만큼 +,- 한다는 의미입니다.
또한, 포인터의 해석은
1) 한 행을 볼 것인지 2) 한 행(구간) 별 원소 개수를 볼 것인지
로 나뉩니다.

다차원 배열에서의 포인터 연산

다차원 배열에서도 포인터에 대한 덧셈/뺄셈 연산이 가능

예) 이차원 배열 m[3][3]

  • m+1 = ?, m+2 = ?

Const 포인터

const 포인터

포인터 변수 p가 가리키는 대상의 내용을 변경하지 못함

  • const 는 constant 라고 불리는 상수입니다.
    (상수로 바뀌어서 가리키는 대상은 바꾸지만, 내용은 못바꿉니다)

참고로, 쉘 프로그래밍에서 readonly 를 사용하면, 뒤에 변수가 상수가 됩니다.
(변수의 상수화 라고 합니다)

예) const 포인터의 활용 (constp.c)

#include <stdio.h>

int main(void)
{
	char s[] = "Barking dogs seldom bite.";
    const char *p = s;
    
    printf("p = %s\n", p);
    p[3] = 'a';						//p가 가리키는 곳의 내용을 변경하지 못함.
    printf("p = %s\n", p);
    return 0;
}

이대로 컴파일하게 된다면 실행되지않습니다. 왜냐하면 p[3] ='a'; 이 부분 때문입니다. p[3] ='a' 을 빼게 된다면 정상 작동하는 것을 확인할 수 있습니다 (참고)

profile
컴퓨터공학과에 재학중이며, 백엔드를 지향하고 있습니다. 많이 부족하지만 열심히 노력해서 실력을 갈고 닦겠습니다. 부족하고 틀린 부분이 있을 수도 있지만 이쁘게 봐주시면 감사하겠습니다. 틀린 부분은 댓글 남겨주시면 제가 따로 학습 및 자료를 찾아봐서 제 것으로 만들도록 하겠습니다. 귀중한 시간 방문해주셔서 감사합니다.

0개의 댓글