4.6 break명령     [doc]     [smts]

 break 명령은 전 절에서 소개한 switch 명령과 반복문 안에서만 쓰이며 이 명령을 만나면 그것을 둘러싸고 있는 가장 안 쪽의 반복문 하나를 빠져 나온다.


다음의 간단한 예를 보자.


0406-01.c
for (int ia=0; ia<10; ia++) {
printf(“%d\n”,ia);
if (ia==3)
break;
}

이 프로그램의 결과는


0

1

2

3


이다. 왜냐면 ia가 3이라면 break 명령이 수행되어 for반복문 밖으로 빠져나오기 때문이다.


0406-02.c
int ia;
while(1) {
scanf(“%d”,&ia);
if (ia==0)
break
else
printf(“you typed %d.”,ia);
}

이 예는 사용자가 입력한 정수가 0 이 되면 break 명령을 만나서 무한 루프를 빠져나오는 것이다.


 또 다른 예로 사용자로부터 숫자(정수)를 입력받는데 정해진 입력이 아니면 다시 입력하도록 하는 것을 생각해 보자. 가상의 로봇에 대한 입력이 1번, 2번, 3번만 있는 경우 나머지 경우에 대해서는 다시 입력하도록 하려면 다음 예 break_ex01 과 같이 반복문과 break명령을 조합하여 사용하면 된다.


0406-03.c
#include <stdio.h>
int main(void)
{
  char cIn;
  printf("1. Turn left.\n");
  printf("2. Turn right.\n");
  printf("3. Stop.\n ");
  printf("Choose one : ");
  while(1) {
      scanf("%d", &cIn);
      if (cIn==1 || cIn==2 || cIn==3)
          break;
      printf("Wrong! Input again : ");
  }
}

이 예를 보면 while 반복문 안에서 scanf()함수에 의해서 하나의 정수를 입력받게 되어 있다. 입력받은 정수가 1, 2, 혹은 3이라면 break명령에 의해서 바로 반복문을 빠져 나가고 아니라면 scanf()함수가 반복되어 호출되도록 되어 있다. 이렇게 함으로서 올바른 숫자가 입력될 때까지 반복해서 입력을 받게끔 할 수 있다.


1. Turn left.
2. Turn right.
3. Stop.
Choose one : 5
Wrong! Input again : 1

또 다른 예를 들어보자. 소수(prime number)란 1과 그 자신의 수로만 나누어 떨어지는 수이다. 1000이하의 소수 중 가장 큰 것을 찾는 프로그램을 작성하고자 한다고 하자. 이 경우는 1000부터 하나씩 줄어가면서 소수인지 아닌지를 판별하는 것이 나을 것이다.


0406-04.c
#include <stdio.h>
int main() {
  for (int ia = 1000; ia>=2; ia--) {
      int ib = 2;
      while(ib < ia/2 ) {
          if (ia%ib == 0) break;
          ib++;
      }
      if (ib == ia/2 +1) {                  //❶
          printf("result: %d\n", ia);  //❷
          break;
      }
  }
}

이 예제에서 for문 안을 눈여겨보자. while 반복이 끝나고 ❶번줄로 넘어왔을 때 ib 변수값이 (ia/2+1)과 같다면 while반복문이 그 안의 break문을 만나지 않고 종료되었다는 의미이므로 (즉, 이것은 ia를 2 ~ (ia/2) 사이의 값으로 나눴을 때 한 번도 0이 되지 않았음을 의미한다) ia는 소수이다. 따라서 이 경우 바깥쪽 for반복문도 빠져나가게끔 되어 있다. 만약 while 반복이 끝나고 ❶번 줄로 넘어왔을 때 ib 변수값이 ia와 같지 않다면 이것은 2~(ia-1) 사이의 값으로 나눴을 때 어디선가 나머지가 0이라는 말이므로 소수가 아니라는 뜻이다. 따라서 다음 ia값을 다시 검사해야 된다. for문 바깥인 ❷로 빠져 나간 후 ia값을 printf()함수에 의해서 화면에 표시한다.


 이 예제를 이해했다면 for, while, break 에 대해서 어느 정도 이해를 했다고 볼 수 있다.


'프로그래밍언어.Lib > C,C++' 카테고리의 다른 글

C/C++의 goto 명령  (0) 2015.05.19
C/C++의 continue 명령  (0) 2015.05.19
C/C++ 의 do ~ while 반복문  (0) 2015.05.18
C/C++ 의 while 반복문  (0) 2015.05.18
C/C++의 for 반복문  (0) 2015.05.18
Posted by 살레시오
,

4.5 do~while 반복문     [doc]     [smts]

반복문에 사용되는 do~while 의 문법은 다음과 같다.


do {
  실행문;
  ...
} while(조건문);

