[c언어] 기초프로그래밍 중간고사 준비 (1~5번)

서희찬·2022년 4월 16일
0
post-thumbnail

학교수업...c언어 기초 배우는 동국대학교 컴퓨터공학과 기초프로그래밍 수업 21년 기출문제 풀이 게시글이다.
제한시간은 2시간..!

1번


10진수를 2진수, 1의 보수, 2의 보수로 나타내는 방법이다.

교수님 코드

#include <stdio.h>

// 2진수 : 0,1로만 표현
// 1의 보수 : 각 자리가 모두 1인 수에서 주어진 2진수를 빼면 된다.
// 2의 보수 : 1의 보수에 1 더한다
#define INTSIZE 32


int main(void)
{
    
    unsigned int num,bp,ubit=0,msb;
    // ubit
    // msb
    // bp

    
    
    printf("10진수를 입력하시오 : ");
    scanf("%d",&num);
    
    bp = 0x80000000; // unsigend int 형식 0x80000000 는 2147483648 이다. 즉, 최댓값이다. => 10000000000000으로 초기화 한것이다.
    printf("%u\n",bp);
    for(int i=0;i<INTSIZE;i++){
        
        //num bp and연산 둘이 1로 겹칠때 1을 출력한다.
        if((num&bp)==bp){
            break;
        }
        ubit++; //비트 수 계산
//        printf("%d\n",ubit);
        bp >>= 1; // bp의 비트열을 1칸씩 오른쪽으로 이동시킨것을 넣는다.
        printf("ubit : %u, bp : %u\n",ubit,bp);
    }
//
    msb = bp;
//
//    //2진수 출력
    //유효한 비트만큼 반복
    for(int i=0;i<(INTSIZE-ubit);i++){
        printf("%d",(num&msb)==msb);
        msb>>=1; //msb가 작아지면서 num 2진수인것의 1위치를 출력한다
        //ex num이 12일때
        // msb 1000 -> 100 -> 10 -> 1
        // num 1100
        // & 연산
        // 2진수 1 -> 1 -> 0 -> 0 출력
        // 2진수 1100
        
    }
    printf("(2)\n");

    //1보수 출력
    // 1의 보수 : 뒤집으면 된다 1->0, 0->1
    //
    num = ~num; // num 비트 뒤집기
    msb = bp; // msb 다시 저장
    
    // msb는 각자리 출력을 위한 변수
    // bp는 num의 최댓자리수 위치 1 비트를 저장하고 있는 변수
    
    for(int i=0;i<(INTSIZE-ubit);i++){
        printf("%d",(num&msb)==msb);
        msb>>=1; //각 자리 출력
        
    }
    printf("(one's complement)\n");

    //2의 보수 출력
    //2의 보수 : 1의 보수 + 1
    
    // num은 뒤집어진 상태여서 -1의 값을 가지는데 1이 더작음
    // 그렇기에 1을 더해준다.
    // -13 -> -12의 비트를 출력한다.
    
    num += 1;
    msb = bp;
    // 각 비트 출력 알고리즘
    for(int i=0;i<(INTSIZE-ubit);i++){
        printf("%d",(num&msb)==msb);
        msb>>=1;
    }
    printf("(two's complement)\n");

    return 0;
}

진짜 1번부터 자비가 없네....미친..보통은 1번은 쉽게 내지않나...
1~5번 중 제일 어려운거같다...
비트연산 복습하고 다시보자 .. 흑 흑 ..


키야.... 코드 분석하니 예술이다.

  • bp 는 비트 최댓값을 저장하는 변수이다. 그렇기에 비트로는 10,000,000,000이 저장되어있다.
  • ubit는 num의 비트길이를 세어주기 위한 변수이다.
    그렇기에 num = 12면 1100인데 이는 길이가 4이므로 bp를 계속 오른쪽으로 옮기면 총 28번 옮긴다.
    그렇기에 intsize는 32이므로 32에 28을 빼면 4이므로 4개의 비트만 보면된다는것을 알 수 있다.
        if((num&bp)==bp){
            break;
        }

