본문으로 바로가기

파일의 IT 블로그

  1. Home
  2. 프로그래밍/C++
  3. [C/C++] Tricky C Quizzes (Never a good code)

[C/C++] Tricky C Quizzes (Never a good code)

· 댓글개 · KRFile

C++ 강의를 듣고 있는데 교안 마지막 부분에 한번 생각해볼만한 거리로 나름 재미있는 코드들을 (사실은 끔직한) 제공해주셨길레 한번 재미삼아 하나씩 알아가보며 정리해봤습니다.

 

#1

How many times main() will get called?

- main() 함수는 몇번이나 호출되는가?

#include <stdio.h>
int main()
{
	printf("main() called \n" );
	main();
	return 0;
}

보시면 printf로 main() called 를 출력하고 다시 main() 함수를 재귀적으로 호출하고 있습니다.

일반적으로 C/C++ 에서는 main 함수가 프로그램의 진입점(시작점)이 되는데 이렇게 main 함수를 재귀적으로 호출하면 어떻게 될까요?

 

우선 탈출점이 없으므로 main() 함수가 무한히 호출될 것입니다.

보통 파이썬에서는 저렇게 재귀에 끝없이 빠지는걸 방지하기 위해서 재귀 호출에 제한이 걸려있는데

 

sys.setrecursionlimit(n)

다음과 같은 코드를 이용해서 재귀 호출 제한을 바꿀 수 있죠.

보통 10 ** 8 ($10^8$) 같이 큰수를 넣어서 DFS같은걸 돌릴때 반복횟수 때문에 문제가 없도록 합니다.

 

https://stackoverflow.com/questions/10242839/is-there-any-hard-wired-limit-on-recursion-depth-in-c

 

Is there any hard-wired limit on recursion depth in C

The program under discussion attempts to compute sum-of-first-n-natural-numbers using recursion. I know this can be done using a simple formula n*(n+1)/2 but the idea here is to use recursion. The

stackoverflow.com

대강 확인해본결과 C에서는 재귀 깊이에 대한 한계가 없어보입니다.

물론 스택 메모리가 꽉차면 Stack OverFlow가 터지면서 프로그램이 종료되겠지만 위의 main() 함수 호출의 경우엔 어떤 매커니즘으로 돌아가는지 잘 모르겠네요.

 

어쨌든 저런 코드는 절대 작성할 일이 없으니..  스택 메모리가 가득찰때까지 호출된다라고 봐야겠네요.

main() 재귀 호출에 대한 내용이 아래에 있습니다.

 

https://stackoverflow.com/questions/4238179/calling-main-in-main-in-c

 

calling main() in main() in c

Is it possible to call main() within the main() function in c?

stackoverflow.com

 

*2022-04-12 추가

main() 함수의 규모가 조금 큰 프로그램에 재귀 호출을 걸어보니 몇초 돌아가다가 얄짤 없이 스택 오버플로우가 뜨는걸 확인했습니다. 특히 메뉴를 구현할때 재귀 함수를 사용하는 경우가 있는데 조금 코드가 지저분하더라도 do~while 을 쓰는게 안전해 보입니다.

 

#2

What is the output of the following program?

- 프로그램의 출력결과는 무엇인가?

 

#include <stdio.h>

int main(){
    float a = 6.7;
    if(a == 6.7)
        printf("A");
    else
        printf("B");
    return 0;
}

 

C언어를 얼마 안한 초심자들이 자주 하는 실수가 나왔습니다.

방대한 소수를 표현하기 위해 컴퓨터에선 표현할때 고정 소수점 / 부동 소수점이 있는데

고정 소수점은 정확도가 높은대신 메모리를 많이 차지해서 현대 컴퓨터는 IEEE의 부동 소수점 방식을 이용합니다.

 

부는 아닐 부자가 아닌 뜰 부자인데 한자는 부동(浮動) /  뜰 부자와 움직일 동자로 소수점이 이리저리 떠다니면서 표현을 하는 방식입니다.

 