while문과 차이점은 do{...} 안의 실행문이 처음에 한 번은 무조건 실행된다는 것이다. 그 이후 while 뒤의 조건문을 체크하여 참이면 do{...} 블럭을 다시 수행하고 거짓이면 그대로 반복을 종료한다.  초보자가 주의할 점은 while()문 뒤의 세미콜론을 빠뜨리기 쉽다는 것이다.


 다음이 do-while문의 예인데 1부터 100까지의 합을 구하는 것으로서 결과는 앞의 예제들과 같다.


0405-01.c
int ia=1, isum=0;
do {
  isum += ia;
} while(ia++ < 100);

while 뒤의 조건문을 잘 파악하면 ia가 1부터 정확히 100까지 do 블럭을 반복한다는 것을 알 수 있다.


다른 예를 들어보자.


0405-02.c
#include <stdio.h>
int main() {
  int ia;
  printf(“Input a positive integer : “);
  do {
      scanf(“%d”, &ia)
  } while(ia<=0);
}

이 예는 사용자가 양의 정수를 입력할 때 까지 do 블럭 안의 scanf()함수를 실행한다.  왜냐면 0이나 음수를 입력하면 while 문 뒤의 조건문이 참이 되어 do 블럭을 다시 수행하기 때문이다. 양수가 입력되면 반복문이 종료된다.



'프로그래밍언어.Lib > C,C++' 카테고리의 다른 글

C/C++의 continue 명령  (0) 2015.05.19
C/C++의 break 명령  (0) 2015.05.19
C/C++ 의 while 반복문  (0) 2015.05.18
C/C++의 for 반복문  (0) 2015.05.18
C/C++ 의 switch ~ case 제어문  (0) 2015.05.18
Posted by 살레시오
,

4.4 while 반복문     [doc]     [smts]

while 반복문은 for문에 비해서 구조가 간단하다.


while (조건문) {
  실행문1;
  …
  실행문n;
}

while 명령 바로 다음에 오는 조건문이 참이면 중괄호 안의 명령어들이 수행되고 거짓이라면 while 문을 빠져 나가게 된다. 만약 조건이 참이어서 실행문들이 다 수행되고 난 후에는 다시 조건문을 검사하여 참이면 다시 수행한다.


조건문이 참이면 소속된 실행문을 수행하므로 다음 예는 무한 루프에 빠지게 된다.


while (1) {
printf(“hi\n”);
}

반면에 다음과 같은 반복문은 절대로 수행되지 않는다. 조건이 항상 거짓(0)이기 때문이다.


while (0) {
printf(“bye.\n”);
}

화면에 문자열 “hi”가 딱 10 번만 출력 되게 하려면 다음과 같이 외부 변수를 이용해야 할 것이다.


0404-01.c
#include <stdio.h>
int main() {
   int icnt = 0;
   while (icnt < 10) {
       printf("hi ");
       icnt++;
   }
}
실행 결과
hi hi hi hi hi hi hi hi hi hi

위의 프로그램은 다음과 같이 조금 더 간략하게 작성할 수 있다. while 반목문에 속한 실행문이 하나일 경우 중괄호를 생략할 수 있다.


0404-01b.c
#include <stdio.h>
int main() {
   int icnt = 0;
   while (icnt++ < 10) {
       printf("hi ");
   }
}
실행 결과
hi hi hi hi hi hi hi hi hi hi

 다음 예제는 1부터 100까지의 합을 구하는 것을 while문으로 구현한 것이다.


0404-02
#include <stdio.h>
int main() {
   int ia = 1, isum = 0;
   while (ia <= 100) {
       isum += ia;
       ia++;
   }
   printf("isum = %d", isum);
}
실행 결과
isum = 5050

for문과 비교해 보면 초기실행문이 while문 바깥에 나와 있고 변환식은 while문 안으로 들어가 있다. 이 예제는 다음과 같이 조금 더 간결하게 만들 수 있다.


0404-02
#include <stdio.h>
int main() {
   int ia = 1, isum = 0;
   while (ia <= 100) {
       isum += ia++;
   }
   printf("isum = %d", isum);
}
실행 결과
isum = 5050

반복문이 하나의 명령이라면 중괄호를 생략할 수 있다. 단항연산자 ++가 ia뒤에 붙었으므로 먼저 isum변수에 ia값을 더한 후 1이 증가함에 유의하자. 만약


isum += ++ia;

이렇게 바뀌면 어떻게 동작을 할 지 생각해 보라. 단항연산자 ++, --의 동작에 대해서 한 번 더 이해가 갈 것이다.

 또 다른 예로 1부터 숫자를 더해나갈 때 어느 수까지 더하면 10000이 처음으로 넘는지를 알아내는 프로그램을 작성해 보자. 이 경우 while 반복문을 사용하면 다음과 같이 간단하게 작성할 수 있다.


0404-03.c
#include <stdio.h>
int main() {
  int ia=0, isum=0;
  while(isum < 10000) {
      isum += ++ia;
  }
  printf("Sum from 1 to %d is %d.\n", ia, isum);
}
실행 결과
Sum from 1 to 141 is 10011.

