2013년 3월 2일 토요일

일반 포인터와 다중 포인터(삼중 까지)

이번 포스트는 다중포인터 즉, 이중과 삼중포인터에 대해 다룰껀데요.

포인터가 뭔지 모르거나 헷갈리는분들은 링크를 달고 싶지만 이상하게 포인터에 대한 내용을 안 다뤘네요.

그러므로 포인터부터 시작하겠습니다.

1.포인터

포인터는 변수와 달리 방향을 가지고 있습니다.

포인터는 어떤 변수를 가리키는 함수인데, 가리킨 변수의 주소값에 저장을 목적으로 선언 됩니다.

일단 일반포인터에 대해 맛보자면,

ex)
int t=1;
int *t1=t;  // 포인터는 변수앞에 *을 붙입니다.

*t1+=1;
printf("%d",t);

결과는 2가 나옵니다. 즉, 포인터를 더해도 포인터가 가리키는 변수도 바뀝니다.

그러니까 포인터가 가리키는 주소에 1을 더해라!라는 명령을 하였고, 컴파일러는 ㅇㅇ이라는 해석을 한거죠.

포인터도 연산을 하는데 그건 링크를 달아드릴게요.
포인터 연산!

이상하게 포인터연산은 포스팅했는데 포인터는 안했네요.

아무튼 이중 혹은 더블포인터로 넘어 갈게요.

2.이중포인터

일반포인터는 *하나를 이중포인터는 **로 선언합니다.

이중포인터는 일반포인터를 가리키는건데요.

즉, 그러니까 일반포인터가 어떤변수를 가리키고 그 포인터를 이중포인터가 가리키는거죠.

생각해보면 별거 아닙니다.

선언한 숫자를 바꿔주는 프로그램으로 왜 이중포인터가 필요한지 알아보겠습니다.

우선 실패작
보시면 결과는 실패입니다.

왜일까요?

네, 바로 제가 주석처리한 문장이 답입니다.


*t와 *t1은 *pt와 *pt1과 같은 일반포인터이므로 누가 누굴 가르키기는 커녕 전혀 무관합니다.

그래서 SWAPPING 프로그램의 t,t1끼리만 바꾸고 pt까진 바꿔주지못하고 출력해버린겁니다.

그림으로 설명하자면

SWAPPING 대입할 때 상황
* pt ㅡ>(대입)  *t(참조)→t                          
*pt1 ㅡ>(대입)*t1(참조)→t1

SWAPPING 대입하고 해석 상황
*pt ㅡ> *t  ㅡ>t1
           ↑↓
*pt1ㅡ>*t1 ㅡ>t

이렇게 되는겁니다.


그럼 SWAPPING프로그램에다가 이중으로 바꿔준다면? 방향은 바뀌게 될 건데, 실험으로 알아보겠습니다.


이번엔 성공!

왜 성공한줄은 아시겠나요?


모르시겠다면 그림으로 상황설명을 하겠습니다.

스와핑함수에 대입상황

**t ㅡ> *pt ㅡ> t
**t1ㅡ>*pt1 ㅡ>t1

대입 후 함수 해석상황

**t   ㅡ>*pt↘t
**t1ㅡ>*pt1↗t1

그니깐 스와핑함수의 이중포인트 두개는 메인함수의 일반포인터를 계속 가리키고있고 이중포인터가 가리키는 것을 서로 바꿧으므로 이중포인터가 가르키는것도 바뀌기 때문입니다.

처음 실험 때와 차이를 묻는다면, 스와핑함수안에 포인터함수들의 가리키는 방향에 차이입니다.

그러니까 처음실험때는 스와핑안에 포인터들은 자기들끼리 바꾸고 메인함수의 포인터들까지는 바꾸지 못 한것이고, 두 번째 실험엔 이중포인터가 일반포인터를 가리키므로 일반포인터채로 바꿔버린겁니다.

이중포인터는 서로 다른 함수끼리의 변수주소이동에 정말 유용하게 쓰입니다.

그럼 삼중포인터로 넘어가겠습니다.

3.삼중포인터

긴말 안하고 방향이 삼중ㅡ>이중ㅡ>일반포인터 의 순서대로라고만 설명하고 포스트를 마치겠습니다.

참고로 삼중포인터는 *** t로 선언합니다.

다차원 배열에 대해서(3차까지.)

안녕하세요.
새내기 tender입니다. 정말 오랜만에 글 써보는데요.

그래서 쉬운 포스트부터 시작할 것이구요.

그리하여 이번 포스트에선 2차 3차 배열에대해 다룰껍니다.

별로 다른건 없구요. 수학으로 빗대자면 1차배열(여태사용한 배열 물론 이 블로그에서)은 직선, 2차배열은 가로세로의 길이가있는 평면도형, 3차배열은 가로세로높이의 길이가 있는 공간도형이라고 표현할 수가 있습니다.

혹시나 배열에 대해 모르시는 분들을 위해 링크를 걸어두겠습니다.
C언어에서 배열을 해보자!
배열은 포인터다!

