1) 지식 창고는 본인이 작성한 콘텐츠(팁/노하우/리소스/강좌 등)을 무료 혹은 가상화폐인 납포인트를 통해 공유하는 공간입니다.
2) 본인이 작성한 콘텐츠에 대해서만 지식 창고에 등록할 수 있으며, 저작권에 위배되는 콘텐츠는 사전경고 없이 삭제될 수 있습니다.
3) 콘텐츠 구매 및 첨부파일 다운로드는 회원그룹 '연구원' 이상 가능하오니, 경험치를 쌓아 진급한 후에 이용 부탁드립니다.
4) 무료 콘텐츠의 본문은 구매절차 없이 즉시 이용할 수 있으며, 판매 납포인트가 있는 콘텐츠는 구매 후 이용할 수 있습니다.
5) 콘텐츠 판매에 따른 납포인트 수익은 지정한 비율(50%)에 따라 판매자에게 지급하며, 납포인트 수익을 통해 진급을 빨리할 수 있습니다.
6) 구매 후 평가를 하면 구매 납포인트의 20%를 돌려 드립니다.
판매자 | 프리미엄 | 판매 납포인트 | 무료 | 평점 | 0점 / 총 0명 참여 |
---|
***************************< 캠퍼스 C 강좌 >******************************
[제목] :
[코드] : campusc1-013 (초급)
[교재] : CAMPUS C (초급, Third edition) [출판사 : 책과스승]
[알림] :이 파일은 "캠퍼스 C"에서 모든 분께 공개한 "초급 강좌"입니다.
이 [알림]의 내용을 지우지 않는다면 누구에게나 임의로 복사해 줄 수
있습니다.그러나 이 강좌 내용에 대한 저작권은 "캠퍼스 C"에 있습니다.
[연락처] : 605-8662 (서울) ("캠퍼스 C", 도서출판 "책과 스승")
천리안 : go campusc
나우콤 : go lcampc
하이텔 ID : campusc
***************************<< 목 차 >>*********************************
<1> () 에 대하여
1> 캐스트(cast) 연산자.
2> 맘대로 쓰는 ()
<2> 포인터 에서의 증가(++), 감소(--)의 의미
<3> **p , *p[], p[][] 인 2차원 배열과 포인터는 넘나든다.
**************************< 내용 시작 >********************************
<1> () 에 대하여
***********************************************************************
1> 캐스트(cast) 연산자.
-----------------------------------------------------------------------
이제 캐스트 연산자를 정식으로 언급을 하자. [88쪽]의 연산자 표를
보자. 윗부분에 "(형명)" 이라고 쓴것이 바로 캐스트 연산자이다. 쓰는 형태
는 "()" 이다.
"cast"라는 낱말의 뜻은 일반적으로 (돌, 주사위,그물 따위를) "집
어 던지다" 이다. 그러나 여기서는 그런 뜻이 아니고 "어떤 형태, 어떤꼴로
만들다"의 뜻이다. 즉 C 에서 캐스트 연산자의 의미는 "어떤 값을 일시적으
로 다른형태로 바꿔서 해석하는것이다."
쓰는 방법을 보면 다음과 같다.
main()
{
char ch;
int i;
i = ch; /* int = char */ <-- 틀림
i = (int)ch; /* int = int */ <-- 맞음
}
이 강좌에서, 대입 연산자(=)의 양쪽의 데이타 타입은 같아야 한다
고 누누이 강조해 왔다. 즉 위에서 보면 "<-- 틀림" 이라고 표시한 줄은 타
입이 안맞고 있음을 볼수가 있다. 타입이 안맞으면
-----------------------------------------------------------------
1. 양쪽의 아파트 크기가 틀리고, ( 위의 경우, 2 바이트 = 1 바이트)
2. 양쪽의 내용이 틀린다 ( // 숫자 = 문자 )
-----------------------------------------------------------------
이것은 마치 시소놀이를 할때 무게 균형이 안잡히는것과 유사하게
보인다. 이럴때 위와 같이
--------------------------------------------------
캐스트 연산자를 "(int)" 라고 변수 "앞"에 씀으로서
--------------------------------------------------
무게 균형을 잡는것이다.
기능은 위와 같이 간단하다. 그러나 초보자들은 흔히 이 표현을 혼
동한다. 이유는 "()" 표현이 함수에도 쓰이고 또 기타 여러군데에서 쓰이기
때문이다. 즉
main()
{
i = xxx(); <--- 함수머리 xxx()
i = (int)yyy; <--- 캐스트 연산자 , 변수 yyy 앞에
}
위 첫줄의 "xxx" 는 형태로 보아 "함수이름"이라는걸 알 수 있다.
그리고 "yyy"는 변수명이라는걸 역시 형태로 보아 알 수 있다. 그러면 다음
을 보자.
main()
{
i = (int)xxx();
}
<문제> 여기서 xxx는 "함수 이름"인가 "변수명" 인가 ?
지난번에도 이런 문제가 나온적이 있다. 즉, xxx 이란 이름 "양쪽"
에 연산자가 하나씩 붙어있는 경우이다. 이 것은 마치 xxx라는 남자 양 옆
에 두 여자가 팔짱을 끼고 있는것 같은 모습이다.
이 때 동시에 한여자는 영화 "람보"를 보자고 하고 다른 여자는 (안
성기가 나오는) "투캅스"를 보자고 한다면, 이 남자는 어디로 가야 할것인가
?
이런 싸움이 붙으면 우리의 영원한 해답은 역시 "연산자 표"이다.
[88쪽]을 보자. () 가 처음 나타나는 것은 "우선순위가 제일 높은 쪽에" 그
것도 제일 처음에 () 가 나오는걸 알 수가 있다.
그리고 지금 우리가 얘기하는 캐스트 연산자는 "우선순위 두번째 그
룹"에서 볼 수가 있다. 이것도 같은 형태이므로 빨간 형광펜으로 두개를 묶
어서 표시를 해두자.
대답은 간단하다. 캐스트 연산자는 "우선순위"가 낮기 때문에, 나중
에 혹시 단독으로 만날 일이 있으면 그때 원하는 영화를 보기로 하고 지금은
미안하지만 물러나야 한다.
따라서 위의 xxx는 함수명이다. 다시 써보면
main()
{
i = (int) xxx();
}
이와같이 판정이 났다. 그리고 앞에 붙은 캐스트 연산자 "(int)"는 함수가
"보고를 할때" int형으로 바꾸는 것이다. 아마 어떤 사령관이 xxx() 함수를
부를때 "쏴라 그리고 대답은 반드시 int형으로 하라" 고 명령을 한 모양이
다. 함수에 관한건 나중에 또 많이 나올테니까 지금은 이해를 못해도 좋다.
사실을 얘기하면, 내가 여러분을 속이고 있는게 있다. 대입 연산자
"=" 을 중심으로 데이타 타입이 안 맞아도 사실 컴파일러는 아무 말도 안한
다. 즉
main()
{
int i;
char ch;
i = ch; /* int = char */
}
위와같이 굳이 캐스트 연산자를 안 쓰더라도 컴파일러는 아무 소리
안하고 "프로그램 잘 짰어 인간아 !" 하고 통과를 시켜준다. 실제로는 자기
가 알아서 "자동적으로 변환(casting)" 을 해준다. C 는 정말 좋은 언어같
다. 그러나 여러분들은 절대로 이런 호의에 넘어가서는 안된다. 나중에 골탕
먹는건 우리 "사람"이지 컴파일러가 아니기 때문이다. 처음 배우는 때부터
확실히 원칙대로 "캐스트"연산자를 써서 균형을 잡아주는 습관을 들이자.
그러다가 나중에 "자동적으로 변환"하는 법칙을 확실히 알게 되면
굳이 캐스트 연산자를 안써도 될것이다. 그러나 컴파일시 "WORNING(경고)"
메세지는 계속 나올 것이다. 그 때는 그런 메세지를 무시할 수도 있을 것이
다.
[91-94쪽])까지 이 내용에 대한 자세한 설명이 있다. 참조하시기 바란다.
<숙제> 다음의 경우에 컴파일러가 어떻게 "자동 변환"을 하는지 간단한 프로
그램을 짜서 알아보세요.
1) char = int 로 받는 경우
2) int = char 로 받는 경우
-----------------------------------------------------------------------
2> 맘대로 쓰는 ()
-----------------------------------------------------------------------
캐스트 연산자와 형태는 똑같지만 "자기 맘대로 쓰는 ()"가 있다.
이것은 캐스트 연산자와 다음과 같은 차이가 있다.
-------------------------------------------------------------
1. 자기가 붙이고 싶은 위치에 붙인다(변수 앞에 만이 아니고)
2. () 사이에 char, int 따위의 "데이타 타입"이 들어가지 않는다.
-------------------------------------------------------------
다음의 예를 보자.
main()
{
if( ( a > 0) && (a < 10) )
}
if()의 경우에 "()"를 하는건 당연하고 위에 밑줄 친 부분에서 ()를
했다. 이건 자기 맘대로 붙이는 것이다. 쓰고 싶으면 쓰고, 쓰기 싫으면 안
써도 된다. 모든 문법이 이것처럼 쉬웠으면 좋겠다.
"연산자 표"에서 보다시피 이 ()는 "우선순위" 가 "최고"로 높다.
따라서 자기가 가장 밀접한 관계를 유지하고 싶은 "놈" 하고 ()로 묶으면 만
사 O.K다. 적어도 C 세계에서는 아무도 이들의 관계를 끊을 수 없다.
이건 쉽게 얘기해서 국민학교 산수 시간의 a = b x (c + d) 와 똑같
은 개념이다. 그러나 나중에는 이런 표현법도 어려워지는게 있으므로 일단
우리의 관심을 기울이자.
사실 위의 표현도 역시 ()을 안해줘도 결과는 같다. 이 경우는 원래
연산하는 우선순서가 ">", "<" 연산이 "&&" 연산보다 우위에 있다. 그러므
로 위에서 사용한 ()는 일종의 군더더기이고 사족(snake's leg)이다. 그러나
일반적으로, 위와같이 붙여준 표현을 "나쁘다" 고 얘기하지는 않는다. 오히
려 "붙여주는 것이 낫지 않을까 ?" 하고 여겨 줄만 하다. 이유는 ()를 사용
하여 시각적으로 내용을 구분해 줌으로서,우리의 머리를 편하게 정리시켜 주
기 때문이다.
그러나 보기에 좋다고, 군더더기를 너무 남발을 하면 (자세한 확인
이 필요하지만..) 실행속도가 느려질 지도 모르겠다. 각 회사의 컴파일러들
이 실행속도 향상을 위하여 "최적화" 작업을 하기는 한다. 그러나 위같은 경
우에도 최적화를 하는지는 잘 모르겠고, 나의 권고는 "적당히 사용" 하라는
것이다.
참고로 "최적화(optimization)"에 대해서 설명하면, 터보 C 컴파일
러 메뉴에서 [options] [compiler] [optimization]을 줄줄이 선택해 보자.
선택 난에 "optimize for --> speed( or size)"를 하게 되있다. 이
게 사실상 컴파일러의 "값어치"를 결정짓는 중요한 요소중의 하나다. 이건
말 그대로 여러분이 짠 프로그램을 컴파일 하는 과정에서
1. 가능한 "실행 속도"를 빠르게 하도록 만들까
2. 아니면 "실행 파일(xxx.exe)의 크기"를 가장 작게 만들까
하는 문제를 결정하는것이다. 여러분들은 어떤걸 선택하시겠는지 ?
욕심 같아서는 가장 작으면서도 가장 빠르도록 만들도록 하고 싶지
만, 아시다시피 이런 문제는 바둑을 두는 것과 유사해서 "한 쪽을 취하면 한
쪽을 내 줘야 하는" 관계와 유사하다.
사실 요즘 세상엔 파일의 크기에 관한 제약은 적다. 하드 디스크의
값이 자꾸 싸지고, 또 메모리의 값도 싸지기 때문에 "프로그램을 얼마나 작
게 만들었나" 하는 문제 보다는 역시 "얼마나 빨리 도나 ?"의 문제가 더 관
심이 있다.
상업적으로는 지금 "터보 C" 가 상당히 성공한 듯이 보이지만 "실행
속도 최적화"에 있어서는 전통적으로 "마이크로 소프트 C (MS-C)"가 단연 앞
선다. 사실상 연구소나 회사에서는 이런 터보 C를 잘 안쓰는것 같다. 터보 C
컴파일러는 "일반 사용자"를 위한 "편리한" 컴파일러지 "좋은" 컴파일러라고
보기는 어렵다고 말 할 수 있기 때문일 것이다.
여러분께서도 점점 전문가가 되면 컴파일러도 골라써야 할 것이다.
***********************************************************************
<2> 포인터 에서의 증가,감소
1> "a++" 와 "a + 1"의 차이
2> a++ 와 a + 1 은 어느만큼 증가하나 ?
***********************************************************************
1> "a++" 와 "a + 1"의 차이
-----------------------------------------------------------------------
이건 아주 쉬운 개념이지만, 모든 문제가 그렇듯이, 표현이 복잡해
지면 우리를 혼란시킨다. 따라서 확실한 이해가 필요하고 더 나아가서 "척"
보면 아는 숙달된 경지에 이르러야 한다. 다음을 보자.
main()
{
char *ma_dangbal = "abcde";
printf("%d",ma_dangbal); --> 100
printf("%d",ma_dangbal + 1); --> 101
printf("%d",ma_dangbal + 2); --> ?
printf("%d",ma_dangbal); --> ?
}
<문제> 문자열 "abcde"는 100 번지부터 값이 들어간다고 치자.따라서 처음
ma_dangbal은 100 번지를 갖고 있다. 위의 나머지 물음표(?)의 답
은 ?
<문제> 현재 마당발이 갖고 있는 주소 100번지가 바뀌고 있는가 ? --> No
그러면 비슷한 문제를 보자.
main()
{
char *ma_dangbal = "abcde";
printf("%d",ma_dangbal); --> 100
ma_dangbal++;
printf("%d",ma_dangbal); --> 101
ma_dangbal++;
printf("%d",ma_dangbal); --> ?
}
<문제> 문자열 "abcde"는 100 번지부터 값이 들어간다고 치자.따라서 처음
ma_dangbal은 100 번지를 갖고 있다. 위의 나머지 물음표(?)의 답
은 ?
<문제> 현재 마당발이 갖고 있는 주소 100번지가 바뀌었는가 ? --> Yes
위에서는 똑같은 "증가"의 의미를 가지지만
1. "ma_dangbal + 1" 과
2. "ma_dangbal++"의
차이를 알아 보는것이었다. 즉 2번 "ma_dangbal++" 은 "ma_dangbal += 1"의
의미로서 ma_dangbal 자체의 값이 바뀌지만, 1 번은 그렇치 않다.
-----------------------------------------------------------------------
2> a++ 와 a + 1 은 어느만큼 증가하나 ?
-----------------------------------------------------------------------
이번에는 "하나의 증가"는 어느만큼의 증가를 의미 하는지 보도록 한다.
main()
{
long rambo[3], *ma_dangbal;
ma_dangbal = rambo; /* &rambo[0] 와 같은 표현(공식) */
printf("%d",ma_dangbal); --> 100
printf("%d", ma_dangbal + 1 ); --> 104
ma_dangbal++;
printf("%d",ma_dangbal); --> 104
}
여기서 유념할 것은 포인터에서 "하나의 증가"는 "한 단위 만큼"
(즉, long이면 4 바이트)만큼 증가 한다는 것이지 1 바이트가 증가 하는것이
아니라는 사실이다.(중요)
<문제> 위의 long 대신 int라고 바꾼다면 번지수는 어떻게 증가 하는가 ?
***********************************************************************
<4> **p , *p[], p[][] 인 2차원 배열과 포인터는 넘나든다.
1> 베이스(base) 캠프와 전진 캠프(offset)
2> 컴파일러가 배열을 분해하는 법
3> 2차원에서 넘나 드는법
***********************************************************************
1> 베이스(base) 캠프와 전진 캠프(offset)
-----------------------------------------------------------------------
일차원 에서 *p 와 p[] 가 넘나드는 것을 본적이 있다. 이차원에서
도 똑같은 원리로 변환을 한다. 이런 내용은 사실 조금 어려운 문제에 속하
지만, 컴파일러가 배열과 포인터를 취급하는 기본 원리만 이해 한다면 그다
지 어려운 일도 아니다. 혹시 중간에 혼동하는 일이 있으면 그건 아주 간단
한 기본원칙을 이해하지 못해서 그런것이다. 절대로 내용 자체가 난해한 것
이 아니다. I.Q zero(0)인 컴파일러가, 복잡한 포인터를 해석하는 방법이란
지극히 간단하다.
이런 내용을 이해 하려면 일단 "K2" 같은 등반영화를 볼 필요가 있다.
<숙제> 혹시 아직 안보신 분들은 비디오라도 빌려 보시길..
큰 산을 정복하는일은 아시다시피 쉬운일이 아니다. 일단은 우리의
목숨을 걸어 놓고 한다는 면에서 우리를 긴장 시킨다. 따라서 계획도 치밀해
야 하는데, 우리가 따져볼 계획은 주로 "목표지점을 찾아 가는" 거리에 관한
일이다.
k2의 정상을 정복하려면 먼저 그 산 아래 적당한 곳에 "베이스 캠
프"를 친다. 나는 왠지 "베이스 캠프"라면 맥주 마시는 집으로 생각이 되지
만, 등반하는 당사자들에게는 이 베이스 캠프란 그것보다 훨씬 중요한 의미
를 지니는 집일 것이다.
정상 정복팀은 앞으로 나가면서 제 1캠프, 제 2 캠프를 설치하며 중
간 기착지로 삼는다. 목표 지점인 "정상"을 정확히 찾기 위한 과정이다. 이
런 과정을 성공적으로 거치면 결국 봉우리 정상에 태극기도 하나 꽂고, 사진
도 하나 찍고, 그리고 어떤 사람이 흘리고 간 소령마크(*) 하나도 줏을 수가
있다.
이제 k2 정상을 찾아가기 위한 문제는 이렇다.
1. [베이스 캠프]는 어디다 칠까 ?
2. 거기서 얼마만큼 가야(offset) 정상인가 ?
아시다시피 베이스 캠프는 "기준점"이고 offset이란 "기준점에서 떨어진 거
리"를 말한다. offset이란 단어는 (특히 어셈블러에서) 아주 많이 쓰이는
중요한 단어 이지만, 영어 사전에는 지금 얘기하는 "기준점에서 떨어진 거
리"라는 의미는 명확히 알 수 없는 것 같다. 이 것은 아주 중요한 개념이므
로 잘 기억해야 한다.
-----------------------------------------------------------------------
2> 컴파일러가 배열을 분해하는 법
-----------------------------------------------------------------------
"기준점"과 "offset"이란 관점에서 배열을 보면 이렇다.
main()
{
int rambo[300] ;
}
이 배열이 100번지 부터 시작한다고 하고, 배열 rambo[1]의 주소를 알아보면
-------------------------
rambo 1
-------------------------
| |
기준점(100번지) offset(1 x 2) ---> 102호
여기서 배열을 표시하는 []는 없어졌는데 이 것은 아직은 필요없고, 주소를
찾는 과정에서는 위와 같이 두가지 정보만 있으면 충분하다. 기억 하시겠지
만 우리의 공식중에 rambo = &rambo[0] 라는게 있었다. 위와 같이 컴파일러
는
-------------------------------------------------------
배열 이름 rambo를 "베이스 주소"로 인식하는데 쓰고 있다.
-------------------------------------------------------
따라서 그 주소는 곧 rambo = &rambo[0] 이다.
아직 까지 우리는 주소 얘기를 하고 있다는 걸 알아야 한다. 이제
그 주소에 사는 사람을 알아 보려면 다음과 같이 "[]"를 붙여준다.
-------------------------
rambo [ 1 ]
-------------------------
프로그램을 직접보면
main()
{
int rambo[3] = { 11,22,33 };
printf("%d", rambo); <-- 주소 찍음(베이스 100 번지)
printf("%d", rambo[0]); <-- 값 찍음 ( 11 )
printf("%d", rambo[]); <--틀린 표현 (offset 값이 없다)
}
이것이 기본적인 내용이다. 그러나 우리가 실제로 쓸때도 매번 이런 내용을
따지지는 않는다. 언젠가 얘기한 적이 있지만 브레이크를 밟으면 차는 서는
것이다. 차를 세울 때마다 원리를 생각할 필요는 없는 것이다. 그 만고불변
의 법칙이
---------------------------------------
[] 과 * 은 무조건 1 차원 씩에 해당한다
---------------------------------------
--------------< 암기 >-------------------------------
1 차원으로 선언 되었으면 1차원으로 찍어라 --> 값이다
그 아래 차원은 아직도 --> 주소를 찍고 있다.
-----------------------------------------------------
이 원리에 입각해서 위의 프로그램에 첨가하면
main()
{
int rambo[3] = { 11,22,33 };
printf("%d", rambo); <-- 주소 찍음(베이스 100 번지)
printf("%d", rambo[0]); <-- 값 찍음 ( 11 )
printf("%d", *rambo); <-- 값 찍음 ( 11 )
printf("%d", rambo[1]); <-- 값 찍음 ( 22 )
printf("%d", *(rambo + 1);<-- 값 찍음 ( 22 )
}
따라서 이제 원칙적인 결론을 얘기하면
---------------------------------------
기준점 과 offset값만 똑같으면 포인터로
쓰든 배열로 쓰든 아무 상관없다 (당연)
---------------------------------------
그러나 이것도 역시 프로그램을 한눈에 척 알아 보는데는 부적당한 "공자님"
같은 말씀이고 요령은 이렇다.
---------------------------------------
[] --> * 로 바꾸고
* --> [] 로 바꾸면 똑같다.
---------------------------------------
둘다 일 차원 표현법이기 때문에 위의 말도 지극히 지당하신 말씀이다. 다만
offset에 대한 연습은 필요할 것이다. 다음에 값만 찍어보자
main()
{
int rambo[3] = { 11,22,33 };
printf("%d", rambo[0]);
printf("%d", * (rambo + 0)); /* 0 은 있으나마나 */
printf("%d", rambo[1]);
printf("%d", * (rambo + 1));
printf("%d", rambo[2]);
printf("%d", * (rambo + 2));
}
여기서 유치한 변환 규칙을 굳이 적어보면
-----------------------------------------
1. 항상 "기준점" + "offset" 값은 잘 보존한다.
2. [] 가 없어지면서 * 이 생기고
3. 괄호 ( ...)가 생긴다.(우선순위 때문에)
-----------------------------------------
3번 우선순위는 중요하다. 예를들어
printf("%d", * (rambo + 2));
여기에서 ()를 생략하면
printf("%d", * rambo + 2);
이것은 전혀 다른 문제가 됨을 알아야 한다. 소령마크(*) 는 더하기(+)보다
우선순위가 상당히 높기 때문에, 더 힘이 센 ()의 힘을 빌어 갈라놔야 한다.
이런 상식을 가지면 아래의 4 가지 표현이 똑같다는 것을 알것이다. 아래는
람보의 첫집 'a'를 찍기위한 표현이다.
main()
{
char rambo[] = "abcde";
char *ma_dangbal;
ma_dangbal = rambo;
printf("%c", rambo[0]);
printf("%c", *(rambo + 0));
printf("%c", *ma_dangbal);
printf("%c", ma_dangbal[0]);
}
여기서 주목 할것은
------------------------------------------------------------------
1. 값을 찍기 위하여 4 가지 전부, 선언된 것과 같은차원을 같는 1 차원
이라는 것
2. 마당발은 반드시 배열 람보의 첫번째 주소를 가지고 있어야 한다는
것 (기준점을 맞추려고)
3. 람보와 마당발은 전부 char 에 관계된 변수들이므로 "++" 즉 "한 집
증가"는 1 바이트의 증가를 의미한다 (offset이 착착 맞을거다)
-------------------------------------------------------------------
영화 "K2"와 같이 여기서도 베이스 캠프(기준점) 과 offset을 착착 맞추고
있다. 다시 써보면 [204쪽] 제일 아래의 표와 같은 것이다.
이 표는 선언 된 것과 같은 차원으로 찍고 있으므로 "값"을 찍고 있다는걸
안다. 기준점과 offset의 관점에서만 보면 별로 어려울것은 없다. 특히 여기
서 소령(*) 표시의 의미가 "...의 값" 인것을 기억하자.
그리고 맨 마지막 줄에 보면 3[atom]이라는 희한한 표현이 있는데
이것도 기본원리만 알면 역시 문제 될 것은 없다.
main()
{
printf("%c", rambo[3]);
printf("%c", 3[rambo]);
}
즉 위의 두개가 같은 표현이라는 것인데 , 예를 들면 람보가 사는 아파트에
가서 수위 아저씨에게 집을 묻는다.
"아저씨 람보네 집 어디에요 ?"
"100호 가서 옆으로 3집 더 가라"
이건 "3호로 가서 옆으로 100집 더가라" 하고 똑같은 말이라는 것을 알것이
다.(따라서 이런 표현이 가능하다)
<숙제> 람보의 둘째집 'b'를 찍기위한 표현을 위와 같이 4가지로 써보세요
그리고 컴파일 시켜서 실제로 결과가 같은지 확인해 보세요
<숙제> 나머지 "cde"도 마찬가지로 쓰고 실행해 보세요
-----------------------------------------------------------------------
3> 2차원에서 넘나 드는법
-----------------------------------------------------------------------
다음과 같이 선언 되었다
main()
{
char **pp , *p[3];
char a[3][4] = { {'M','O','N','\0'},
{'T','U','E','\0'},
{'W','E','N','\0'}
};
}
이른바 2차원의 3 총사가 모였다. a[][]는 옆으로 4집 그리고 3층 구조를 가
지고 있다. 여기서 "WEN"의 가운데 'E'를 찍는 방법을 알아보자
main()
{
p[0] = &a[2][1];
pp = &p[0];
putch(a[2][1]); /* 'E' print */
putch(*p[0]); /* 'E' print */
putch(**pp); /* 'E' print */
}
위에서 포인터는 반드시 "초기화"를 시켜주는걸 보자. 그리고 전부다 2 차원
으로 무언가를 찍고 있다. 그러면 우리는 일단 멀리서 보더라도 이것들이
값을 찍고 있다는 것을 알수 있다.( 2차원으로 선언 되었기 때문에) 그러면
모든 경우를 살펴보자.
char **pp , *p[3];
char a[3][4] = { {'M','O','N','\0'},
{'T','U','E','\0'},
{'W','E','N','\0'}
};
main()
{
p[0] = &a[0][0];
pp = &p[0];
printf(" %p", a); /* 0 차원 , 주소 찍음 */
printf(" %p", a[0]); /* 1 차원 , 주소 찍음 */
printf(" %p", a[1]); /* 1 차원 , 주소 찍음 */
printf(" %p", a[2]); /* 1 차원 , 주소 찍음 */
printf(" %c", a[2][1]); /* 2 차원 , 값 찍음 */
printf(" %p", p); /* 0 차원 , 주소 찍음 */
printf(" %p", p[0]); /* 1 차원 , 주소 찍음 */
printf(" %p", p[1]); /* 1 차원 , 주소 찍음 */
printf(" %p", p[2]); /* 1 차원 , 주소 찍음 */
printf(" %c", *p[2]); /* 2 차원 , 값 찍음 */
printf(" %p", pp); /* 0 차원 , 주소 찍음 */
printf(" %p", *pp); /* 1 차원 , 주소 찍음 */
printf(" %c", **pp); /* 2 차원 , 값 찍음 */
}