이 예제에서는 ia=0으로 초기화 시킨 다음에 isum += ++ia 와 같이 ++연산자를 ia앞에 붙였다. 이렇게 해야만 정확한 결과가 얻어진다는 것을 유의해야 한다. (왜인지 생각해 보자.)



'프로그래밍언어.Lib > C,C++' 카테고리의 다른 글

C/C++의 break 명령  (0) 2015.05.19
C/C++ 의 do ~ while 반복문  (0) 2015.05.18
C/C++의 for 반복문  (0) 2015.05.18
C/C++ 의 switch ~ case 제어문  (0) 2015.05.18
C/C++ 의 if ~ else 조건 제어문  (0) 2015.05.18
Posted by 살레시오
,

4.3 for 반복문    [doc]    [smts]

프로그램에서 같은 코드를 변수값만 바꿔가며 반복해서 해야 하는 경우는 빈번하게 발생한다. 이런 경우를 위해서 반복문이 사용된다. C 언어에서 사용하는 반복문은 for 와 while 그리고 do~while 세 가지가 있으며 가장 많이 쓰이는 것은 for 반복문이다.


for (초기실행문; 반복조건; 변환문) {
  명령문1;
  …
  명령문n;
}

for문 이후의 블럭이 정해진 수만큼 반복해서 수행이 된다. 초기실행문은 반복을 시작할 때의 초기값을 설정하는 부분이다. 만약 10번 반복해야 하고 초기값이 0이라면 이 부분에 0을 설정하는 실행문이 들어가야 한다. 만약 반복조건이 거짓이 되면 그 순간 반복문을 빠져 나가게 된다. 변환문은 매 반복이 끝나고(즉 명령문n이 끝난 다음) 반복조건이 참일 때 수행되는 명령문이다. 여기서 변수의 값을 증가 혹은 감소시킨다든가 하는 실행문이 위치하게 된다.


 다음 예제를 보자


0403-01.c
#include <stdio.h>
int main() {
   int ia;
  for (ia=0; ia<10; ia++) {
      printf("count : %d\n", ia);
  }
}
실행 결과
count : 0
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
count : 9

이 예제는 단순히 화면에 0부터 9까지 출력하는 프로그램이다. for구문이 수행되는 단계를 기술하면 다음과 같다.


      ① 반복문에 진입하기 전에 초기 실행문은 한 번 수행된다.

      ② 조건식을 검사한다.

      ③ 조건식이 참이라면 반복명령문(들)을 실행한다.

      ④ 변환문을 수행한 후 ②로 돌아간다.


위의 예제에서는 변환문은 ia++ 이다. ia는 0부터 시작해서 10보다 작을 경우 루프를 돌며 반복문을 수행한다. 즉 10번 반복문을 수행한다.


초기 실행문에 아예 변수의 선언을 해도 된다.


0403-02.c

#include <stdio.h>
int main() {
  for (int ia=9; ia>=0; ia--) {
      printf("count : %d\n", ia);
  }
}

실행 결과

count : 9
count : 8
count : 7
count : 6
count : 5
count : 4
count : 3
count : 2
count : 1
count : 0

이 예는 앞의 경우와 반대로 10부터 1까지 카운트다운을 하는 프로그램이다. 이 경우 변수 ia는 반복문이 시작될 때 생성되고 반복문이 종료되면 소멸된다. 즉, 반복문이 종료되면 변수 ia는 사용할 수 없다. 단, 이 기능은 C99 이후부터 지원하므로 gcc 를 실행할 때 ‘-std=c99’ 옵션을 반드시 추가해야 한다. 만약 C++컴파일러를 사용한다면 (g++) 별다른 옵션 조절없이 이 기능을 사용할 수 있다.


 이제 for 반복문을 사용하여 1부터 100까지의 총합을 구하는 프로그램을 작성해 보자.


0403-03.c
#include <stdio.h>
int main(void)
{
  int isum = 0;
  for (int ia=1; ia<=100; ia++) {
      isum += ia;    
  }
  printf(“result: %d.\n”,isum);
}

for 문 뒤에 실수로 세미콜론을 붙이지 않도록 주의한다. 즉


for ( ia=1; ia<=100; ia++);

  isum += ia;


이와 같이 되면 문법적으로는 오류가 없으나 의도하지 않게 반복문이 수행되지 않을 것이다. 또한 for문 뒤에 오는 명령어가 하나뿐이라면 중괄호{}를 생략할 수 있어 좀더 간결하게 프로그램을 작성할 수 있다.


for ( ia=1; ia<=100; ia++)

  isum += ia;


하지만 반복문에 속한 명령문이 하나 뿐일지라도 중괄호로 포함해 주면 가독성 측면에서 좀 더 낫다.


 다른 예로 구구단을 출력하는 프로그램을 for 반복문을 이용하여 작성해 보자.