어쨌든 저 6.7이란것도 소수점 길게 찍어보면 정확히 6.7로떨어지는게 아니라 오차때문에 6.7000001 같은 형태로 떨어집니다. 그래서 실수들끼리 같은걸 비교할땐 뺀다음에 오차 범위 (입실론) 내로 들어오는걸 체크하면 되는데 그정도까진 이 포스팅에서 다루지 않겠습니다.

 

어쨌든 위 코드를 실행하면 a는 6.7과 완전히 동일하지 않아서 A가 아닌 B가 출력됩니다.

 

#3

What is the output of the following program?

- 프로그램의 출력결과는 무엇인가?

 

#include <stdio.h>

int main(){
    int n = 12/5;
    float f = 12/5;
    
    printf("%d %f", n, f);
    return 0;
}

 

12/5를 산술연산하고 각각 int와 float에 저장하는데,

기본적으로 숫자를 계산할땐 컴퓨터에 가장 최적화된 int로 계산하므로

int / int 로 소수점이 날라갈것이고 어떻게 하던 2가 나오겠네요.

 

그걸 int n 에 저장하면 2가 저장될 것이고.. float에 저장하면 2.000~ 이 저장되겠네요.

 

#4

What is the output of the following program?

- 프로그램의 출력결과는 무엇인가?

 

#include <stdio.h>
int main()
{
	int a = 100 > 90 > 80;
	printf("%d", a);
	return 0;
}

이것도 꽤 유명하죠~ 분명 수학에선 부등호를 3개씩 적는게 됩니다만 프로그래밍에서 할땐 부등호 2개씩 비교하고 저렇게 3개씩 비교하고 싶을땐 2개씩 비교한걸 각각 and로 비교해야 합니다.

 

이유는 우선 대입연산자는 오른쪽에서 계산해서 왼쪽에 대입하는데 오른쪽걸 먼저 계산해야겠죠.

 

100 > 90 > 80을 계산할때 100 > 90 은 우선 참이므로 1이 되고 그럼 1 > 80 을 비교하게 됩니다.

1 > 80 은 거짓이므로 0이 나오겠네요.

 

그래서 출력결과는 0입니다.

 

 

#5

What is the output of the following program?

- 프로그램의 출력결과는 무엇인가?

#include <stdio.h>
int main()
{
	int a = 2;
	switch(a) {
	case 1:
		printf("A");
	case 2:
		printf("B");
	case 3:
		printf("C");
	break;
	case 4:
		printf("D");
	default:
		printf("E");
	}
	return 0;
}

이건 제가 강의했을때 적었던것인데 case문 끝에 break를 안걸어주면 어떻게 되냐였습니다.

일반적으로 case문은 break를 안걸어주면 그 위치에서 시작해서 break를 만날때까지 코드가 쭉 실행됩니다.

 

예를 들어서 위 코드는 a = 2 이므로 case 2에 걸려서 우선 B가 출력되고 아래 break 를 만날대까지 출력하므로

C에서 출력하고 break 가 걸려서 출력이 멈추겠죠.

 

그래서 결론적으로 BC가 출력됩니다.

 

#6

What is the output of the following program?

- 프로그램의 출력결과는 무엇인가?

#include <stdio.h>
int main()
{
	int a = 1;
	while(a-- >= 1)
	while(a-- >= 0);
	printf("%d", a);
	return 0;
}

음.. 지금까지 본것중에 가장 끔찍해보이는 코드가 나왔습니다.

제일 햇갈리고 어려운 증감 연산자 입니다.

파이썬에선 이게 햇갈린다고 해서 아예 증감연산자를 언어상에서 없애버렸죠.

 

while문 첫번째에는 세미콜론이 안들어가있고 두번째 while엔 들어가있네요..?

아마 첫번째 while로 두번째 while을 중괄호로 감싼건데 한줄이라 생략을 한걸로 추정 됩니다.

 

* 중괄호를 치나 안치나 출력결과가 동일한걸로 봐선 같은 코드라고 생각하는데 혹시 아니라면 정정 부탁드립니다!

 

#include <stdio.h>
int main()
{
	int a = 1;
	while(a-- >= 1)
    {
    	while(a-- >= 0);
    }
	printf("%d", a);
	return 0;
}

