1) 지식 창고는 본인이 작성한 콘텐츠(팁/노하우/리소스/강좌 등)을 무료 혹은 가상화폐인 납포인트를 통해 공유하는 공간입니다.
2) 본인이 작성한 콘텐츠에 대해서만 지식 창고에 등록할 수 있으며, 저작권에 위배되는 콘텐츠는 사전경고 없이 삭제될 수 있습니다.
3) 콘텐츠 구매 및 첨부파일 다운로드는 회원그룹 '연구원' 이상 가능하오니, 경험치를 쌓아 진급한 후에 이용 부탁드립니다.
4) 무료 콘텐츠의 본문은 구매절차 없이 즉시 이용할 수 있으며, 판매 납포인트가 있는 콘텐츠는 구매 후 이용할 수 있습니다.
5) 콘텐츠 판매에 따른 납포인트 수익은 지정한 비율(50%)에 따라 판매자에게 지급하며, 납포인트 수익을 통해 진급을 빨리할 수 있습니다.
6) 구매 후 평가를 하면 구매 납포인트의 20%를 돌려 드립니다.
판매자 | 프리미엄 | 판매 납포인트 | 무료 | 평점 | 0점 / 총 0명 참여 |
---|
***************************< 캠퍼스 C 강좌 >******************************
[제목] :
[코드] : campusc1-010 (초급)
[교재] : CAMPUS C (초급, Third edition) [출판사 : 책과스승]
[알림] :이 파일은 "캠퍼스 C"에서 모든 분께 공개한 "초급 강좌"입니다.
이 [알림]의 내용을 지우지 않는다면 누구에게나 임의로 복사해 줄 수
있습니다.그러나 이 강좌 내용에 대한 저작권은 "캠퍼스 C"에 있습니다.
[연락처] : 605-8662 (서울) ("캠퍼스 C", 도서출판 "책과 스승")
천리안 : go campusc
나우콤 : go lcampc
하이텔 ID : campusc
****************************<< 목 차 >>************************************
<1> 프로그램 흐름의 제어
1> break
2> continue
3> goto 와 레이블(label)
<2> 포인터 와 일차원 배열 (스트링(string) 과의 관계)
1> 스트링(string) 이란 화물열차다..
2> 배열과 스트링
3> 포인터와 스트링 ( * & 의 의미)
**************************< 내용 시작 >********************************
<1> 프로그램 흐름의 제어
***********************************************************************
1> break
-----------------------------------------------------------------------
break 는 말 그대로 잘 나가는 순서를 깨트리는 역할을 합니다. 그
리하여 약속된 특별한 위치로 제어순서를 옮기는데, 말로 하면 다음과 같습
니다.
1. 자기("break")를 감싸고 있는 가장 가까운 껍질("블럭")을 하나
벗어나게 한다.
2. 여기서 말하는 껍질("블럭" --> "{ }" ) 이란 다음의 4 가지다.
(if는 해당이 안됨)
1) while()
2) for()
3) do - while()
4) switch()
간단한 예를 들어 보면 다음과 같습니다.
------------------------------------------
main()
{
printf("one");
while(1) {
printf("two");
for(;;) {
printf("three");
break;
printf("four");
}
/* <-- 요기로 벗어남 */
}
printf("five");
}
-----------------------------------------
공식에 의하면 break; 를 둘러싼 가장 가까운 { }를 벗어나므로 화면에 다음
과 같이 찍습니다.
one two three two three two three two ...... (영원히)
이해가 될것 입니다.
-----------------------------------------------------------------------
2> continue
-----------------------------------------------------------------------
continue는 자기를 둘러싼 가장 가까운 { }안에서 "나머지 부분"을
무시하고 무조건 "조건을 판단하는 곳" 으로 갑니다. 여기서 상관있는 문은
다음의 3 가지 입니다.( switch() 이 빠졌음)
1) for()
2) while()
3) do - while()
예를 직접 보면 다음과 같습니다.
-----------< while >------------
main()
{
printf("one");
while(1) {
printf("two");
printf("three");
continue;
printf("four");
}
}
<결과> one two three two three two three ...... (영원히)
----------< for >----------------
while() 과 같음
main()
{
printf("one");
for(;;) {
printf("two");
printf("three");
continue;
printf("four");
}
}
<결과> one two three two three two three ...... (영원히)
----------< do while >----------------
main()
{
printf("one");
do {
printf("two");
printf("three");
continue;
printf("four");
} while(1);
}
<결과> one two three two three two three ...... (영원히)
-----------------------------------------------------------------------
3> goto 와 레이블(label)
-----------------------------------------------------------------------
이건 별로 설명이 필요 없을것 같은데 말 그대로 "어디로 가라" 입
니다. 그 도착지는 "레이블"이 붙은 곳 입니다. 라벨 아시지요 ? 옷 같은 물
건 살 때 붙은 라벨(label) 말 입니다. C 에서는 라벨을 " xxx : " 이렇게
붙여 줍니다.switch 문에서 사용한 ':' 이 또 나옵니다.
예를 직접 들어 보면
------------------------
main()
{
here :
printf(" good morning");
goto here;
}
-----------------------
라벨을 쓰는 위치도 위와같이 제일 앞에 함으로서 특별히 눈에 잘
띄게합니다. 이건 마치 장기에서 "차" 움직이듯 아무 곳에나 쓸 수 있습니
다. (단, 한 함수내 에서만!). 위에서 break 와 continue 가 { } 를 한 겹씩
밖에 벗어 나지 못한다는 점을 비교하면 어떻게 이용 가능한지 짐작 할 수
있을 겁니다.
그러나 이 goto 문은 가급적 쓰지 말아야 합니다. 만들어 놓고 쓰지
말라는게 이상하게 들리겠지만, 사실상 너무 남발 하면 소위 말하는 "스파
게티 로직(spaghetti logic)" 이 되어 프로그램의 흐름을 이해 하기 어렵게
됩니다. 이태리의 맛없는 국수 스파게티 아시지요 ? 이게 한번 엉키면 갈피
를 못 찾고 정신이 없다는 얘기 입니다. 한국 사람들이 더 생생하게 느낄려
면 "미친 여자 머리카락 엉키듯" 한거지요. 혹시 BASIC을 좀 해 보신 분들은
이 goto문을 많이 쓰면 어떤 일이 벌어지는지 금새 이해 하실 겁니다.
어셈블러를 할 때는 아직도 이 짓을 안 할 수는 없습니다. 저급(low
level) 언어의 특성상 어쩔 수 없는 거지요. 그런 짓을 않하기 위해 C 같은
고급("high level")언어를 만든 것 이구요. 그러니까 고급언어에서는 가급적
쓰지 않는게 좋지만, 그러나 겹겹이 있는 블럭 { }을 벗어나 원하는 곳으로
단숨에 가고자 할땐 이 goro를 안 쓸 수는 없습니다. 그리고 실제적으로도
한두개 쯤은 꼭 쓰게 되기도 합니다.
***********************************************************************
<2> 포인터 와 일차원 배열 (스트링(string) 과의 관계)
1> 스트링(string) 이란 화물열차다..
2> 배열과 스트링
3> 포인터와 스트링
***********************************************************************
1> 스트링(string) 이란 화물열차다..
-------------------------------------
스트링이란 말 그대로 "줄"입니다. 그러나 그것은 여기서 얘기하는
정확한 개념이 아니고 차라리 "줄줄이 사탕" 이나 "기차" 같은 걸 연상하는
게 더 정확 합니다. 즉 " 한 칸에 한 글자 씩 들어가서 줄 형태를 이루는
것" 그것이 스트링입니다. 우리는 이미 스트링을 많이 써왔습니다.
printf("Good") 에서 쌍따옴표 " " 사이의 문장이 스트링입니다. 이것을 특
별히 화물열차에 비교 하는 이유는
---------------------------------------------
1. 길이가 얼마 인지 정해져 있지 않다.
2. 맨 뒤 칸에는 꼭 사람(조수)가 타는 칸이 있다.
-----------------------------------------------
는 것 입니다. 스트링에 길이가 정해져 있지 않다는 것은 여러분도 알 것입
니다. 즉 printf("abcdef........"); 이렇게 길이에는 제한이 없습니다. 그
런데 여기서 꼭 알아야 할 것은 스트링 끝에는 다음글자가 있어야 한다는 것
입니다.
---------------------------------------
" 반드시 NULL글자( ASCII 0x00) 이 있다"
---------------------------------------
[534쪽]의 아스키코드 (제일 첫글자) 0x00에 아무런 표시가 안 되있
는 분은지금 형광펜으로 표시해 두세요. 이와 같이 "글자들"의 끝에
"zero(0x00)"가 붙는 문장의 형태를 우리는 일반적으로 (ASCIIZ string) 이
라고 부릅니다. 이 그림의 실제 모습이 [159쪽](새교재 [137쪽])의 메모리
구조 입니다.
참고로 다른 문장 형태를 비교해보면, PASCAL 이라는 언어에서는 문
장의 형태를 다음과 같이 쓰지요.
[ 1바이트] [2바이트] [3바이트] [...] [....]
| |
문장길이표시 문장시작
즉 처음의 두 바이트에 문장의 길이를 표시해 둡니다. 따라서 이런 문장은
끝에 별다른 표시를 해 둘 필요가 없지요. 그리고 앞의 두바이트만 읽어보
면, 당연히 이 문장의 길이를 알수 있지요. 그러나 C 문장에서는 길이를 따
로 표시하지 않기 때문에, 지나가는 기차칸 세듯이 일일이 세봐야 합니다.
그리고 기차의 끝칸에 해당하는 것은 0x00 이기 때문에 이 글자는 정말 관심
을 갖고 유심히 봐야 합니다.
영어 글자 하나가 한 바이트를 차지하는 것은 알겁니다. 그러면 다
음 크기를 볼까요
printf("Good"); <-- 5 바이트 크기 ( good + NULL)
printf("morning"); <-- 8 바이트 크기 ( morning + NULL)
printf("A"); <-- 2 바이트 크기 ( A + NULL)
putch('A'); <-- 1 byte 크기 ( A ) <-- 스트링이 아님
이제 약방의 감초처럼 나오는 문제가 다음 아닙니까 ?
<문> 다음의 차이는 무엇인가 ?
1. "A" --> 스트링으로서 2 바이트 차지.
2. 'A' --> 문자 상수로서 1 바이트.
3. A --> ?
4. a --> ?
3 번과 4번의 차이는 얼뜻 눈에 안들어 오지요 ? 이건 정답이 있는 것은 아
니지만 C에 조금 익숙한 분들은
A --> 대문자로 보아 "매크로 정의"한 어떤 이름일것이다.
a --> 변수명 일것이다.
라고 대답 할 겁니다.
-----------------------------------------------------------------------
2> 배열과 스트링
-----------------------------------------------------------------------
나중에 정식으로 언급 할 기회가 있겠지만 우리가 프로그램을 짜면
내부적으로는 이 프로그램이 몇 조각으로 분해 됩니다. 즉
"데이타 부분"
"명령어 부분"
"스택 부분"
"기타 부분"등
이지요. 컴퓨터 용어로 "크기"에 관한 것이 많은데, 우리는 이미 비트, 니
블, 바이트 , 같은 용어는 알고, 지금 나오는 크기는 세그먼트(segment) 라
는 용어를 씁니다. 즉
"데이타 segment"
"명령어 segment"
"스택 segment"
"기타 segment"등
이지요. segment의 낱말의 뜻은 그냥 " 부분, 조각" 이란 뜻 이지만 여기서
는 정확하게 64k 바이트 (0xffff)를 말 합니다. 여러분 께서도 이제는 크기
에 대한 개념에 어느정도 익숙하다고 생각하는데 [20쪽]) 레지스터를 보세
요.
맨 밑에 4개가 쪼로록 "세그먼트" 레지스터입니다. 이 레지스터들은 통째로
2바이트이기 때문에 메모리처럼 아파트 두채로 그리지 않았습니다.
아직도 기억을 하시는지 모르겠는데, 한 바이트는 2개의 니블로 되
있습니다. 니블 하나를 16진법으로는 'f'로 표시하기 때문에 세그먼트의 최
대 크기는 0xffff 입니다.
<문제> 위에서 얘기한 "세그먼트"와 크기가 같은것은 어느것인가 ?
1) char
2) int
3) long
4) float
이제 우리가 printf("Good"); 이라고 프로그램을 짜면 "Good" 이라
는 부분은 "데이타 부분"에 저장 됩니다. 이때 차지하는 집이 아파트 5 채
라는 겁니다. 이걸 취급하는 방법은 두가지인데 첫째가 우리가 이미 아는 배
열입니다.
main()
{
char train1[5] = { 'G', 'o', 'o','d', '\0');
char train2[] = "Good";
}
위에서 train1[]는 train2[] 와 똑같습니다. train2[] 처럼 숫자를 생략하
면 데이타의 크기에 맞게 값이 결정된다는 것은 이미 아시지요 ? 이건 숫자
를 [] 안써도 된다는 간편함 뿐만이 아니고 나중에 " " 사이의 데이타 길이
가 달라져도 크기가 "자동적"으로 변해 준다는 면에서 프로그램 작성상의 오
류를 확실히 예방 할 수 있습니다. 따라서 "스트링인 경우"는 특히 섣불리
[4] 이런식으로 굳이 숫자를 세어 넣지 마십시오. 실수의 한 예로 눈에 보이
는 대로 [4]라고 써넣으면 스트링 끝의 "NULL" 문자가 짤려지고 그러면 스
트링을 찍을 때 끝을 못찾아서 컴퓨터가 미쳐버리고 마는 것입니다.
위 배열에서는 총 5 바이트가 쓰였는데( 4 + NULL), 배열을 이용하여 위의
"Good" 문장을 찍으려면 다음과 같이 합니다.
for(i = 0; i < sizeof(train); i++)
putch(train[i]);
만일 Good의 d 만 찍고 싶으면 putch(train[3]); 이렇게 하면 될 것입니다.
배열의 구조 및 사용법에 대한 기초로 잠시 반복 하면 아래와 같이 될겁
니다
train[0] <-- 100 번지 라고 치면
train[1] <-- 101 번지
train[2] <-- 102 번지
train[3] <-- 103 번지
-----------------------------------------------------------------------
3> 포인터와 스트링
-----------------------------------------------------------------------
포인터는 다음과 같은 형식으로 씁니다.
main()
{
char train[] = "Good";
char *ppp = "morning"; <-- 포인터
}
형태는 일반 변수명 앞에 "소령마크,혹은 눈(snow)마크"를 붙여줍니다.
그리고 배열과 마찬가지로 스트링이 포인터에 할당 뻍는데, 그 의미는 조금
다릅니다.
이제부터 그 유명한 포인터(pointer) 이야기를 해 보지요. 포인터
(pointer)는 말 그대로 "어디를 가리키는 것" 이라는 말입니다.
어느집 아파트 문패에 다음과 같이 써있습니다.
------------------------------
100호 대장 김 용팔
-------------------------------
사실 아파트 문패에 "대장" 이란 말을 쓰는 사람은 없지만 이건 C 아파트 입
니다. 이것은 예를 들면
------------------------------
100호 char kimpalyong
-------------------------------
과 같은 형식이라고 했습니다.
여기서 대장 이란 말이 이 집의 크기를 암시하듯이 char 가 보여주는 것도
------------------------------------------------
1. 크기는 1 바이트
2. 이 집에 사는 내용은 한 문자 'q' 따위를 넣는다
------------------------------------------------
라고 했습니다.(중요)
그러면 이번엔 아파트에 이런 문패가 있다고 합시다
-----------------------------------------
대장 의 집을 알려주는 집 김 용팔
------------------------------------------
우리는 또 짐작 할수 있습니다.
1. 김 용팔이 대장은 아니구나 (내용의 문제)
2. 이 집 크기가 대장집과 똑같은 것은 아니겠구나 (크기의 문제)
C 에서는 위와 같은 문패가 너무 길다고 생각하여 표기법을 하나 정했습니
다. 즉 위에서 "의 집을 알려주는 집" 대신 '*' 표시를 하기로 했습니다.
다시 쓰면
------------------------
대장 * 김 용팔
-------------------------
어떤가요 한결 간단해지지 않았습니까 ? 이건 표기법이기 때문에 우리는 무
조건 외워야 합니다. 처음 보는 분은 의미를 얼른 연상 하지 못하겠지만 자
꾸 보면 익숙해 질겁니다. 나중에 나오겠지만 포인터는
------------------------
대장 ** 김 용팔
-------------------------
------------------------
대장 *** 김 용팔
-------------------------
이렇게도 쓰이므로 여기서 표기법을 꼭 외워야 합니다.
이제 김용팔은 더이상 대장이 아니라는 사실을 명심하고 그 집에 가
서 문을 열어 보면 누군지는 모르지만 좌우간 "대장" 인 사람의 주소가 있
다는 사실을 알겁니다. 이제 C 의 한 예로 표기법을 바꿔보면
-------------------
char *kim_yongpal;
-------------------
입니다.이제 kim_yongpal 이란 변수는
1. 더이상 한 바이트(char 크기)가 아니다. (크기)
2. 한글자 'q' 따위를 갖는게 아니고 남의 "주소"를 갖고 있다
그 주소는 "대장"에 해당하는" char 변수"의 주소다. (내용)
이제 예를 들어 봅니다. (중요)
main()
{
char *pointer, yong7,yong8;
int *pp, i,j;
}
위에서 pointer 라는 변수는 "char" 만 가리키기로 했으므로 yong7
이나 yong8의 집 주소만 가져야지 i,j 의 주소를 가질 수 없습니다. 마찬가
지로 pp 는 i,j (int type)의 값만 가져야지 다른 type의 변수의 주소를 가
질수 없는 겁니다..(중요)
또하나 표기법이 있습니다.
main()
{
char *pointer, yong8, a;
int *p_int, i, j;
a = 'q'; /* char type */
pointer = &yong8; /* <--- address */
}
위에서 & 가 처음 등장 했습니다. 다음 두 집을 볼까요
------------------------------- ------------------------
< 100 호 > < 111 호 >
가수 의주소를 알려주는집 마 당발 가수 서 대지
------------------------------- ------------------------
다시 써보면
------------------------------- ------------------------
< 100 호 > < 111 호 >
가수 *마 당발 가수 서 대지
------------------------------- ------------------------
여기서 가수 대신에 char라고 바꾸기로 하고 다시 써보면
------------------------------- ------------------------
< 100 호 > < 111 호 >
char *ma_dangbal char so_daeji
------------------------------- ------------------------
당발씨 집에 서대지씨의 주소(111 호)를 넣어주고 나면 우리는 앞으로 당발
의 집에서 서대지씨의 집주소를 알 수 있습니다. 넣는 과정은 이렇습니다.
ma_dangbal = so_daeji 의 주소;
여기서도 C 의 독특한 표현법이 쓰입니다.
"의 주소" 대신 "&"를 이름"앞"(뒤가 아님)에 붙여주 는 것입니다. 즉
ma_dangbal = &so_daeji;
어떤가요 역시 간단하지요 ?
이것도 물론 처음 보면 생소하리라고 생각되지만 역시 표기법이기 때문에 암
기 하는 수 밖에 없습니다. 단순히 암기가 아니고 척 보면 알 정도로 "숙달"
되야 합니다.
<문> 다음의 문제를 풀면서 표현법을 눈에 익히세요
main()
{
char ch1 = 'O', ch2 = 'K';
char *pc1, *pc2, *temp;
pc1 = &ch1;
pc2 = &ch2;
temp = pc1;
pc1 = pc2;
pc2 = temp;
printf("%c%c", *pc1, *pc2);
}
<문> [180쪽] (예제 2)번 풀어보세요
<문> 다음을 실행해보고 크기가 같은 이유는 무었인가 생각해 보세요?
main()
{
char *p_ch;
int *p_int;
long *p_int;
printf("size = %d", sizeof(p_ch));
printf("size = %d", sizeof(p_int));
printf("size = %d", sizeof(p_long));
}
아래의 예를 통하여 포인터는 스트링을 어떻게 취급하는지 볼까요
main()
{
char ch;
char train[] = "Good";
char *ppp = "Good"; <-- 포인터의 초기화
printf("%s",train);
printf("%s", ppp);
}
위에 언급한 바와 같이 배열 train[] 에는 스트링의 글자들을 하나
씩 갖고 있습니다.그러나 포인터는 다릅니다. "morning" 이라는 데이타는 메
모리 어디에 있으나 우리는 단지 첫글자 'm' 이 있는곳의 주소만 알뿐입니
다. 그 주소가 ppp라는 포인터 변수에 들어가지요. 따라서 우리는 단지 시작
번지만 알 뿐입니다. 스트링의 길이가 얼마 인지 현재로는 모릅니다. 줄줄이
사탕처럼 하나씩 가다가 0x00을 만나면 끝인지 알 뿐입니다. 따라서 우리에
게 NULL 문자(0x00)은 얼마나 중요 한지 아시겠지요 ? 이걸 잃어버리면 그야
말로 난리가 나는겁니다.
배열과 포인터가 스트링을 갖고 있는 모습이 다르다는 걸 확실히 머리
에 그려야 합니다. 앞으로는 포인터가 강좌의 기초가 되야합니다.그러므로
여기서 확실히 알아야 합니다.
다음 프로그램을 보세요 머리속에 어떤 아파트의 모습이 그려집니까 ?
main()
{
char *p = "Good";
}
[183쪽]의 그림이 그려져야 합니다. 그림에서 보면 포인터 변수 p
의 주소는 500이라고 써있는데, 이런 주소 부분은 전부 "임의로(강사 맘대
로)" 적은것입니다. 따라서 "왜 500번지에요 ?" 이렇게 물어 보면 안됩니다.
나중에도 또 나오겠지만, 컴파일러가 실제로 컴파일 할 때, 이런 번지는 자
동적으로 결정이 됩니다.
포인터 변수집 p에는 현재 100 이라는 값이 들어가 있는데, 우리는
이런걸 보고 "p는 100호를 가리킨다" 라고 말 합니다. 정확한 말 이지요 ?
----------------------------------------------
<문> 다음을 실행해보세요
#include <stdio.h>
#define SIZE 80
main()
{
char word1[SIZE],word2[SIZE],word3[SIZE];
printf("Enter the Text : ");
scanf("%s %s %s", word1,word2,word3);
printf("word1 = %s\n word2 = %s\n word3 = %s\n", word1,
word2,word3);
}
<참고> - 여기서 %s 는 (String type)의 준말입니다.
- scanf() 에서 %s 를 3개 받으려면 space key, tab key, return
key중 하나를 사용하여 3 문장을 구별하라.
------------------------------------------
<문> 다음을 실행해 보세요
#include <stdio.h>
main()
{
static char word[] = "Happy Birth day";
static char *great = "hello";
int count = 0;
count = 0;
while(word[count] != NULL)
count++;
printf("Length = %d\n", count);
count = 0;
while(great[count] != NULL)
count++;
printf("Length = %d\n", count);
}
<참고> 포인터로 선언된 great가 배열로 사용된걸 눈여겨 보세요.
(나중 언급)
-------------------------------------------------
<문> 다음을 실행하라
#include <stdio.h>
main()
{
char letters[5];
int i;
for(i =0; i < 5; i++)
letters[i] = getchar();
for(i =4; i >= 0; i++)
putchar(letters[i]);
}
***************************< 끝 맺으며 >*******************************
오늘부터 포인터에 들어 갔는데 중요한 것입니다. 개념은 어려울 것이 없고
표기법 문제 이므로 부지런히 연습하시길....
***********************************************************************