0403-04.c
#include <stdio.h>
int main() {
   int ia = 3;
   for (int ib=2; ib<10; ib++) {
       printf("%d x %d = %d\n",ia, ib, ia*ib);
   }
}

이 예제에서 변수 ia는 단수를 지정하며 다음과 같이 3단을 출력한다.



3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27

for문을 중첩해서 사용할 수 도 있다. 다음 예제는 2단부터 9단가지 출력하는 프로그램이다.


0403-05.c
#include <stdio.h>
int main() {
   for (int ia=2; ia<10; ia++) {
       for (int ib=2; ib<10; ib++) {
           printf("%d x %d = %d\n",ia, ib, ia*ib);
       }
       printf("------------\n");
   }
}

초기 실행문은 콤마(,)로 연결하여 여러 변수를 동시에 초기화시킬 수도 있다.


for (int ia=1, isum=0; ia<=100; ia++) {
  isum += iA;
}

초기실행문에서 선언된 변수는 반복문이 종료된 이후에는 사용할 수 없다. 즉, 이 경우 변수 ia와 isum은 반복문이 종료된 후 소멸되므로 사용할 수 없다. 변환문도 콤마로 구분하여 여러 변수를 동시에 변화시켜줄 수 있다. 또한 조건은 ||연산자나 &&연산자를 이용하여 다중 조건을 체크할 수도 있다. 혹은 리턴값을 가진 함수를 이용하여 그 값을 비교할 수도 있다.


 만약 isum 변수를 반복문 종료 후에도 사용하고 싶다면 반드시 for문 밖에서 선언해야 한다. 다음 예는 1부터 100까지의 합을 구하는 예이다.


0403-06.c
#include <stdio.h>
int main() {
   int isum = 0;
   for (int ia=1; ia<=100; ia++) {
       isum += ia;
   }
   printf("isum = %d", isum); // isum변수를 사용할 수 있다.
}
실행 결과
isum = 5050

   for 반복문 바깥에서 선언된 변수는 반복문이 종료된 이후에도 사용할 수 있다.



'프로그래밍언어.Lib > C,C++' 카테고리의 다른 글

C/C++ 의 do ~ while 반복문  (0) 2015.05.18
C/C++ 의 while 반복문  (0) 2015.05.18
C/C++ 의 switch ~ case 제어문  (0) 2015.05.18
C/C++ 의 if ~ else 조건 제어문  (0) 2015.05.18
C/C++ 포인터 사용시 주의할 점  (0) 2015.05.18
Posted by 살레시오
,

4.2 다중조건 분기문     [doc]    [stms]

 만약 if 명령으로 여러 가지의 경우를 따져서 수행하려고 하면 if ~ else 문이 다중으로 중첩되어 프로그램의 가독성을 떨어뜨린다. 예를 들어서 어떤 정수형 변수의 값이 0일 때, 1일 때, 2일 때, 등등에 수십 가지에 대해서 동작이 다르게 수행되어야 하는 경우 if ~ else 명령보다는 여기에서 소개할 switch ~ case 명령을 사용하는 것이 가독성이나 수행 속도 면에서 훨씬 효율적이다.


 switch ~ case 명령의 기본적인 문법은 다음과 같다.


switch (정수형변수) {
  case 값1:
      명령문1;
      break;
  case 값2:
      명령문2;
      break;
  ...
  default:
      명령문n;
      break;
}

switch명령 바로 다음에 오는 변수가 case 다음의 값1이나 값2에 해당하는 값이 있는지 판별한 후에 해당하는 값이 있으면 거기에 속한 명령문을 수행한다. case뒤에 오는 것은 반드시 하나의 값이어야 하며 조건이나 여러 값은 올 수 없다. 해당하는 값이 없을 경우에는 default 로 설정된 ‘명령문n’을 수행하게 된다. 필요에 따라 default문은 생략할 수도 있다.


 이 명령을 쓸 때 주의할 점은 다음과 같다.


  1. switch문 뒤에 오는 변수는 반드시 정수형 (char, short, int, long과 각각의 unsigned형) 이어야 한다

  2. case 에 포함된 명령어들의 끝에는 반드시 break문을 써야 한다.


 다음 예제는 정수(명령)를 하나 입력받아서 1이면 “Robot turned left.”이라고 표시하고, 2라면 “Robot turned right.”라고 표시하고 3이면 “Robot stopped.”이라고 표시한다. 만약 1, 2, 3중 아무 것도 아니라면 “illegal command.”라고 표시하는 간단한 프로그램이다. 흔히 하기 쉬운 실수가 case문이 끝나는 곳에 break문을 빼먹는 것인데 초보자들은 유의해야 한다.


ex04-08.c
#include <stdio.h>
int main() {
  int iA;
  printf("1. Turn left.\n");
  printf("2. Turn right.\n");
  printf("3. Stop.\n ");
  printf("Choose one :");
  scanf("%d", &iA);
  
  switch(iA) {
      case 1:
          printf("Robot turned left.\n");
          break;
      case 2:
          printf("Robot turned right.\n");
          break;
      case 3:
          printf("Robot stopped.\n");
          break;
      default:
          printf("Illegal command.\n");
          break;
  }
}

1. Turn left.
2. Turn right.
3. Stop
Choose one : 2
Robot turned right.
Press any key to continue...

이 예제와 같이 세 가지 정도는 if ~ else 문으로 구현해도 상관 없으나 경우의 수가 많아 지는 곳에는 switch ~ case 문이 훨씬 더 효율적이다.



Posted by 살레시오
,

4.1 조건 분기문    [doc]    [smts]

프로그램에서 어떤 조건에 따라서 수행해야 하는 행동이 달라지는 경우는 매우 빈번하게 발생한다. 따라서 프로그램언어라면 보통 명령 수행의 흐름을 바꾸는 제어 명령어가 마련되어 있으며 C/C++언어도 이를 위해서 조건 검사 명령과 반복 명령어가 있다.


if 명령문은 조건을 제어하기 위해서 사용된다. 문법은 다음과 같다.


if (조건식) {
  실행문1;
  …
   실행문n;
}

보다시피 아주 간단한 문장으로 조건문이 참인지 거짓인지 판별하여 조건이 참이면 바로 뒤의 중괄호 {}로 묶인 실행문들을 수행하고, 참이 아니면 수행하지 않고 다음으로 넘어간다.


 만약 실행문이 하나라면 굳이 중괄호로 묶을 필요는 없으나 가독성을 높이기 위해서 중괄호를 항상 사용한다. 예를 들면 다음과 같다.


if (ca == cb)
  cx = 10;
if (cd > 10) {
  ce = 100;
}

 if 문을 사용할 때는 몇 가지 주의할 점이 있다. 먼저 조건은 반드시 괄호로 감싸야 한다는 점이고 괄호 안의 조건은 참과 거짓을 판별할 수 있어야 한다. C언어는 내부적으로 정수 0을 거짓으로 취급하고 그 이외의 수는(보통은 1값) 모두 참으로 취급한다는 점을 유의하자. 아래의 예에서 sa=10이라는 대입문은 무조건 수행되고 예2에서 sb=sc라는 대입문은 절대로 수행되지 않는다. (왜?)


if (1) {
  sa = 10; // sa=10과 동일
}

if (0) {
  sb = sc;
}

또한 조건문에서 가장 하기 쉬운 실수가 ‘==’를 ‘=’로 잘 못 사용하는 경우인데 이 경우 논리적인 버그가 발생하게 된다. 예를 들면


long la = 1, lb = 1, lc;
if (la = lb) {
  lc = 10;
}

위와 같은 경우에는 la=lb라는 표현식은 변수 la에 변수 lb값을 대입하고 그 자체로 변수 lb값인 1을 갖게 된다. 따라서 의도와 다르게 lc=10이라는 명령은 무조건 수행되게 된다. 만약 lb변수값이 0이라면 lc=10이라는 명령은 절대로 수행되지 않는다. 따라서 아래와 같이 프로그램을 수정해야 할 것이다.


long la=1, lb=1, lc;
if (la == lb) {
lc = 10;
}

또한 실수하기 쉬운 예가 다음과 같다.


if (la == 10);
  lb = lc;

이 예의 경우 if 조건 다음의 세미콜론 ‘;’에 의해 수행문이 종료되기 때문에 조건과 관계없이 lb=lc명령이 수행된다. 실제 프로그래밍을 하다보면 쉽게 하는 실수이니 눈여겨보기 바란다.


다음의 두 예는 서로 다른 프로그램이다. 첫 번째 예는 괄호가 없기 때문에 if 조건이 첫 번째 문장에만 적용되어서 ia의 값과는 상관없이 sc++이 수행되지만, 두 번째 예는 ia가 10값일 때에만 sc++이 수행된다.


if (ia == 10)
sb++;
sc++;
if (ia == 10) {
  sb++;
  sc++;
}

이번에는 if 문과 항상 같이 다니는 else문에 대해서 알아보자. 기본적인 문법은 아래와 같다.


if (조건문) {
  명령1;
  ...
} else {
  명령2;
  ...
}

else문에 포함된 명령어집합은 if 조건이 거짓일 경우 수행된다. 또한 if와 else를 조금 확장해 보면 if ~ else if 문이 된다.


if (조건문1) {
  명령문1;
  ...
} else if (조건문2) {
  명령문2;
  ...
} else {
  명령문3;
  ...
}

조건문1이 참이면 명령문1을 수행하고 조건문1이 거짓이고 조건문2가 참이면 명령문2가 수행되며, 두 조건 다 거짓일 경우 명령문 3이 수행된다.


 다음 예제는 하나의 정수를 입력받아서 3의 배수인지 아닌지를 판별하여 화면에 표시해주는 예제이다. 3의 배수라면 3으로 나눈 나머지가 0일 것이고 아니라면 3으로 나눈 나머지가 0이 아니라는 사실을 이용하면 쉽게 프로그램을 작성할 수 있다.


ex04-01.c
#include <stdio.h>
int main() {
  int ia;
  printf("Input an interger :");
  scanf("%d", &ia);
  if (ia%3 == 0)
      printf("%d is multiple of 3.\n", ia);
  else
      printf("%d is NOT multiple of 3.\n", ia);
}

Input an interger number :2
2 is NOT multiple of 3.

 사용자가 입력받은 수의 절대값을 출력하는 프로그램 예를 들면 다음과 같다. 입력된 수가 양수냐 아니냐에 따라서 수행되는 일이 달라진다.


ex04-02.c

#include<stdio.h>
int main() {
double da;
printf("input a number :");
scanf("%lf", &da);
printf("|%lf|=", da);
if (da>0) {
printf("%lf",da);
} else {
printf("%lf",-da);
}
}

실행 결과

input a number :-1.1
|-1.100000|=1.100000

이 프로그램에서 입력된 수가 양수이면 그대로 출력하고 음수라면 -1을 곱해서 출력하는 간단한 방법을 사용했다.


 다음 예는 입력된 정수가 음수인지, 0인지, 양수인지를 판별하는 예이다. if-else문이 중첩되어 사용되었음을 눈여겨보아야 한다.


ex04-03.c
#include <stdio.h>
int main() {
  int ia;
  printf("Input an interger number : ");
  scanf("%d",&ia);
  if (ia < 0)
      printf("%d is negative.\n", ia);
  else if (ia > 0)
      printf("%d is positive.\n", ia);
  else
      printf("%d is a zero.\n", ia);
}

Input an interger number : 0
2 is a zero.

다음은 사용자로부터 입력 받은 문자 하나가 알파벳 소문자라면 ‘lower case’ 라고 화면에 출력하는 예제이다.


ex04-04.c
#include <stdio.h>
int main() {
char ch;
scanf("%c", &ch);
if ('a'<=ch && ch<='z' ){
printf("lower case");
}
}

g
lower case

이 예제에서 비교문 (‘a’<=ch && ch<=’z’)는 (97<=ch && ch<=122) 와 동일하다. 문자는 내부적으로 아스키코드로 간주되기 때문이다.


 위 예제어서 대문자의 경우 “upper case’라고 출력하고 숫자의 경우 ‘digit’이라고 츌력하는  부분을 추가하면 다음과 같다.


ex04-05.c
#include <stdio.h>
int main() {
char ch;
scanf("%c", &ch);
if ('a'<=ch && ch<='z' ){
printf("lower case");
} else if ('A'<=ch && ch<='Z' ){
printf("upper case");
} else if (‘0’<=ch && ch<=’9’) {
printf("upper case");
} else {
printf("unknown");
}
}

이와 같이 if - else if 문은 얼마든지 중첩하여 사용할 수 있다.


Posted by 살레시오
,

6.6 포인터 사용시 유의점     [gdoc]     [smts]

 C 프로그래밍에서 포인터를 사용할 때 주의하지 않으면 치명적인 오류를 발생하게 된다. C프로그래밍이 어렵다는 인식이 있는 것은 바로 포인터를 적절하게 사용하기가 상당히 어렵다는 점에서 기인한다. 포인터는 곧 ‘주소’이므로 어느 주소값을 가르키고 있는가가 가장 중요하다. 먼저 확인할 사항은 포인터가 초기화가 되었는가이다.


 초기화되지 않은 포인터가 있을 경우 컴파일러에 따라 경고 메시지를 내기도 하고 경고 없이 실행하다가 실행 중 오류(runtime error)를 발생시켜서 프로그램이 다운될 수도 있다. 포인터를 사용할 때는 반드시 초기화를 시켜야 한다는 것을 알아두자.


다음 예를 보자


0604-01.c
#include <stdio.h>
int main()
{
double *dpa;
*dpa = 1.0;  //(1)
}

이 예는 언듯 문제가 없어보일 지도 모르지만 포인터 dpa가 초기화되지 않고 (1)에서 사용되었다. 이 프로그램은 컴파일러에 따라 컴파일시 오류를 발생하거나 실행이 되더라도 정상적인 동작을 하지 않고 프로그램이 죽어버릴 것이다. 그 이유는 포인터가 초기화되지 않은 상태이므로 정상적인 주소값을 가지고 있기 때문이다. 비정상적인 주소에 실수값 1.0을 대입하였으니 프로그램이 죽어버리는 것이다.


 포인터를 초기화시키려면 다음과 같이 기존 변수의 주소값을 사용하는 방법이 있다.


