티스토리 뷰
C언어 다차원 포인터
C언어 다차원 포인터에 대해 Do it! C언어 입문(저자:김성엽) 이란 책을 통해 공부했으며, 책의 카테고리를 바탕으로 필자가 이해한 내용을 요약한 글이다. 내용이 궁금하거나 찾아야 할 내용이 있으면, 필자가 정리한 글을 다시 보면서 복습하기위해 작성했다. 바로 아래에서 글을 확인하도록 하자.
다차원 포인터
간접으로 여러 번 가리키는 포인터를 '다차원 포인터'라고 부름. 차원은 '자신이 가리키는 대상'의 개수만큼 증가함.
short *p, data =5;
p=&data;
/*포인터 변수 p는 data변수 하나를 가리키니 1차원,
data는 가리키는곳이 없으니, 0차원 */
*키워드를 두 개 이상 사용하면 '다차원 포인터'가 됨. *키워드는 최대 7개까지 사용 가능함(컴파일러마다 다름).
char *p1; /* 1차원 포인터 : p1, *p1 사용가능 */
char **p2; /* 2차원 포인터 : p2, *p2, **p2 사용 가능 */
char ***p3; /* 3차원 포인터 : p3,*p3,**p3,***p3 사용 가능 */
일반 변수의 한계와 다차원 포인터
short data = 0;
int my_ptr = (int)&data; /* 주소값 크기인 4바이트를 가진 변수가 주소를 저장할 수는 있음 */
*my_ptr = 3; /* 하지만 이 주소값으로 할 수 있는게 없어서 의미가 없음.
포인터 변수가 아니라 *키워드 못사용함.*/
2차원 포인터
2차원 포인터를 이해한다면, 3차원 포인터는 주소 하나를 더 저장하는거 뿐이니, 2차원 포인터만 이해하면 됨.
short **pp;
이렇게 선언하면 아까 말했듯이, pp,*pp,**pp 3개를 사용 할 수 있음. **pp를 쓴다는 것은 pp에 또 다른 메모리의 주소를 가리킨다는 것이어서, *pp에도 주소 값이 들어가야 함. 그러니까 포인터 변수 pp에 4바이트의 A라는 공간의 주소를 가지고 있다면, *pp는 A라는 공간을 가리키고, ★★ *pp(A라는 메모리 공간)에도 어떤 메모리의 주소를 가지고 있어야, **pp를 사용할 수 있게 됨.( A라는 공간은 무조건 포인터일 필요가 없음 B라는 공간의 주소만 가지고 있으면 **pp를 사용했을 때 가리킬 수 있음).
※A라는 공간에 B공간의 주소가 아니라 그냥 숫자 상수나 문자 상수를 넣었을 때, 그걸 주소로 해석하고 프로그램 밖에 있는 메모리를 가리킬 수 있어서 오류가 일어남.
#include <stdio.h>
void main()
{
short data =3;
short *p =&data;
short **pp= &p;
printf("[Before ] data : &d\n", data);
*p=4; /* p에 data의 주소가 있으니, *p는 데이타를 가리킴 */
printf("[Use *p ] data : %d\n", data);
**pp=5; /*pp에 p의 주소가 있으니 **pp는 p가 가지고 있는 주소 공간을 가리킴 */
printf("[Use **pp] data : %d\n", data);
}
/* 결과 화면
[Before ] data : 3
[Use *p ] data : 4
[use **pp] data : 5 */
1차원 포인터 변수에 1차원 포인터 변수의 주소를 저장하면?
int *q, *p, data = 3;
p = &data;
q = (int *)&p; /* p의 주소는 (int **)형으로 반환돼서 형변환을 해줘야함 */
/* 이렇게하면 **q형식을 못쓰고 data는 무조건 *p로 밖에 못가리킴.
q가 p의 주소를 가지고 있는게 의미가없음.*/
2차원 포인터가 가리키는 대상을 동적으로 할당하기
short **pp, data =3;
pp = (short **)malloc(4); /* 포인터 변수 pp은 가리키는 첫번째 대상이 주소를 담을 수 있는
4바이트이기만 하면 두번째 대상을 가리킬 수있으니,
동적으로 할당해도됨. */
*pp = &data;
**pp=5;
동적으로 할당된 공간이 * 연산자를 사용해서 직접 data를 가리키지는 못하지만 pp로 data의 주소를 넘겼기 때문에 **pp를 통해 data를 가리킬 수 있음. 그러므로 아래처럼 표현하면 의미를 잘 표현할 수 있음.
pp=(short **)malloc(sizeof(short *)); /* (short *)은 포인터이기 때문에 크기가 4임.
이렇게 쓰면 동적으로 할당된 공간이 어떤의미로
만들어젔는지 보여주므로 더 좋을 수 있음 */
그래서 위와 같이 표현한것을 '1차원 포인터 한 개를 동적 할당한다.'라고 이야기함.
#include <stdio.h>
#include <malloc.h>
void main()
{
short **pp;
pp=(short **)malloc(sizeof(short *)); /* pp에 첫번째 4바이트 공간의 주소를 넘김 */
*pp=(short *)malloc(sizeof(short)); /* 첫번째 공간에 2바이트인 2번째 공간의 주소를 넘김 */
**pp = 10; /* 2번째 2바이트 공간에 10을 대입함 */
printf("**pp : %d\n", **pp);
free(*pp); /* 순서에 유의해야함.
free(pp);를 먼저하면 *pp의 주소를 찾지못해,
동적할당된 메모리 해제 불가능*/
free(pp);
}
/*결과 화면
**pp : 10 */
2차원 포인터가 가리키는 대상을 동적으로 할당하면 좋은점
short **pp = (short **)malloc(3 * sizeof(short*));
/* 12바이트 (4바이트 공간 3개)를 할당함 */
A 공간에 4바이트, A1 공간에 4바이트, A2 공간에 4바이트 주소를 담을 수 있는 공간이 3개인 셈임.
각 공간의 주소를 접근하는 방법은 *(pp+0), *(pp+1), *(pp+2) 임.
*pp = (short *)malloc(2 * sizeof(short));
/* *pp (A)라는 공간에 또다시 동적 할당을 해서
2개의 정수를 저장할 수 있음 */
첫 번째 정수 값을 저장할 때는 *(*pp+0) 또는 **pp , 두 번째 정수 값을 저장할 때는 **pp+1을 사용하면 됨.
이런 식으로 두 번째 공간, 세 번째 공간을 동적 할당을 하면 2차원 배열과 비슷한 형식의 메모리를 구성할 수 있음.
배열은 행의 개수나 열의 개수가 변경이 되면 반드시 컴파일을 다시 해야 하는데 2차원 포인터를 이용하면 프로그램을 실행하면서 메모리 크기를 바꿀 수 있어서 매우 유용함.
유의사항
#include <stdio.h>
void GetMyData(int *q)
{
q=(int *)malloc(8); /* q라는 포인터 변수에 메모리를 할당해줌.
하지만 GetMyData 함수가 사라질때,
q라는 변수는 사라지므로 메모리가 손실남 */
}
void main()
{
int *p;
GetMyData(p); /*p의 주소를 보낸게 아님 */
*p=5; /* p에는 쓰레기 주소값이 들어가있는데,
거기에 5를 대입하면 프로그램 밖의 메모리를 사용할 수도있음.
높은 확률로 오류! */
free(p); /* p라는 변수에 동적할당 된적이 없음. 이것도 오류 요소임 */
}
#include <malloc.h>
/* 난 처음에 *q로 받으면 되겠다고 생각했는데
1차원 포인터의 주소는 2차원형태로 반환돼서 형변환을 해줘야하니,
2차원 포인터로 주소를 받는게 맞음*/
void GetMyData(int **q)
{
*q=(int *)malloc(8);
}
void main()
{
int *p;
GetMyData(&p);
*p =5; /* 이렇게하면 8바이트의 공간중, 4바이트에 5를 넣는거임. 오류 x */
free(p); /* 포인터 변수 p에 동적메모리 할당했으니, 오류 x */
}
여러 개의 1차원 포인터(첫 번째 공간)를 동적 할당하기
int n;
short **pp;
scanf("%d", &n);
pp = (short **)malloc(sizeof(short *) * n);
/* 동적메모리 할당할때는 크기를 변수로 지정해도됨.
이렇게 선언하면, 4바이트 공간을 n개 선언가능.
원하는대로 숫자를 입력해서
공간의 수(포인터 역할을 하는 공간) 를 만들 수 있음 */
각 공간의 주소를 참조하려면 *(pp+n-1)을 이용하면 됨.
이렇게 하면 2차원 배열을 사용하는 거 보단, 코드는 조금 복잡할 수는 있어도, 메모리 효율을 극대화할 수 있음.
배열은 한번 선언하고 나서 수정을 하려면 프로그램을 다시 만들어야 해서 낭비가 있는 채로 사용하거나, 메모리가 부족하면 못 사용할 수 있는데, 동적 메모리로 할당하면 프로그램이 실행되면서 수정이 가능함.
활용
#include <stdio.h>
#include <malloc.h>
void main()
{
unsigned char *p_limit_table;
unsigned char **p;
int age, age_step, member, temp, sum;
printf("20대부터 시작해서 연령층이 몇 개인가요 : ");
scanf("%d", &age_step);
p_limit_table = (unsigned char*)malloc(age_step);
p=(unsigned char **)malloc(sizeof(unsigned char *) * age_step);
for(age =0; age< age_step; age++){
printf("\n%d0대 연령의 윗몸 일으키기 횟수\n", age+2);
printf("이 연령대는 몇 명입니까? : ");
scanf("%d",&temp);
*(p_limit_table + age) = (unsigned char) temp;
*(p + age) = (unsigned char *)malloc(*(p_limit_table + age));
for(member = 0; member < *(p_limit_table +age); member++){
printf("%dth : ", member +1);
scanf("%d",&temp);
*(*(p + age) + member) = (unsigned char) temp;
}
}
printf("\n\n연령별 평균 윗몸 일으키기 횟수\n");
for(age=0;age<age_step;age++){
sum=0;
printf("%d0대 : ", age +2);
for(member = 0; member < *(p_limit_table + age); member++){
sum = sum + *(*(p+age)+member);
}
printf("%5.2f\n", (double)sum/ *(p_limit_table+age));
free(*(p+age));
}
free(p);
free(p_limit_table);
}
/* 결과 화면
20대부터 시작해서 연령층이 몇 개인가요 : 3
20대 연령의 윗몸 일으키기 횟수
이 연령대는 몇 명입니까? : 4
1th : 55
2th : 51
3th : 63
4th : 59
30대 연령의 윗몸 일으키기 횟수
이 연령대는 몇 명입니까? : 2
1th : 43
2th : 40
40대 연령의 윗몸 일으키기 횟수
이 연령대는 몇 명입니까? : 3
1th : 41
2th : 35
3th : 38
연령별 평균 윗몸 일으키키 횟수
20대 : 57.00
30대 : 41.50
40대 : 38
*/
글을 마음대로 배포하셔도 되지만, 출처(링크)는 반드시 남겨주시기 바랍니다.
'C언어' 카테고리의 다른 글
C언어 동적 메모리 할당 (0) | 2021.03.15 |
---|---|
C언어 정적 메모리할당 (0) | 2021.03.15 |
C언어 배열과 포인터 (0) | 2021.03.15 |
C언어 표준 입력 함수 (0) | 2021.03.15 |
C언어 포인터 (0) | 2021.03.14 |
- Total
- Today
- Yesterday
- C언어malloc함수
- PHP이스케이프
- HTML태그사용법
- PHP문자열연결연산자
- C언어2차원포인터
- PHP이스케이핑
- PHP큰따옴표작은따옴표차이점
- PHPescaping
- C언어malloc
- PHP작은따옴표역할
- C언어정적메모리할당
- C언어다차원포인터
- htmlTag
- C언어프로세스
- 무효트래픽이의신청
- html이미지
- HTMLbestTag
- PHPescapecharacter
- PHPhere문서
- C언어동적메모리할당
- 이미지무료다운로드사이트
- PHP큰따옴표
- HTMLtag사용법
- PHP'
- PHP작은따옴표
- PHP"'
- PHP마침표
- PHP'"
- html이미지넣기
- 무효클릭신고양식
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |