반복문 for 의 함정

2013. 10. 23. 02:37 from Language/C언어

for 와 while 은 반복문으로써 자주 사용된다. while 문을 그대로 for 로 대체할 수도 있지만 상황에 따라서 while 도 쓰고 for 도 쓰인다. for 에 대한 설명은 인터넷에 찾아보면 자주 나오므로 생략. 



반복문의 함정을 이야기 하기 전에 변수의 범위에 대하 잠깐 이야기 해보자. 변수의 범위(scope)는 크게 두가지로 나뉜다. 첫째로 변수에 접근할 수 있는 영역. 둘째로 메모리상에 존재하는 기간. 변수에 접근할 수 있는 영역은 지역변수 전역변수에 관한 내용으로 쉽게 이해할 수 있다. 그리고 많이들 알고 있으므로 생략.


변수가 메모리상에 존재하는 기간은 조금 낯설수도 있다. 쉽게말해서 변수가 메모리에 저장 되었다가 메모리에서 삭제되는 기간을 이야기 하는것이다. 지역변수가 메모리에 저장되는 타이밍은 변수 선언을 할때이다. 어떤 함수내에서 변수를 선언하면 동시에 메모리에 저장되는 것이다. 그리고 메모리에서 삭제되는 타이밍은 그 함수를 종료할 때이다.

- 지역 변수는 함수가 호출될 때 메모리상에 올라갔다가, 함수가 종료되면 메모리상에서 사라진다.


이제 반복문 for 의 함정을 이야기 할수 있을 것 같다. 반복문은 시작과 종료를 중괄호로 되어있다. 즉, 함수이므로 반복문 안에서 지역변수 선언이 가능하다(함수라고 말해도 되는지는 정확히 모르겠지만 지역변수 선언 가능). 따라서 지역변수가 선언 되었을 때 메모리로 저장되고 반복문을 종료할 때 똑같이 메모리상에서 삭제 된다. 그런데 for 문은 종료할 때가 언제일까? 

  1. for( i = 0 ; i< 3 ; i++ )
  2. {
  3. int a = 0;
  4. a++;
  5. printf("%d \n",a);
  6. }

이런 문장을 실행했을 때 오류가 떠야 정상일 것이라 생각할 수도 있다. 왜냐하면 int a 가 선언 되었는데 계속해서 선언을 하게 되므로 오류가 발생할 것이다. 그러나 실제로 컴파일 하보면 오류가 발생하지 않는다. 그 이유는 for 문은 두 번째 줄 부터 여섯 번째 줄 까지 전부 실행하고 괄호를 탈출한 뒤 다시 조건문부터 실행하기 때문이다. 괄호를 탈출 한다는 것은 함수가 끝는 다는 것과 같고 그러므로 메모리에 저장되 있던 지역변수가 메모리상에서 사라지게 된다. 메모리상에서 사라지게 되므로 i 가 0 일때 생성 되었던 int a 는 소멸하고 다시 i 가 1 일때 새로운 int a 가 메모리상에 저장 되는 것이다.
참고로 위 예제를 실행하면 아래와 같이 된다.
1
1
1

- for 문의 종료는 for 문 내용을 전부 실행한 후 for 문을 완전히 탈출한 다음 다시 조건부터 시작한다.


'Language > C언어' 카테고리의 다른 글

선언(declaration)과 정의(definition)의 차이  (0) 2013.11.08
C언어 따옴표의 의미  (0) 2013.11.06
강제 형 변환  (0) 2013.10.23
컴파일과 링크의 차이  (0) 2013.10.23
라이브러리와 헤더파일의 차이  (0) 2013.10.23
Posted by 나무길 :

강제 형 변환

2013. 10. 23. 02:36 from Language/C언어

강제 형 변환이란 자료형을 강제로 변환 시키는 것이다. 대충 이름만 봐도 감이 올 것이다.

강제 형 변환이 어떤 경우에 유용한지 살펴보자.

#include <stdio.h>

int main()
{
int a = 1;
int b = 2;

float f =  a / b;
printf("나눗셈 결과 : %f \n", f);

return 0;
}

위 결과를 예상해 보면 정수형 데이터끼리 연산했을 지라도 실수형 변수 f 로 연산 결과를 대입했으므로 0.5000 가 제대로 대입 됐을 것이라 생각할 수 있다. 하지만 실제로 연산 결과를 보면 0.0000 으로 출력 된다. 왜 이런 현상이 발생했을까?

C언어는 문법적으로 산술 연산결과의 자료형은 피 연산자의 자료형과 일치하기 때문이다. 무슨 말인고 하니 정수형 데이터끼리 연산을 하면 정수형 데이터가 생성되고, 실수형끼리 연산을 하게 되면 실수형 데이터가 생성된다는 뜻이다. 위 예제를 풀어서 보면 1/2 연산 결과는 0.5 이지만 정수형 데이터끼리 연산했으므로 결과물도 정수형이여 한다. 따라서 0.5 에서 소수 부분은 손실되고 0 이라는 결과를 얻게 된다. 그 다음 0 을 실수형 데이터 f 에 대입했으므로 0.0 이라는 값을 출력하는 것이다.


이럴때 원하는 결과물을 얻기 위해서 필요한 것이 강제 형 변환이다. 'float f =  a / b ;'  ----> 'float f =  (float) a / b ;' 이렇게 수정한다면 int 형 변수 a 를 float 형으로 강제 변환 하게 된다. 따라서 1.0 을 2 (int 형 변수 b) 로 나누는 꼴이 된다. 이때 자동 형 변환이 발생하게 되는데 (피연산자들 간의 자료형 통일을 위함. 데이터 손실이 적은 쪽으로 변환된다.) int 형 변수 b 도 float 형 변수 b 로 바뀌게 되는 것이다. 
결국 1.0 / 2.0 = 0.5 값을 얻게 되어 변수 f 에 대입하여 원하는 값을 출력할 수 있게 된다.


강제 형 변환은 위와 같은 산술 연산뿐만 아니라 비교연산에서 발생한다. 예전에 스모로봇 소스를 만들 때 그 당시에는 몰랐는데 나중에 그 소스를 다시 보면서 이상한점을 발견한 적이 있었다. 지금 그 소스가 어디있는 지 모르므로 비슷한 예제를 사용해보겠다.

#include <stdio.h>


int main(int argc, char **argv)
{
unsigned int i = 100;
if(i < -10)
printf("Large \n");
return 0;
}


위 소스를 실행하면 "Large"가 출력되지 않아야 정상일 것이다. 100은 당연히 -10보다 크기 때문에 if 조건문이 거짓이 되기 때문에.. 하지만 실제로는 "Large"가 잘 출력된다. 왜그럴까? 이것 또한 형 변환 때문이다. '-10' 입장에서는 'unsigned i' 를 보고 형을 일치 시켜야 하기 때문에 강제로 '-10'이 unsigned 형으로 변환 된다. 그 결과 '-10'은 2의 보수를 취해서 '4,294,967,285' 으로 된다. 이는 당연히 100 보다 크므로 "Large"가 출력 하게 되는 것이다. 실수하기 쉬운 것으로 잘 기억해 놔야겠다.


'Language > C언어' 카테고리의 다른 글

C언어 따옴표의 의미  (0) 2013.11.06
반복문 for 의 함정  (1) 2013.10.23
컴파일과 링크의 차이  (0) 2013.10.23
라이브러리와 헤더파일의 차이  (0) 2013.10.23
잘못된 포인터의 사용 1  (0) 2013.10.23
Posted by 나무길 :

Microsoft Visual Studio 를 하다보면 소스 코드를 작성해 놓고 아무것도 모르고 F7, Ctrl + F7, Ctrl + F5 를 누루는 경우가 있다.

위 작업들은 '빌드, 컴파일, 디버깅하지 않고 실행'에 해당한다. 이러한 것들을 좀 명확히 알고 사용할 수 있도록 하자.


컴파일이란 소스 코드로 작성해 놓은 것을 컴퓨터가 알아들을 수 있는 언어로 바꾸어 주는 과정을 의미한다. 컴퓨터가 알아들을 수 있는 언어란 기계어로 '바이너리' 라고 한다. 단순히 해당 소스 코드를 해당프로그래밍 언어의 문법에 맞는 검사하여 오류가 없다면 기계어로 번역해준다. 
컴파일된 소스파일은 .c 에서  오브젝트 파일로 변환된다. 변환된 오브젝트 파일은 윈도우에서는 확장자를 .obj 로 갖고 리눅스 또는 유닉스에서는 .o 로 갖는다. 그러나 오브젝트 파일은 실행 파일이 아니다. 따라서 확장자 .exe 로 생성 되지 않는다.

- 현재 활성화 중인 창에 열려 있는 CPP 하나만 문법 검사 및 기계어로 변환 시킨다. 컴파일 단축키 : Ctrl + F7



실행파일을 생성 하는 작업을 링크 라고 한다. 링크는 컴파일로 이미 만들어진 기계어코드를 라이브러리와 연결시켜서 실행가능한 파일로 만들어내는 역할을 한다. 이때 참고로 빌드라는 것이 있는데 빌드는 컴파일과 링크를 합친 과정이라고 생각하면 쉽다. 소스코드를 작성한 후에 컴파일 과정을 거치지 않고 빌드를 하게 되면 컴파일과 링크를 모두 실행하게 되며 컴파일 과정을 거친 후에 빌드를 하게 되면 컴파일 과정을 생략하고 생성되어 있는 오브젝트 파일에 링크 작업을 수행하여 실행파일을 만든다.

- .c 파일을 컴파일한 후에 생성되는 .obj 파일들을 이용하여 링크 작업을 해야 .exe 파일이 만들어진다. 빌드 단축키 : F7


'Language > C언어' 카테고리의 다른 글

반복문 for 의 함정  (1) 2013.10.23
강제 형 변환  (0) 2013.10.23
라이브러리와 헤더파일의 차이  (0) 2013.10.23
잘못된 포인터의 사용 1  (0) 2013.10.23
포인터, 배열, 포인터 배열 비교  (0) 2013.10.23
Posted by 나무길 :