0604-02.c
#include <stdio.h>
int main()
{
  double da = 0.0;
  double *dpa = &da; // 변수 da의 주소로 포인터 dpa를 초기화
  *dpa = 1.0;
}

아니면 malloc()함수를 사용하여 정상적인 메모리 공간에  새로운 저장 공간(메모리)과 주소를 할당받을 수 있다.


#include <stdio.h>
int main()
{
  double *dpa = malloc(sizeof(double)); //새로운 저장공간과 주소값 할당
  *dpa = 10;
  …
  free(dpa); // 다 사용한 후 반드시 저장공간을 반환해야 한다.
}

malloc()함수와 free()함수는 stdio.h 헤더파일에 정의된 표준 함수이며 각각 메모리를 할당하고 반환하는 역할을 한다. sizeof()함수는 입력 인자의 바이트수를 반환하는데 sizeof(double) 은 double형의 바이트 수를 반환한다. (이 경우는 8) 따라서 8바이트 저장 공간을 확보한 후 그 주소를 반환한다. 그 주소는 포인터 dpa에 저장된다. 단, malloc()함수로 할당받은 저장 공간은 반드시 free()함수로 반환시켜야 한다.


다음 예는 소위 dangling 포인터의 예이다.


0604-04.c
#include <stdio.h>

int main()
{
int ia=10, *ipa = &ia;
printf("*ipa = %d\n", *ipa);
if (ia==10) {
int ib = 20;
ipa = &ib;
}
printf("*ipa = %d\n", *ipa);
}

if 블록 안에서 ipa가 &ib로 초기화가 되었지만 이 블록에서 벗어나는 순간 내부 변수 ib는 소멸되므로 ipa포인터도 그 소재가 불분명하게 된다. 이러한 경우를 dangling 포인터라고 하는데 프로그램이 길어질 경우 프로그래머가 의식하지 못하는 부분에서 이러한 실수가 일어날 수도 있게 된다. 당연히 이러한 경우도 방지해야 한다.


 다음 예를 보자. 다음 예는 ①에서 func(ipa)라고 호출을 하고 있다. 이 함수 내에서 포인터는 ②에서 내부 지역변수 ia의 주소값으로 초기화 된다. 그런데 func()함수 내부의 ipb포인터는 main()함수의 ipa와는 별개의 포인터이다. 따라서 main()함수 안의 ipa는 여전히 초기화가 되지 않은 포인터이다. 따라서 엉뚱한 값이 나오거나 프로그램이 실행 중지되기도 한다.


0604-03.c
#include <stdio.h>
void func(int*);

int main()
{
int *ipa;
func(ipa); //①
printf("*ipa = %d\n in main()", *ipa);
}

void func(int *ipb)
{
int ia = 20;
ipb = &ia; //②
printf("*ipb = %d in func().\n", *ipb);
}

 이와 같이 포인터를 사용할 경우에는 메모리의 할당과 해제에 각별한 주의를 기울여야 하는데 메모리 누수(leakage)와 같은 예기치 않은 동작을 발생시키기 쉽기 때문이다.



Posted by 살레시오
,

 C/C++에서 함수의 반환값이 포인터가 될 수 도 있다. 이 경우 함수의 선언은 다음과 같다.

반환자료형 *함수명(입력데이터형1, 입력데이터형2, …);


함수 내부에서 return 명령어에 의해 반환되는 변수도 당연히 반환자료형의 포인터가 되어야 한다. 이것은 문자열을 반환하거나 배열을 반환해야 하는 함수를 작성할 때 사용된다.


 예를 들어서 getMsg()라는 함수의 반환형이 문자열일 경우 다음과 같이 선언한다.

char *getMsg();


자료형 (char*)은 문자배열 즉 문자열을 표현하는 것이다. 이것을 이용하여 예제를 들어보면 다음과 같다.


#include <stdio.h>

char *getMsg(); // 함수 선언

int main()
{
printf("%s", getMsg());
}

char *getMsg() // 함수 정의
{
char *str = "getMsg() called.\n";
return str;
}


getMsg() called.


이 예제에서 getMsg() 함수는 내부에서 문자열 포인터 str을 생성한 후 그것을 반환한다. main()함수에서는 그것을 받아서 그대로 printf()함수의 입력 인자로 주는 간단한 예제이다.


C++ 강좌 전체 목록 >>>


c{c++},n{c0010}

Posted by 살레시오
,

 어떤 함수의 내부에서 호출하는 쪽의 변수를 직접 조작하려면 그 변수의 포인터를 넘겨받으면 된다. 이렇게 변수의 포인터를 넘겨 받아서 호출하는 함수의 변수를 직접 접근하는 방식을 참조에 의한 호출(call-by-reference) 라고 한다. 프로그래밍에서  참조(reference)라는 용어는 주소(address)와 거의 같은 의미로 사용된다.


 다음 예제를 살펴보자.