이 부분에서 bp가 1000이고 num이 1100이면 num&bp는 1000이므로 만족하고 탈출한다.

  • msb 는 num의 비트길이만큼 이동된 bp를 가진다. 이는 2진수로 출력하는데 활용된다.

그리고 제일 예술적인 부분이다.

    for(int i=0;i<(INTSIZE-ubit);i++){
        printf("%d",(num&msb)==msb);
        msb>>=1; //msb가 작아지면서 num 2진수인것의 1위치를 출력한다
        //ex num이 12일때
        // msb 1000 -> 100 -> 10 -> 1
        // num 1100
        // & 연산
        // 2진수 1 -> 1 -> 0 -> 0 출력
        // 2진수 1100
    }
    printf("(2)\n");

2진수 출력 알고리즘이다.
총 4번 반복하며, msb가 1000,100,10,1로 변하면서 &연산을 진행하며 자릿수에 1인값만 출력하게된다.

그리고 1의보수는 비트를 한번 뒤집어주면된다.

    num = ~num; // num 비트 뒤집기
    msb = bp; // msb 다시 저장
    
    // msb는 각자리 출력을 위한 변수
    // bp는 num의 최댓자리수 위치 1 비트를 저장하고 있는 변수
    
    for(int i=0;i<(INTSIZE-ubit);i++){
        printf("%d",(num&msb)==msb);
        msb>>=1; //각 자리 출력
        
    }
    printf("(one's complement)\n");

그러고 다시 출력한다.

그리고 2의 보수는 1의보수에 1을 더해주면된다.
근데 비트에 1을 더한다는것과 2의0승의 1을 더하는것 모두 1을 추가하는것이다.
그렇기에

   num += 1;
    msb = bp;
    // 각 비트 출력 알고리즘
    for(int i=0;i<(INTSIZE-ubit);i++){
        printf("%d",(num&msb)==msb);
        msb>>=1;
    }
    printf("(two's complement)\n");

이와같이 2의보수를 출력한다.


2번

시간 헤더파일을 가져와서 쓰고, 키를 입력받으면 end-start를 하면 될 것같다.. 근데 뭐지 이게

교수님 코드

#include <stdio.h>
#include <time.h> // 시간 헤더
#include <conio.h> // 콘솔 입출력 함수 제공 헤더

// iny kbhit()
// keyboard hit 약자, 버퍼에 값 있으면 1, 없으면 0 리턴

// time_t : 리턴 타입

int main(void)
{
    
    time_t start, end;
    
    printf("key를 입력하면 시간(초) 출력됩니다.");
    
    start = time(NULL); // 1970년 1월 1일 0시 0분 0초부터, 현재까지 몇 초가 지났는지를 리턴
    
    while(1){
        if(_khbit()){ //키보드 입력이 있을때
            end = time(NULL);
            break;
        }
    }
    printf("%d 초\n",(int)(end-start)); // 지난 시간 출력
    return 0;
}

아니 교수님...장난하는것도 아니고.. vsc에만 되는 conio헤더 파일을 사용하시면 리눅스나 맥사용자는 어떡하라고요....
돌리는거 확인을 못해서 교수님 정답 코드를 가져왔다.

우선,.. 코드 설명을 하자면 아래와같다.
time_t로 시간 start,end 변수를 만들어 준 후 start에는 100000초가 들어가고 5초뒤에 키를 입력했다면 end에는 100005초가 들어가서 5초가 출력된다.

하... conio...미치겠네~
이번에는 이렇게 안내시겠지..제발..

3번

음... 그냥 두 양수 unsigned int로 받고 double에 넣고
범위 넘으면 넘었다 말해주고 안넘으면 그냥 출력하면 되는 문제이다.