지금도 C언어에대해 그렇게 잘 아는것은 아니지만 초기때보다 지식이 넓어졌으므로 지금 저 포스트들을 보면 저 포스트들의 설명이 어색하고 횡설수설한 말만 할지라도 탈 없이 봐주시면 감사하겠습니다.

우선 2차배열부터 시작하겠습니다.

2차배열

수1을 떼우셨다면 다 아는 행렬 아시죠?

      1열  2열
1행   2     3

2행   1     4

 2차배열은, 말 그대로 행렬입니다.

그럼 선언과 초기화방법이랑 출력방법을 실험으로 알려드리겠습니다.

1.무작정 다 써서 초기화하는 방법.
13: 2중 반복문을 통해 행과 열을 다 출력함.
이걸로 무작정 다 써서 초기화하는 방법 끝.

2.scan함수로 입력해서 초기화하는 방법.

여태까지 다 한 것들입니다.
아 이런방법도 할 수 있었지 이렇게 생각해주시고 넘어가도 상관없습니다.


3. 배열의 크기를 선언하지 않고 초기화 하는 방법.

이 부분은 조심해야할 것이 하나 있습니다.
그것은 일단 1차원 배열에서 무작정 선언 어떻게했었는지 먼저 더듬고 시작하겠습니다.

t[]={~,~,~,~,~,~,~};
~의 개수가 길이였죠?

그런데 이번 2차원 배열에서는 길이가 한 직선뿐만있는 1차원 배열과는 달리 가로 세로 이렇게 두 개의 길이가 존재하기 때문에, 둘 다 비우면 안 되고 열은 꼭 써줘야 컴파일러가 그걸 자동으로 해석을 해줍니다.

실험으로 알아보겠습니다.

첫 째, 우선 둘 다 비웠을 경우

실패

둘 째, 열을 썼을 경우

성공!

이렇게 2차배열을 마치고 3차배열로 넘어가겠습니다.

3차 배열

3차배열은 공간도형이라 생각하시면 되는데, 저 같은 경우는 출력할 때, 공간도형 생각했다가 되게 고생했구요(상상이 좀 풍부해가지고 ㅋㅋ;)

원리만 공간도형이라고 편하게 생각하시고, 예로는 아파트 생각하시면 됩니다.

동과 호 그리고 층이있는 아파트를 생각하시면 되고 이것마저 생각하기 힘들다면 생각하지마시고 배열하나에 배열 2개가 들어가있다고 생각하시면 됩니다.

그래도 이해가 안 된다면, 그냥 입력할 수 있는 갯수가 더 늘어난다 생각하시고 도형같은 거 그냥 잊어버리세요.

뭐 두서가 좀 길어졌는데요.

본론으로 들어가서 선언과 초기화 방법을 알려드릴게요.

초기화방법은 위에서 다 했듯이 2차 배열은 2중 반복문이라면 3차배열은 3중 반복하면 되겠습니다.

실험으로 선언과 초기화방법을 알려드릴게요.


이걸로 3차배열을 마치고 마지막으로 2차배열과 3차배열의 크기 계산을 알아 보겠습니다.


크기 계산 방법.

1차배열에선 어떻게 구했었죠?

바로 자료형크기x길이이었었죠?

그럼 2차배열과 3차배열은 어떻게 구할까요?

1차배열에선 길이지만 2차배열과 3차배열은 넓이가 있습니다.

자료형의크기x넓이입니다.

그럼 실험으로 알려드리고 포스트를 마치겠습니다.



2013년 1월 19일 토요일

포인터 연산

안녕하세요.

이번포스트는 포인터의 증가감소연산을 알아 볼텐데요.

우선 포인터에 대한 증가감소가 가능한 코드들을 알아 볼게요.

int main(void)
{
int t=10;
int *ptt=t;
int *ptt1=....;
ptt++;
ptt += 3;
ptt -= 3;
ptt1 += ptt;
ptt1= ptt+10;
등등
}
보시다시피 증가감소는 다 사용할 수 있다고 할 수 있습니다.

그런데 이 때, 연산의 결과는 어떨까요.

실험으로 알아보겠습니다.

포인터ptt선언 밑 초기화 %p로 주소값 출력.

%d 였다면 9 11 이라는 값이 출력했겠지만 %p(주소는 자료형의 사이즈간격으로 되있다.)라서 자료형사이즈 x n이 되는 겁니다.


다 이해하셨으리라 믿고 이 포스트를 마치겠습니다.

2013년 1월 13일 일요일

포인터로 이뤄진 배열을 알아보자!

1.포인터

포인터라는 것은 주소 값을 저장하려는 목적으로 쓰입니다.

여기서 주소란 메모리 주소인데요. 즉, 1바이트 메모리의 단위를 하나의 주소 값이 할당되고 그 할당된 주소를 저장하려는 목적으로 만들어진 함수가 바로 포인터라는 것입니다.