그래서 다음 코드라고 생각을 하고.. 진행을 하면 되겠네요

 

(1) 외부 while(a-- >= 1) 조건에 의해 a-- >= 1인지 비교하는데 후위 증감 연산자이므로 우선 a >= 1 인지 비교하고 비교가 끝나면 a가 1감소하게 됩니다.

현재 a의 값은 1이므로 1>=1 : 참 이므로 a를 1감소 시킨다음에 a는 0이 되고 while문 조건이 참이므로  내부 while 문이 실행됩니다.

 

(2) while(a-- >= 0); 인지 비교하는데 현재 a는 0이므로 참이고, 나중에 a가 감소하니 -1이 됩니다.

그리고 while(a-- >= 0); <-- 이 문장 끝에 세미콜론이 찍혀있는데 이렇게 쓰면 while 문 내부적으로 실행할 코드는 하나도 없다는 겁니다. 그러므로 다시 while(a-- >= 0); 여기로 돌아와서 조건문을 다시 한번 확인하는데

 

현재 a는 -1이므로 -1 >= 0 은 거짓이 됩니다. 다만 조건에 관계없이 후위 연산자에 의해 a는 1감소합니다. 그래서 a = -2가 되겠군요

 

(3) 내부 while문의 처리는 종료되었고, 외부 while에서 조건을 다시 한번 체크합니다.

-2 >= 1 역시 거짓이라 외부 while까지 실행이 끝나서 while문은 탈출했습니다. 역시 거짓 참과 관계 없이 a는 1감소, 결론적으로 a = -3이 되었습니다.

 

그래서 a는 -3이 출력되겠네요.

사실 증감 연산자를 덕지덕지 떡칠하는것도 좋은 코드는 아닌데

이런 코드는 작성하지 않는게 좋습니다. (물론 이렇게 작성할 사람도 없겠지만은..)

 

그냥 Quiz용으로 꼬여진 코드라고 보시면 되겠네요.

 

 

 

#7

What is the output of the following program?

- 프로그램의 출력결과는 무엇인가?

 

#include <stdio.h>

void fun(int *i)
{
	*i = *i + 1;
}
int main()
{
	int arr[] = {10, 20, 30, 40, 50};
	int i, *ptr = arr;
	
	for(i = 0; i < 4; i++){
		fun(ptr++);
		printf("%d\n", *ptr);
	}
	
	return 0;
}

마지막으로 포인터를 사용해서 배열을 탐색하는 예제네요.

fun 이라는 함수는 포인터로 입력받아서 그 주소의 값에 1을 더하는 역할을 하고 있습니다.

 

그리고 i는 그냥 for문의 index용 변수, ptr 포인터는 arr의 시작주소를 가리켰으니 arr과 동일한 용법으로 접근할 수 있겠네요.

 

fun(ptr++); 우선 이 코드가 실행되면 후위 증감연산자 이므로 ptr에 1을 더한 주소값이 아닌 그냥 ptr의 주소에 대한 값에 1이 더해질 것이고 그러면

ptr이 arr의 시작주소 (첫번째 요소 주소) 를 가리키고 있으므로 10에 1이 더해진것이 저장될것이고,

arr[0] = 11이 됩니다.

 

후위 증감연산자에 의해 ptr이 1 더해짐, 포인터 연산에 의해 ptr은 다음 요소를 가리키게 되고 arr[1]에 해당하는 20이 출력됩니다. 그리고 다시 21이 되고 30을 출력하고..

그러다가 보면 20 30 40 50이 출력되고 끝나겠죠.

 

출력 결과는 20 30 40 50 이네요.

 

다음걸 가리켜서 출력하고 이전것에 1을 더해서 저장하는 형태이기 때문에

저 과정이 끝난후에 arr을 찍어보면 아마 11 21 31 41 50 이 되었을겁니다.

 

for(i = 0; i < 5; i++){
    printf("%d\n", arr[i]);
}

11
21
31
41
50

예측한대로 결과가 잘 나왔습니다!

SNS 공유하기
💬 댓글 개
이모티콘창 닫기
울음
안녕
감사해요
당황
피폐

이모티콘을 클릭하면 댓글창에 입력됩니다.