#include <stdio.h>

#define LIMIT 4294967295

int main(void)
{
    unsigned int num1,num2;
    double num3=0;
    printf("두 개의 양수를 입력하시오 : ");
    scanf("%u %u",&num1,&num2);
    
    num3 = (double)num1 + (double)num2; //double에 넣기 위해 형 변환 해주기
    
    // 범위 넘음
    if(num3>LIMIT){
        printf("unsigned int의 최대값 : 4294967295\n");
        printf("%.f 만큼 오버플로우가 발생했습니다.\n",num3-LIMIT ); // 소수점 날리기
        printf("더한 값 : %.1f\n",num3);
    }
    // 범위안
    else{
        printf("더한 값 : %.f\n",num3);
    }
    return 0;
}

주의 해야할 점

  • double에 넣을려면 double로 형변환 해줘야한다.
  • 소수점 출력 %.f하면 소수점 다 날린다.
  • unsigned int 최대값 : 4294967295

교수님 코드도 비슷하니 생략하겠다.

4번

교수님 코드

#include <stdio.h>

#define a 0.25
// E(0) = 1


int main(void)
{ 
    int cnt = 0;
    double X,E = 1;
    
    printf("문자열을 입력하시오. ");
    // 문자열을 반복해서 입력받는다.
    while(1){
        scanf("%lf",&X); //문자열 입력받는 테크닉
        
        // X가 -1일때
        if(X==-1)
            break;
        
        E = a*E + (1-a)*X; // E값을 매번 초기화
        printf("E(%d) = %f\n",++cnt,E);
    }
    

    return 0;
}

교수님의 압도적으로 깔끔한 코드이다..
문자열을 입력받아야해서 문자열을 배우지 않은 지금 어떻게 접근해야지 생각을 했는데 반복문으로 입력을 반복받는 방법이 있었다.
C언어에서는 입력을 하나 받고 돌리고 이런느낌이기에 저게 가능한것같다..

그렇기 때문에 매번 E값을 초기화 해주고, E(N)을 출력해주고 마지막인 -1이 왔을때 반복문을 끝내면 된다..

이 코드는 정말 멋지다..! 굿굿!

5번

소수판별 알고리즘을 사용하는 문제이다.

내가 짠 코드

#include<stdio.h>

int main(void)
{
    int cnt ,num;
    printf("n을 입력하세요 : ");
    scanf("%d", &num);
    
    for (int i = 2; i <= num; i++) // num이하
    {
        cnt = 0;
        for (int j = 2; j <= i; j++) // i이하
        {
            if (i % j == 0) // 나눠질때
                cnt++; //cnt 올린다
        }
        if (cnt == 1) // 나눠지는 수 1개만 있을때
            printf("%d ", i);
    }
}

이중 for문으로 구현 했으며 수가 나눠질때마다 cnt를 올려서 cnt가 1일때 소수임을 판단하고 출력하는 방식의 코드이다.

교수님 코드

#include<stdio.h>

int main(void)
{
    int flag=0 ,num;
    printf("n을 입력하세요 : ");
    scanf("%d", &num);
    
    for (int i = 2; i <= num; i++) // num이하
    {
        flag=0;
        for (int j = 2; j <= i/2; j++) // i이하
        {
            if (i % j == 0) // 나눠질때
            {
                flag = 1;
                break;
            }
        }
        if (flag == 0) // 나눠지는 수 1개만 있을때
            printf("%d ", i);
        
    }
}

시간적,메모리적으로 훨 효율적이다.
cnt대신 flag로 true/false구분한 점, flag=1이되면 반복문 탈출한 점, i/2로 절반만 탐색하게 작성한 점이 체크하고 넘어가야할 점이다.

profile
Carnegie Mellon University Robotics Institute | Research Associate | Developing For Our Lives, 세상에 기여하는 삶을 살고자 개발하고 있습니다

0개의 댓글

관련 채용 정보