포인터란 것을 처음 아신 분은 주소는 어떻게 표현할까 라는 의문점이 생길수도 있습니다.

우선 작은 예를 들자면 int형 변수 Num의 주소는 0x12ff76~Ox12ff79(16진수)가 int형 변수입니다.

왜 주소가 4개이냐면 int는 4바이트이기 때문입니다. 주소 변경은 16진수이고 맨 뒤에 숫자가 하나씩늘어나는 것입니다.

자 이제 포인터를 쓰는 예를 보여드리겠습니다.






딱히 걸고 넘어갈 것은 없구요.
결과창을 보면 첫 줄, 둘 째줄에 1번 결과들은 첫 번째 짤에서 설명 가능합니다.
두 번째 칸들도 글로 설명했죠. int함수의 주소(제가 스샷 찍었을 때는 몰랐는데 %d를 %p로 하면 16진수 주소들이 정확히 나오더라구요. 참고하세요~)라고.

참! 까먹었었는데 프린트함수에서 포인터함수를 *을붙여서 출력하게 되면 그 문에서 그 포인터함수가 저장하고 있던 값을 그대로 내뱉습니다. *를 붙이지 않으면 

그리고 별로 도움은 안되지만 포인트함수의 선언 방법을 알려드릴게요.


int* pt
int *pt
int*  pt

int * pt


int  *pt
int*   pt
int *  pt
int  * pt
int   *pt
.
.
.
.
.
.
보시다시피 *만 포인터함수 앞에 붙여두면 됩니다.

더 나가서, 리턴문에서의 포인터함수 사용법과 널 포인터를 언급하겠습니다.

리턴문에서의 사용법
리턴문(return *ptender;)에서는 이 문장(return *ptender;)을 통해 값을 반환하려면 pt가 가리키는 메모리 공간에 접근을 해서 값을 읽혀져야 합니다.

그 때, pt는 크기 값으로 읽혀져야 하나 아니면 데이터에 저장되있는 수로 읽혀져야 하느냐에서 의견이 갈릴 수 있습니다.

그런데 위에 두 갈등은 return문만 가지고는 풀리지 않습니다.

그리고 pt의 정보가 필요합니다. 그니까 위에 실험에서와 같이
int t=10;
int *pt=&t;
이렇게 pt가 가리키면 리턴문(return *pt;)에서의 pt는 저장되있던 int자료형의 크기,주소 순서로 읽혀져 마지막엔 10이라는 저장되있던 정수로 해석이 된다.

이를 좀 고쳐서 double t=10으로 했다면 리턴문은 실수로 해석이 된다.

널 포인터
널 포인터라는 것은 int *pt=NULL;이라는 문장에서 *pt인데 사실 NULL은 0을 표현하는 함수입니다.

그럼 저 문장은 주소가 0인곳을 가리키는 것일까요? 절대 아닙니다.

아무주소도 가리키지 않는 것입니다.

포인터로 이뤄진 배열

드디어 포인터와 배열인데요. 시간 정말 많이 까먹었습니다. 워낙 이해하는데 오래걸려서 ..

arr(배열함수)과 pt(point tender 즉, 포인트함수)의 차이부터 알아봅시다.


비교조건\
\비교대상
포인터 변수
배열의 이름
이름 존재
나타내는 것과
저장 가능
메모리의 주소 값
메모리의 주소 값
주소 값의
변경이 가능
가능
불가능
이 표가 사실인지 확인해보겠습니다.




여기서 보여드리지 못한것이 9번줄의 arr=&arr인데요.
그 문장을 주석해제하면 에러가 뜹니다.
즉, arr함수는 주소값을 변경 가능하지 않는다는거죠.
(오랜만에 코드 만들어보니까 아주 엉망이네요. 8번 째 줄에 arr[0]입니다.)

이번에는 배열을 대상으로 하는 포인터 연산 (*연산)을 알아봅시다.

위 파란글씨문장 을 짧게 1차원 배열이름의 포인터라고 하는데, 그래도 기네요.

아무튼 1차원 배열이름의 포인터 사용법을 작은 예로 보여드리자면,.



*tender[n]으로 n번의 요소를 표현할 수 있습니다.
저는 그냥 귀찮아서 배열함수만 쓰고 1번 요소만 보여드린겁니다.

위의 코드들을 해석하자면

5,6 줄에서 보시면 텐더 배열함수를 각각 선언했는데, 배열함수는 배열함수 자체가 포인터이기 때문에, 배열함수를 따로 포인터함수로 가리키지 않고 배열함수 이름만으로 포인터함수를 가리킬 수 있습니다.

그래서 8,9번 줄에 따로 포인트 함수를 선언 가리킴 없이도 포인터함수가 가능했던 것이구요.



대충해서 죄송하구요.
시간이 오래걸려서인지 의욕도 떨어지고, 정신적으로도 약간 멘붕이 오네요.
사실 뭐 보러오는 사람도 없는데 열심히 해봤자 시간만 더 까먹으니깐 상관은 없겠죠.
여기서 포스팅 마칠게요~