#include <stdio.h>
void addOne(float *); // 함수 선언

int main()
{
   float fa = 10.0f;
   addOne(&fa);
   printf("fa=%f\n",fa);
}

void addOne(float *fpa){
   *fpa += 1.0f;
}


 이 예제에서 addOne()함수는 float형 포인터를 받아서 fpa에 저장한다. addOne()함수에 &fa 를 넘긴 것을 눈여겨 보아야 한다. 그리고 내부에서 *fpa 값을 1,0만큼 증가시킨다. 하지만 addOne() 함수의 *fpa 는 main()함수의 fa 변수와 같다. 따라서 fa변수를 직접 조작하는 효과가 나는 것이다. 실행 결과를 보면 다음과 같다.


fa=11.000000


함수를 선언할 경우에는 굳이 인자의 이름을 써 줄 필요가 없고 인자의 자료형만 밝혀주면 된다. 위의 예제에서


void addOne(float *fpa);
void addOne(float *);//이렇게 인자의 이름 fpa를 생략해도 됨


라고 addOne()함수를 선언했는데 이 함수의 첫 번째 인자가 float형 포인터(float *)라고 명시한 것이다.


 다른 예로 두 변수의 값을 바꾸는 swap()함수를 작성해 보자.


#include <stdio.h>
void swap(int*, int*); // 함수 선언

int main()
{
   int ia = 11, ib = 22;
   swap(&ia, &ib);
   printf("ia=%d, ib=%d\n", ia, ib);
}

void swap(int *ipa, int *ipb){
   int itmp = *ipa;
   *ipa = *ipb;
   *ipb = itmp;
}


ia = 22, ib = 11


이 예에서 swap()함수는 두 개의 int형 포인터를 받는다. 그리고 그 내부에서 *ipa와 *ipb 값을 교환했는데 이는 main()함수에서 ia, ib를 바꾼 것과 같은 효과를 가진다.


C++ 강좌 전체 목록 >>>


c{c++},n{c0007}

Posted by 살레시오
,

6.3 포인터 연산     [doc]     [smts]

 포인터 변수에 대해서 더하기와 빼기 연산이 가능하다. 먼저 다음 예제를 살펴보자.


0602-01.c
#include <stdio.h>
int main()
{
  short sa=10, sb=11, *spa=&sa, *spb=&sb;
  long la=20, lb=21, *lpa=&la, *lpb=&lb;
  printf("%p, %p\n", spa, spb);
  printf("%p, %p\n", lpa, lpb);
}

printf()함수에서 %p 형식지정자는 포인터를 출력할 때 사용되며 주소를 16진수로 표시해준다. 실행 결과는 다음과 같다. (주소는 PC마다 다를 수 있다.)


ffffff12, ffffff10
0028ff0c, 0028ff08

변수 sa와 sb는 인접한 메모리에 저장되는데 주소값의 차이가 2가 난다. short형이 2바이트 자료형이기 때문이다. 마찬가지로 long형은 4바이트 자료형이므로 인접한  la와 lb는 주소가 4가 차이가 난다.


 이와 같이 포인터에 정수를 더하거나 빼기도 하고 포인터끼리 뺄셈을 하는 등 연산 기능을 제공한다. 이러한 연산을 통해 포인터가 가리키는 주소를 변화시키거나 포인터들이 가리키는 주소 간 거리를 계산할 수 있다. 이러한 기능은 특히 배열을 다룰 때 유용하게 사용된다.


포인터에 정수를 더하거나 뺄 수 있는데 이 경우 (주소의) 변량은  다음과 같다.


  • 더하거나 빼는 정수×자료형의 크기


다음 예를 보자.


0602-02.c
#include <stdio.h>
int main()
{
  short sa = 10;
  short *spa = &sa;
  printf("%p\n", spa++);
  printf("%p\n", spa);
  printf("%p\n", spa+2);
}

실행결과는 다음과 같다.(주소값은 PC마다 다를 수 있다.)


0028ff1a
0028ff1c
0028ff20

포인터 spa를 1 증가시켰는데 주소값은 2가 증가되었다. 이는 spa가 short형 포인터이고 short는 2바이트를 차지하는 자료형이기 때문이다. 그리고 spa+2는 주소값이 4가 증가되었는데 (정수)*(바이트수) 만큼 증가되기 때문이다.


증감연산자와 포인터 연산자를 조합한 몇 가지 혼동할 여지가 있는 예를 들어보자.


*(++ipA)  // 포인터값을 먼저 증가시킨 해당 변수의 값을 참조
*(ipA++)  // 해당 변수값을 참조한 다음 포인터값을 증가
++(*ipA)  // *ipA 변수값 1 증가후 그 값 참조
(*ipA)++  // *ipA 값 참조 후 변수값 1 증가

이 예제들의 경우 괄호를 생략하여 가독성을 떨어뜨리는 것은 바람직하지 않다.


Posted by 살레시오
,